Java字符串真的是不可变的吗? [英] Is a Java string really immutable?

查看:120
本文介绍了Java字符串真的是不可变的吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

We all know that String is immutable in Java, but check the following code:

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

Why does this program operate like this? And why is the value of s1 and s2 changed, but not s3?

推荐答案

字符串是不可变的*但这只是意味着你无法使用其公共API更改它。

String is immutable* but this only means you cannot change it using its public API.

你在这里做的是使用反射来规避正常的API。同样,您可以更改枚举值,更改整数自动装箱中使用的查找表等。

What you are doing here is circumventing the normal API, using reflection. The same way, you can change the values of enums, change the lookup table used in Integer autoboxing etc.

现在,原因 s1 s2 更改值,是它们都引用相同的实习字符串。编译器执行此操作(如其他答案所述)。

Now, the reason s1 and s2 change value, is that they both refer to the same interned string. The compiler does this (as mentioned by other answers).

原因 s3 对我来说实际上有点令人惊讶,因为我以为它会共享数组(它在早期版本的Java中做了,在Java 7u6之前)。但是,查看 String 的源代码,我们可以看到实际上复制了子字符串的字符数组(使用 Arrays.copyOfRange(..))。这就是它保持不变的原因。

The reason s3 does not was actually a bit surprising to me, as I thought it would share the value array (it did in earlier version of Java, before Java 7u6). However, looking at the source code of String, we can see that the value character array for a substring is actually copied (using Arrays.copyOfRange(..)). This is why it goes unchanged.

您可以安装 SecurityManager ,以避免恶意代码执行此类操作。但请记住,某些库依赖于使用这些反射技巧(通常是ORM工具,AOP库等)。

You can install a SecurityManager, to avoid malicious code to do such things. But keep in mind that some libraries depend on using these kind of reflection tricks (typically ORM tools, AOP libraries etc).

*)我最初写的是 String s不是真正不可变的,只是有效的不可变。这可能会误导当前 String 的实现,其中数组确实标记为私人决赛。但是,值得注意的是,没有办法将Java中的数组声明为不可变的,因此必须注意不要将它暴露在类之外,即使使用正确的访问修饰符也是如此。

*) I initially wrote that Strings aren't really immutable, just "effective immutable". This might be misleading in the current implementation of String, where the value array is indeed marked private final. It's still worth noting, though, that there is no way to declare an array in Java as immutable, so care must be taken not to expose it outside its class, even with the proper access modifiers.

由于这个话题似乎非常受欢迎,这里有一些建议进一步阅读: Heinz Kabutz的反思疯狂讲话,其中涵盖了OP中的许多问题,以及其他反思......好吧......疯狂。

As this topic seems overwhelmingly popular, here's some suggested further reading: Heinz Kabutz's Reflection Madness talk from JavaZone 2009, which covers a lot of the issues in the OP, along with other reflection... well... madness.

它涵盖了为什么这有时很有用。为什么,大多数时候,你应该避免它。 : - )

It covers why this is sometimes useful. And why, most of the time, you should avoid it. :-)

这篇关于Java字符串真的是不可变的吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆