猿问

Java字符串真的是不可变的吗?

Java字符串真的是不可变的吗?

我们都知道StringJava 中是不可变的,但请检查以下代码:


String s1 = "Hello World";  

String s2 = "Hello World";  

String s3 = s1.substring(6);  

System.out.println(s1); // Hello World  

System.out.println(s2); // Hello World  

System.out.println(s3); // World  


Field field = String.class.getDeclaredField("value");  

field.setAccessible(true);  

char[] value = (char[])field.get(s1);  

value[6] = 'J';  

value[7] = 'a';  

value[8] = 'v';  

value[9] = 'a';  

value[10] = '!';  


System.out.println(s1); // Hello Java!  

System.out.println(s2); // Hello Java!  

System.out.println(s3); // World  

为什么这个程序运行这样?为什么价值s1和s2变化,但不是s3?


HUX布斯
浏览 524回答 3
3回答

繁星点点滴滴

在Java中,如果将两个字符串原语变量初始化为同一个字面值,则会为这两个变量分配相同的引用:String Test1="Hello World";String Test2="Hello World";System.out.println(test1==test2); // true这就是比较返回true的原因。创建第三个字符串,使用substring()该字符串创建一个新字符串而不是指向相同的字符串。使用反射访问字符串时,您将获得实际指针:Field field = String.class.getDeclaredField("value");field.setAccessible(true);因此,更改为将更改包含指向它的指针的字符串,但由于s3它创建的新字符串substring()不会更改。

蝴蝶刀刀

你正在使用反射来规避String的不变性 - 它是一种“攻击”形式。你可以创建很多像这样的例子(例如你甚至可以实例化一个Void对象),但这并不意味着String不是“不可变的”。有些用例可能会使用这种类型的代码,并且可以“良好编码”,例如尽早清除内存中的密码(GC之前)。根据安全管理器的不同,您可能无法执行代码。
随时随地看视频慕课网APP

相关分类

Java
我要回答