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
}
}
}
Above code will print:
"Luigi Luigi"
What happened to Mario?
What happened to Mario ??
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...
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"));
... then you'll see Luigi Mario
as the compiler will have interned " Mario"
to a different string to "Mario"
.
See more on this question at Stackoverflow