为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

HUX布斯 2019-08-14 16:36:17
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?
查看完整描述

3 回答

?
繁星点点滴滴

TA贡献1803条经验 获得超3个赞

在Java中,如果将两个字符串原语变量初始化为同一个字面值,则会为这两个变量分配相同的引用:

String Test1="Hello World";String Test2="Hello World";System.out.println(test1==test2); // true

https://img1.sycdn.imooc.com//5d53c82f00013a2707480168.jpg

这就是比较返回true的原因。创建第三个字符串,使用substring()该字符串创建一个新字符串而不是指向相同的字符串。

https://img1.sycdn.imooc.com//5d53c83100016e0a05090158.jpg

使用反射访问字符串时,您将获得实际指针:

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

因此,更改为将更改包含指向它的指针的字符串,但由于s3它创建的新字符串substring()不会更改。

https://img1.sycdn.imooc.com//5d53c83400016cd607580331.jpg


查看完整回答
反对 回复 2019-08-14
?
蝴蝶刀刀

TA贡献1801条经验 获得超8个赞

你正在使用反射来规避String的不变性 - 它是一种“攻击”形式。

你可以创建很多像这样的例子(例如你甚至可以实例化一个Void对象),但这并不意味着String不是“不可变的”。

有些用例可能会使用这种类型的代码,并且可以“良好编码”,例如尽早清除内存中的密码(GC之前)。

根据安全管理器的不同,您可能无法执行代码。


查看完整回答
反对 回复 2019-08-14
  • 3 回答
  • 0 关注
  • 523 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信