jvm 宕机 打印jvm_通过入侵JVM打印阵列

jvm 宕机 打印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(" ");

    @Test
    public 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 宕机 打印jvm

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值