这个 Java 代码片段是如何工作的?(字符串池和反射)

2022-08-31 11:51:03

Java字符串池与反射相结合,可以在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" 

马里奥怎么了?


答案 1

马里奥怎么了?

你基本上改变了它。是的,通过反射,您可以违反字符串的不可变性...由于字符串滞留,这意味着任何使用“Mario”(除了在较大的字符串常量表达式中,该表达式将在编译时解析)在程序的其余部分最终为“Luigi”。

这种事情就是为什么反射需要安全权限的原因...

请注意,由于 的左结合性,该表达式执行任何编译时串联。这是有效的,这就是为什么你仍然看到.如果将代码更改为:str + " " + "Mario"+(str + " ") + "Mario"Luigi Luigi

System.out.println(str + (" " + "Mario"));

...然后你会看到编译器将被拘留到一个不同的字符串。Luigi Mario" Mario""Mario"


答案 2

它被设置为路易吉。Java中的字符串是不可变的;因此,编译器可以将 所有提及解释为对同一 String 常量池项(大致称为“内存位置”)的引用。您使用反射来更改该项目;所以你的代码中的所有内容现在都像你写的一样。"Mario""Mario""Luigi"