带有反射和字符串的 Java 拼图

标签 java reflection puzzle

此源输出 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) 版本的 setvalue.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/

相关文章:

java - Spotify 拼图 : avoiding exception handling error

java - 删除对象的引用

java - Spring Controller - 将 JSON 属性映射到外键实体

c# - 将属性名称作为字符串传递到方法中 .NET

c# - 如果我将引用项目的 Copy Local 设置为 false,则主项目找不到程序集

algorithm - 编程两列火车在没有位置数据或通信的情况下相交(逻辑谜题)

java - 二叉树是否包含另一棵树?

java - 在 Java 中读/写文件

java - 如何初始化 NamedParameterJdbcTemplate 变量

java - 使用反射调用Java中的方法并获取返回值