修改 JVM 输出数组

我的网站

前言

Java 比较常见的局限性中,输出数组可以算是其中一个。如果关于如何输出一个数组的回答得到了 1000 以上的赞,那么你就应该好好考虑是否还有一种更简单的方法。在其他的语言中都有简单的方式输出数组,而 Java 为什么没有呢?

不像 JDK 类库中的其他类,数组并没有继承 Object 的 toString() 方法。


输出的类型和地址对吗?


实际上 Java 并没有输出地址,取而代之的是一种比较神秘的输出形势,输出包含了类型的内部表示以及实例的 hashCode() 值。由于所有的数组都是一个对象,因此都会有一个 hashCode()、自己的类型、一个同步锁以及其他 Object 所带的属性和方法,但是没有一个是为数组专门设计的方法。这就是为什么 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

这些输出值对于每一位都是熟悉的。J 是 long 内部代码, L 是 Java 类的内部代码,Z 是布尔类型的内部代码。

在上边的程序中我们最终写了一个特殊的 toString 方法来打印 Map.Entry。在整个程序中多次的调用,这种方式在 Java 中相对来说是更简单些,他它们不好调试。


通过更改 JVM ?


我们需要做的就是更改 Object.toString(),这个类是我们唯一能够访问到的数组的父类,数组本身是定义到 JVM 内部的,无法直接接触到相关代码。即没有类似 byte[] 这样的类来定义 byte[] 可访问的方法。

拷贝一份 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]

就像在其他语言里边看到的结果一样。


翻译原文

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值