代码:
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) { }
}
结果:
Howdy pardner.
a.equals("Hello") --> true
a --> Howdy
此代码如何变更" Hello"和#34;你好"打印时?
答案 0 :(得分:9)
首先,String
literals composed of the same characters resolve to the same instance.所以
String one = "hello";
String two = "hello";
两个变量都指的是同一个对象。
第二,static
initializer blocks are executed when a class is first loaded (and initialized)。这在调用任何类方法之前发生,即。在main
之前。
对于char[]
文字String
引用的String
对象,您using reflection to retrieve "Howdy"
。{/ p>
Field value = String.class.getDeclaredField("value");
...
value.get("Howdy")
并将其分配到char[]
文字String
String
对象的"Hello"
字段
value.set("Hello", value.get("Howdy"));
现在,当您的main
方法执行时
String a = new String("Hello");
String
文字"Hello"
引用之前为其设置char[]
字段的同一对象。此char[]
包含字符'H'
,'o'
,'w'
,'d'
和'y'
,因为它来自String
文字"Howdy"
引用的对象。
这些字符将复制到此处创建的新 String
对象
String a = new String("Hello");
答案 1 :(得分:8)
首先发生的是你的static
块执行。通过反思,它会将String a
的值更改为"Howdy"
(实际上它会将String
"Hello"
更改为"Howdy"
,但效果相同)。但是,你得到了
a.equals("Hello") --> true
因为编译器已经用true
替换了该值。我跑了javap -v
并得到了
31: ldc #75 // String a.equals(\"Hello\") --> true
所以这就是发生的事情。正如我在评论中指出的那样,如果您将String a
更改为
final String a = "Hello";
最后一行变为
a --> Hello
出于同样的原因。
答案 2 :(得分:6)
看看这里:
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)
返回此字段所代表的字段的值 指定的对象。
首先执行静态块。
在执行main()
之前,所有出现的包含“Hello”的String都被字符串“Howdy”替换为反射。
“Hello”和“Howdy”指的是同一个对象。这就是s.equals("Hello")
输出为真的原因
System.out.println(a.equals("Howdy"));
也会输出true
。
查看确切的执行过程: