此源输出 G'Day Mate.
这是怎么发生的?
public static void main(String args[]) {
System.out.println("Hello World");
}
static {
try {
Field value = String.class.getDeclaredField("value");
value.setAccessible(true);
value.set("Hello World", value.get("G'Day Mate."));
} catch (Exception e) {
throw new AssertionError(e);
}
}
如果我们将主要函数 "Hello World"
更改为 new String("Hello World")
:
System.out.println(new String("Hello World"));
它输出 Hello world
。
实际发生了什么?
最佳答案
本源码开启了java的一些有趣的技巧。让我们一一考察。
首先我们需要了解代码的流程。哪部分代码会先执行?
静态初始化 block 。为什么?咨询一下Java Language Specification (12.4) :
Initialization of a class consists of executing its static initializers and the initializers for static fields (class variables) declared in the class.
什么时候发生?再次来自 JLS (12.4.1) :
T is a class and a static method declared by T is invoked.
所以我们可以得出结论,static initiazlier会先于main方法执行。
现在,这两行正在使用反射:
Field value = String.class.getDeclaredField("value");
value.setAccessible(true);
为了简单起见,我们可以将第一行分成两行:
Class<String> c = String.class;
Field value = c.getDeclaredField("value");
第一行是检索 Reflected Class Object第二行是检索一个 Field
,它表示 String
类的 value
字段。
value.setAccessible(true)
表示反射类对象在使用时应该抑制Java语言访问检查。( Reference )。
问题下一行是
value.set("Hello World", value.get("G'Day Mate."));
如果我们深入研究 .set() documenation我们可以看到我们正在调用 set(Object aObject,Object value)
版本的 set
。 value.get("G'Day Mate.")
正在返回 "G'Day Mate."
的 value
字段值,实际上是一个 char[]
。通过调用 set
,它将 "Hello World"
对象的值字段替换为 "G'Day Mate."
对象的值字段.
解释了 static
block 的代码。
让我们深入了解主要功能。
这很简单。它应该输出 Hello, world
。但它正在输出 G'Day Mate
。为什么?
因为我们在 static
初始化器中创建的 Hello, world
String 对象与我们在 main 函数中使用的 Hello, world
对象相同。咨询JLS再次阐明它
Moreover, a string literal always refers to the same instance of class String. This is because string literals - or, more generally, strings that are the values of constant expressions (§15.28) - are "interned" so as to share unique instances, using the method String.intern.
这answer可以帮助您更简洁地了解事实。
所以它显示不同的值,因为我们已经将 Hello,world
对象的值更改为 G'Day, Mate
。
但是,如果您在 main 函数中使用 new String("Hello world")
,它将直接创建一个新的 String
实例,而不是检入其池中。因此 main 函数的 Hello world
将不同于我们已更改其值的静态初始化程序的 Hello world
。
关于带有反射和字符串的 Java 拼图,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20036436/