通过入侵JVM打印阵列
總覽
Java中最常見的陷阱之一就是知道如何打印數組。 如果有關如何打印陣列的答案獲得了超過1000票贊成票,那么您必須懷疑是否有更簡單的方法。 幾乎所有其他流行語言都具有這種更簡單的方法,因此我不清楚Java為什么仍會這樣做。
與其他JDK類不同,數組沒有特別健全的toString(),因為它是從Object繼承的。
它打印類型和地址嗎?
實際上,它不打印地址,只是看起來像一個地址一樣。 它打印類型的內部表示以及對象的hashCode() 。 由于所有數組都是對象,因此它們具有hashCode()和類型以及同步鎖,而對象具有的其他所有內容,但是沒有特定于數組的方法。 這就是為什么toString()對數組沒有用的原因。
看起來沒有什么變化?
如果我運行以下程序。
public class ObjectTest {boolean[] booleans = {true, false};byte[] bytes = {1, 2, 3};char[] chars = "Hello World".toCharArray();short[] shorts = {111, 222, 333};float[] floats = {1.0f, 2.2f, 3.33f, 44.44f, 55.555f, 666.666f};int[] ints = {1, 22, 333, 4_444, 55_555, 666_666};double[] doubles = {Math.PI, Math.E};long[] longs = {System.currentTimeMillis(), System.nanoTime()};String[] words = "The quick brown fox jumps over the lazy dog".split(" ");@Testpublic void testToString() throws IllegalAccessException {Map<String, Object> arrays = new LinkedHashMap<>();for(Field f : getClass().getDeclaredFields())arrays.put(f.getName(), f.get(this));arrays.entrySet().forEach(System.out::println);} }它打印。
booleans=[Z@277c0f21 bytes=[B@6073f712 chars=[C@43556938 shorts=[S@3d04a311 floats=[F@7a46a697 ints=[I@5f205aa doubles=[D@6d86b085 longs=[J@75828a0f words=[Ljava.lang.String;@3abfe836我認為這對每個人都是顯而易見的。 O_O喜歡的事實,J是一個升翁內部碼和L為的J ava類的內部碼。 當b未使用時, Z也是布爾值的代碼。
我們對于它可以做些什么呢?
在此程序中,我們最終不得不編寫一個特殊的toString方法,以供需要通過打印Map.Entry的特殊方法調用對象時使用。 重復此操作多次可以提高程序的吞吐量,并且避免在Java中使用數組很容易,因為它們很難調試。
黑客JVM呢?
我們可以做的就是更改Object.toString()。 我們必須更改此類,因為它是我們有權訪問的數組的唯一父級。 我們無法更改數組的代碼,因為它是JVM內部的。 例如,對于所有byte []特定方法,沒有byte [] Java類文件。
取得java.lang.Object的源代碼副本,并將toString()替換為
public String toString() {if (this instanceof boolean[])return Arrays.toString((boolean[]) this);if (this instanceof byte[])return Arrays.toString((byte[]) this);if (this instanceof short[])return Arrays.toString((short[]) this);if (this instanceof char[])return Arrays.toString((char[]) this);if (this instanceof int[])return Arrays.toString((int[]) this);if (this instanceof long[])return Arrays.toString((long[]) this);if (this instanceof float[])return Arrays.toString((float[]) this);if (this instanceof double[])return Arrays.toString((double[]) this);if (this instanceof Object[])return Arrays.deepToString((Object[]) this);return getClass().getName() + "@" + Integer.toHexString(hashCode());}在Java <= 8中,我們可以通過添加到命令行將此類添加到bootclasspath的開頭
-Xbootclasspath/p:target/classes(或您的類已編譯到的任何位置),現在當我們運行程序時,
booleans=[true, false] bytes=[1, 2, 3] chars=[H, e, l, l, o, , W, o, r, l, d] shorts=[111, 222, 333] floats=[1.0, 2.2, 3.33, 44.44, 55.555, 666.666] ints=[1, 22, 333, 4444, 55555, 666666] doubles=[3.141592653589793, 2.718281828459045] longs=[1457629893500, 1707696453284240] words=[The, quick, brown, fox, jumps, over, the, lazy, dog]就像您使用其他任何語言一樣。
結論
雖然這是一個很酷的技巧,但是最好的解決方案是他們最終修復Java,以便為數組生成合理的輸出。 它知道您需要一個并提供它,但是將其隱藏在您必須通過Google查找的類中,以便每個新的Java開發人員在第一次嘗試使用數組時都必須擁有一個WTF時刻。
翻譯自: https://www.javacodegeeks.com/2016/03/printing-arrays-hacking-jvm.html
總結
以上是生活随笔為你收集整理的通过入侵JVM打印阵列的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: hotspot jvm_在Hotspot
- 下一篇: 安卓系统卸载软件卸载的干净吗(安卓系统卸