问题描述
Java字符串池加上反射可以在Java中产生一些难以想象的结果:
Java string pool coupled with reflection can produce some unimaginable result in Java:
import java.lang.reflect.Field;
class MessingWithString {
public static void main (String[] args) {
String str = "Mario";
toLuigi(str);
System.out.println(str + " " + "Mario");
}
public static void toLuigi(String original) {
try {
Field stringValue = String.class.getDeclaredField("value");
stringValue.setAccessible(true);
stringValue.set(original, "Luigi".toCharArray());
} catch (Exception ex) {
// Ignore exceptions
}
}
}
以上代码将打印:
"Luigi Luigi"
马里奥怎么了?
推荐答案
你基本上改变了它。是的,通过反射,你可以违反字符串的不变性......并且由于字符串实习,这意味着任何使用Mario(除了在更大的字符串常量表达式中,这将在编译时解析)将结束在程序的其余部分中作为Luigi。
You changed it, basically. Yes, with reflection you can violate the immutability of strings... and due to string interning, that means any use of "Mario" (other than in a larger string constant expression, which would have been resolved at compile-time) will end up as "Luigi" in the rest of the program.
这种情况是为什么反射需要安全权限......
This kinds of thing is why reflection requires security permissions...
请注意表达式 str ++Mario
不执行任何编译时串联,因为左边-Anociativity +
。它实际上是(str +)+Mario
,这就是为什么你仍然会看到 Luigi Luigi
。如果您将代码更改为:
Note that the expression str + " " + "Mario"
does not perform any compile-time concatenation, due to the left-associativity of +
. It's effectively (str + " ") + "Mario"
, which is why you still see Luigi Luigi
. If you change the code to:
System.out.println(str + (" " + "Mario"));
...然后你会看到 Luigi Mario
因为编译器会将Mario
插入另一个字符串Mario
。
... then you'll see Luigi Mario
as the compiler will have interned " Mario"
to a different string to "Mario"
.
这篇关于这个Java代码片段如何工作? (字符串池和反射)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!