这个源代码开启了一些有趣的java技术。让我们一一检查。
首先我们需要了解代码的流程。代码的哪一部分将首先执行?
静态初始化块。为什么?让我们查阅Java 语言规范 (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");
第一行是检索反射类对象,第二行是检索Field
表示类value
字段的a String
。
value.setAccessible(true)
表示反射的类对象在使用时应该禁止 Java 语言访问检查。(参考)。
有问题的下一行是
value.set("Hello World", value.get("G'Day Mate."));
如果我们深入研究 .set() 文档,我们可以看到我们正在调用 .set() 的set(Object aObject,Object value)
版本set
。value.get("G'Day Mate.")
正在返回"G'Day Mate."
的value
字段值实际上是一个char[]
. 并通过它的调用将对象的值字段的值set
替换为对象的值字段。"Hello World"
"G'Day Mate."
解释了static
块的代码。
让我们深入了解主要功能。这很简单。它应该输出Hello, world
. 但它正在输出G'Day Mate
。为什么?因为Hello, world
我们在初始化器中创建的 String 对象与我们在 main 函数中使用的对象static
相同。Hello, world
再次与JLS 协商将阐明这一点
此外,字符串字面量总是引用 String 类的同一个实例。这是因为字符串字面量 - 或者更一般地说,作为常量表达式值的字符串(第 15.28 节) - 是“内部的”,以便使用 String.intern 方法共享唯一实例。
这个答案可以帮助您更简洁地理解事实。
因此它显示了不同的值,因为我们已经将Hello,world
对象的值更改为G'Day, Mate
.
但是,如果您new String("Hello world")
在 main 函数中使用,它将直接创建一个新实例,String
而不是检入其池中。所以Hello world
main 函数Hello world
与我们改变了值的静态初始化器不同。