您的位置:首页 > 编程语言 > Java开发

修改 JVM 输出数组

2016-03-14 21:00 363 查看
我的网站

前言

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]


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

翻译原文
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  jvm class java array