在一次采访中,有人问我为什么String是不可变的

我是这样回答的:

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

现在如果假设java允许字符串可变,那么如果我们将s1改为hello world,那么s2值也将是hello world,所以java字符串是不可变的。

谁能告诉我我的答案是对的还是错的?


当前回答

由于以下方面的设计、效率和安全性,Java开发人员决定字符串是不可变的。

Design Strings are created in a special memory area in java heap known as "String Intern pool". While you creating new String (Not in the case of using String() constructor or any other String functions which internally use the String() constructor for creating a new String object; String() constructor always create new string constant in the pool unless we call the method intern()) variable it searches the pool to check whether is it already exist. If it is exist, then return reference of the existing String object. If the String is not immutable, changing the String with one reference will lead to the wrong value for the other references.

根据DZone上的这篇文章:

Security String is widely used as parameter for many java classes, e.g. network connection, opening files, etc. Were String not immutable, a connection or file would be changed and lead to serious security threat. Mutable strings could cause security problem in Reflection too, as the parameters are strings. Efficiency The hashcode of string is frequently used in Java. For example, in a HashMap. Being immutable guarantees that hashcode will always the same, so that it can be cached without worrying the changes.That means, there is no need to calculate hashcode every time it is used.

其他回答

由于以下方面的设计、效率和安全性,Java开发人员决定字符串是不可变的。

Design Strings are created in a special memory area in java heap known as "String Intern pool". While you creating new String (Not in the case of using String() constructor or any other String functions which internally use the String() constructor for creating a new String object; String() constructor always create new string constant in the pool unless we call the method intern()) variable it searches the pool to check whether is it already exist. If it is exist, then return reference of the existing String object. If the String is not immutable, changing the String with one reference will lead to the wrong value for the other references.

根据DZone上的这篇文章:

Security String is widely used as parameter for many java classes, e.g. network connection, opening files, etc. Were String not immutable, a connection or file would be changed and lead to serious security threat. Mutable strings could cause security problem in Reflection too, as the parameters are strings. Efficiency The hashcode of string is frequently used in Java. For example, in a HashMap. Being immutable guarantees that hashcode will always the same, so that it can be cached without worrying the changes.That means, there is no need to calculate hashcode every time it is used.

除了这些精彩的回答,我还想补充几点。像字符串一样,Array保存了对数组开头的引用,所以如果你创建了两个数组arr1和arr2,并做了类似arr2 = arr1的事情,这将使arr2的引用与arr1相同,因此改变其中一个的值将导致另一个的改变

public class Main {
    public static void main(String[] args) {
        int[] a = {1, 2, 3, 4};
        int[] b = a;
        a[0] = 8;
        b[1] = 7;
        System.out.println("A: " + a[0] + ", B: " + b[0]);
        System.out.println("A: " + a[1] + ", B: " + b[1]);
        //outputs
        //A: 8, B: 8
        //A: 7, B: 7
    }
}

Not only that it would cause bugs in the code it also can(and will) be exploited by malicious user. Suppose if you have a system that changes the admin password. The user have to first enter the newPassword and then the oldPassword if the oldPassword is same as the adminPass the program change the password by adminPass = newPassword. let's say that the new password has the same reference as the admin password so a bad programmer may create a temp variable to hold the admin password before the users inputs data if the oldPassword is equal to temp it changes the password otherwise adminPass = temp. Someone knowing that could easily enter the new password and never enter the old password and abracadabra he has admin access. Another thing I didn't understand when learning about Strings why doesn't JVM create a new string for every object and have a unique place in memory for it and you can just do that using new String("str"); The reason you wouldn't want to always use new is because it's not memory efficient and it is slower in most cases read more.

这可能与安全性没有多大关系,因为安全实践建议使用字符数组作为密码,而不是字符串。这是因为当不再需要数组时,可以立即删除数组。不同的是,字符串不能被擦除,因为它是不可变的。在垃圾收集之前可能需要很长时间,在内容被覆盖之前可能需要更长的时间。

我认为选择不变性是为了允许共享字符串,它们很容易分裂。字符串赋值,选择子字符串变成了一个常数时间的操作,字符串比较也是,因为可重用的哈希码是字符串数据结构的一部分,可以首先进行比较。

从另一方面来说,如果原始字符串很大(比如大型XML文档),那么从中选取少量符号可能会防止整个文档被垃圾收集。因此,后来的Java版本似乎远离了这种不变性。现代c++既有可变(std::string)版本,从c++ 17开始也有不可变(std::string_view)版本。

在Java中使字符串不可变的最重要的原因是安全考虑。下一个是缓存。

我相信这里给出的其他原因,比如效率、并发性、设计和字符串池,都源于字符串不可变的事实。如。可以创建字符串池,因为字符串是不可变的,而不是相反。

点击这里查看高斯林的采访记录

From a strategic point of view, they tend to more often be trouble free. And there are usually things you can do with immutables that you can't do with mutable things, such as cache the result. If you pass a string to a file open method, or if you pass a string to a constructor for a label in a user interface, in some APIs (like in lots of the Windows APIs) you pass in an array of characters. The receiver of that object really has to copy it, because they don't know anything about the storage lifetime of it. And they don't know what's happening to the object, whether it is being changed under their feet. You end up getting almost forced to replicate the object because you don't know whether or not you get to own it. And one of the nice things about immutable objects is that the answer is, "Yeah, of course you do." Because the question of ownership, who has the right to change it, doesn't exist. One of the things that forced Strings to be immutable was security. You have a file open method. You pass a String to it. And then it's doing all kind of authentication checks before it gets around to doing the OS call. If you manage to do something that effectively mutated the String, after the security check and before the OS call, then boom, you're in. But Strings are immutable, so that kind of attack doesn't work. That precise example is what really demanded that Strings be immutable

字符串是不可变的有几个原因,这里是一个总结:

Security: parameters are typically represented as String in network connections, database connection urls, usernames/passwords etc. If it were mutable, these parameters could be easily changed. Synchronization and concurrency: making String immutable automatically makes them thread safe thereby solving the synchronization issues. Caching: when compiler optimizes your String objects, it sees that if two objects have same value (a="test", and b="test") and thus you need only one string object (for both a and b, these two will point to the same object). Class loading: String is used as arguments for class loading. If mutable, it could result in wrong class being loaded (because mutable objects change their state).

也就是说,String的不可变性只是意味着你不能使用它的公共API改变它。实际上,您可以使用反射绕过常规API。在这里看到答案。

在你的例子中,如果String是可变的,那么考虑下面的例子:

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