MD.*_*oob 13 java puzzle reflection
这个来源输出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);
}
}
Run Code Online (Sandbox Code Playgroud)
如果我们将主要功能更改"Hello World"
为new String("Hello World")
:
System.out.println(new String("Hello World"));
Run Code Online (Sandbox Code Playgroud)
它输出Hello world
.
实际上发生了什么?
MD.*_*oob 17
这个源代码打开了一些有趣的java技术.让我们逐一检查.
首先,我们需要了解代码的流程.代码的哪一部分将首先执行?
静态初始化块.为什么?让我们参考Java语言规范(12.4):
类的初始化包括执行其静态初始化程序和类中声明的静态字段(类变量)的初始化程序.
它什么时候发生?再次来自JLS(12.4.1):
T是一个类,并且调用由T声明的静态方法.
因此我们可以得出结论,静态initiazlier将在main方法之前首先执行.
现在,这两行正在使用反射:
Field value = String.class.getDeclaredField("value");
value.setAccessible(true);
Run Code Online (Sandbox Code Playgroud)
为简单起见,我们可以将第一行分成两行:
Class<String> c = String.class;
Field value = c.getDeclaredField("value");
Run Code Online (Sandbox Code Playgroud)
第一行是检索Reflected Class Object,第二行是检索Field
表示类的value
字段的行String
.
value.setAccessible(true)
表示反射的类对象在使用时应禁止Java语言访问检查.(参考).
问题的下一行是
value.set("Hello World", value.get("G'Day Mate."));
Run Code Online (Sandbox Code Playgroud)
如果我们深入了解.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
我们在static
初始化程序中创建的String对象与Hello, world
我们在main函数中使用的对象相同.再次咨询JLS将会对此有所了解
此外,字符串文字始终引用类String的相同实例.这是因为字符串文字 - 或者更常见的是作为常量表达式(第15.28节)的值的字符串 - 被"实例化"以便使用String.intern方法共享唯一实例.
这个答案可以帮助您更简洁地理解事实.
所以它显示了不同的值,因为我们已经将Hello,world
对象的值更改为G'Day, Mate
.
但是如果你new String("Hello world")
在main函数中使用它将直接创建一个新的实例,String
而不是检查它的池.因此Hello world
,main函数Hello world
与我们更改了值的静态初始化程序不同.
由于new String("Hello World")
在堆创建新的对象,而不是使用以前创建"Hello World"
的字符串常量池的对象.
所以,如果你写
System.out.print(new String("Hello World").intern());
它会显示输出为G'Day, Mate
.因为intern()
方法返回一个字符串实例的引用id String Constant Pool
.
归档时间: |
|
查看次数: |
1100 次 |
最近记录: |