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