码:
public static void main ( String[] args){
String a = new String("Hello");
String b = " pardner.";
System.out.println(a+b);
System.out.println("a.equals(\"Hello\") --> " + (a.equals("Hello")));
System.out.println("a --> " + a);
}
static {
try {
Field value = String.class.getDeclaredField("value");
value.setAccessible(true);
value.set("Hello", value.get("Howdy"));
} catch (Exception e) { }
}
Run Code Online (Sandbox Code Playgroud)
结果:
Howdy pardner.
a.equals("Hello") --> true
a --> Howdy
Run Code Online (Sandbox Code Playgroud)
打印时,此代码如何将"Hello"更改为"Howdy"?
首先,String由相同字符组成的文字解析为同一个实例.所以
String one = "hello";
String two = "hello";
Run Code Online (Sandbox Code Playgroud)
两个变量都指的是同一个对象.
其次,static初始化块在首次加载(并初始化)类时执行.这在调用任何类方法之前发生,即.之前main.
第三,您的Java版本的实现String可能使用char\[\]字段来存储字符串.此字段已命名value.
您正在使用反射来检索该char[]为String被引用的对象String字面"Howdy".
Field value = String.class.getDeclaredField("value");
...
value.get("Howdy")
Run Code Online (Sandbox Code Playgroud)
并将其分配给文字引用char[]的String对象的字段String"Hello"
value.set("Hello", value.get("Howdy"));
Run Code Online (Sandbox Code Playgroud)
现在,当你的main方法执行时
String a = new String("Hello");
Run Code Online (Sandbox Code Playgroud)
在String文字"Hello"中引用了你设置了相同的对象char[]先前场.这char[]包含字符'H','o','w','d',和'y'因为它是取自String通过字面引用的对象"Howdy".
这些字符将复制到此处创建的新 String对象中
String a = new String("Hello");
Run Code Online (Sandbox Code Playgroud)
首先发生的是你的static块执行.通过反射,它改变了String ato 的值"Howdy"(实际上它改变了String "Hello"to "Howdy"但具有相同的效果).但是,你明白了
a.equals("Hello") --> true
Run Code Online (Sandbox Code Playgroud)
因为编译器已经用该值替换了true.我跑了javap -v,得到了
31: ldc #75 // String a.equals(\"Hello\") --> true
Run Code Online (Sandbox Code Playgroud)
所以这就是发生的事情.正如我在评论中指出的那样,如果你String a改为
final String a = "Hello";
Run Code Online (Sandbox Code Playgroud)
最后一行更改为
a --> Hello
Run Code Online (Sandbox Code Playgroud)
出于同样的原因.
看看这里:
http://docs.oracle.com/javase/7/docs/api/java/lang/reflect/Field.html
public void set(Object obj,Object value)
将指定对象参数上此Field对象表示的字段设置为指定的新值.如果基础字段具有基本类型,则新值将自动解包.
public get(Object obj)
返回指定对象上此Field表示的字段的值.
首先执行静态块.
在main()执行之前,所有出现的包含"Hello"的String都被字符串"Howdy"替换为反射.
"Hello"和"Howdy"指的是同一个对象.这就是s.equals("Hello")输出true
System.out.println(a.equals("Howdy"));也会输出的原因true.
看一下确切的执行过程:
