为什么String在Java中是不可变的?

问题

我在接受采访时被问到为什么String是不可变的

我这样回答:

当我们在java中创建一个字符串时,如String s1 ="hello";然后将在字符串池(hello)中创建一个对象,并且s1将指向hello.Now如果我们再次执行String s2 ="hello";然后将不会创建另一个对象,但s2将指向hello,因为JVM将首先检查字符串池中是否存在相同的对象。如果不存在,则不会创建新的对象。

现在,如果假设java允许字符串可变,那么如果我们更改s1tohello worldthens2value也将是hello worldso java字符串是不可变的。

如果我的答案是,请问有谁可以告诉我吗?


#1 热门回答(126 赞)

String由于几个原因而不可变,这里有一个摘要:

  • 安全性:参数通常表示为网络连接中的字符串,数据库连接URL,用户名/密码等。如果它是可变的,则可以轻松更改这些参数。
  • 同步和并发:使字符串不可变自动使它们对线程安全,从而解决同步问题。
  • 缓存:当编译器优化你的String对象时,它会看到如果两个对象具有相同的值(a ="test",并且b ="test"),那么你只需要一个字符串对象(对于a和b,这两个将指向同一个对象)。
  • 类加载:String用作类加载的参数。如果是可变的,则可能导致加载错误的类(因为可变对象改变了它们的状态)。

话虽如此,String的不变性意味着你不能使用它的公共API来改变它。事实上,你可以使用反射绕过普通的API。见答案here

在你的示例中,ifString是可变的,请考虑以下示例:

String a="stack";
  System.out.println(a);//prints stack
  a.setValue("overflow");
  System.out.println(a);//if mutable it would print overflow

#2 热门回答(37 赞)

Java开发人员认为字符串是不可变的,因为以下方面设计,效率和安全性

设计Strings在java堆中的特殊内存区域中创建,称为"String Intern pool"。在创建新String时(不是在使用String()构造函数的情况下或者在内部使用String()构造函数创建新String对象的任何其他String函数; String()构造函数总是在池中创建新的字符串常量,除非我们调用方法intern())变量它搜索池以检查它是否已经存在。如果存在,则返回现有String对象的引用。如果String不是不可变的,则使用一个引用更改String将导致其他引用的值错误。

根据DZone的this文章:

Security String广泛用作许多java类的参数,例如:网络连接,打开文件等。字符串不是不可变的,连接或文件将被更改并导致严重的安全威胁。可变字符串也可能导致Reflection中的安全问题,因为参数是字符串。效率字符串的哈希码经常在Java中使用。例如,在HashMap中。不可变保证hashcode将始终相同,因此可以缓存它而不必担心更改。这意味着,每次使用时都不需要计算哈希码。


#3 热门回答(19 赞)

根据DZone的this文章最重要的原因:

String Constant Pool ...如果string是可变的,用一个引用更改字符串将导致其他引用的值错误。安全字符串被广泛用作许多java类的参数,例如网络连接,打开文件等。字符串不是不可变的,连接或文件将被更改并导致严重的安全威胁。 ...

希望它会对你有所帮助。