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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/22397861/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 15:31:19  来源:igfitidea点击:

Why is String immutable in Java?

javastring

提问by rocking

I was asked in an interview why String is immutable

我在一次采访中被问到为什么 String 是不可变的

I answered like this:

我是这样回答的:

When we create a string in java like String s1="hello";then an object will be created in string pool(hello)and s1will be pointing to hello.Now if again we do String s2="hello";then another object will not be created but s2will point to hellobecause JVMwill first check if the same object is present in string poolor not.If not present then only a new one is created else not.

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

Now if suppose java allows string mutable then if we change s1to hello worldthen s2value will also be hello worldso java String is immutable.

现在,如果假设Java允许串可变那么如果我们改变S1hello world那么S2价值也将hello world因此Java字符串是不可改变的。

Can any body please tell me if my answer is rightor wrong?

任何人都可以告诉我我的答案是还是

回答by Kick

String class is FINALit mean you can't create any class to inherit it and change the basic structure and make the Sting mutable.

String 类是否FINAL意味着您不能创建任何类来继承它并更改基本结构并使 Sting 可变。

Another thing instance variable and methods of String class that are provided are such that you can't change Stringobject once created.

提供的另一件事实例变量和 String 类的方法是这样的,String一旦创建对象就不能更改。

The reason what you have added doesn't make the String immutable at all.This all says how the String is stored in heap.Also string pool make the huge difference in performance

您添加的原因根本不会使 String 不可变。这一切都说明了 String 在堆中的存储方式。此外,字符串池对性能产生了巨大的影响

回答by JDGuide

Most important reason according to thisarticle on DZone:

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

String Constant Pool... If string is mutable, changing the string with one reference will lead to the wrong value for the other references.

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. ...

字符串常量池...如果字符串是可变的,使用一个引用更改字符串将导致其他引用的值错误。

安全

String 被广泛用作许多java 类的参数,例如网络连接、打开文件等。如果String 不是一成不变的,连接或文件将被更改并导致严重的安全威胁。...

Hope it will help you.

希望它会帮助你。

回答by JDGuide

Stringis immutable for several reasons, here is a summary:

String由于多种原因是不可变的,这里是一个总结:

  • Security: parameters are typically represented as Stringin network connections, database connection urls, usernames/passwords etc. If it were mutable, these parameters could be easily changed.
  • Synchronizationand 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: Stringis used as arguments for class loading. If mutable, it could result in wrong class being loaded (because mutable objects change their state).
  • 安全性:参数通常表示为String网络连接、数据库连接 url、用户名/密码等。如果它是可变的,则这些参数可以轻松更改。
  • 同步和并发:使 String 自动不可变使它们线程安全,从而解决同步问题。
  • 缓存:当编译器优化您的 String 对象时,它会看到如果两个对象具有相同的值(a="test" 和 b="test"),因此您只需要一个字符串对象(对于 a 和 b,这两个将指向同一个对象)。
  • 类加载String用作类加载的参数。如果是可变的,则可能会导致加载错误的类(因为可变对象会更改其状态)。

That being said, immutability of Stringonly means you cannot change it using its public API. You can in fact bypass the normal API using reflection. See the answer here.

话虽如此,String唯一的不变性意味着您不能使用其公共 API 更改它。实际上,您可以使用反射绕过普通 API。请参阅此处的答案。

In your example, if Stringwas mutable, then consider the following example:

在您的示例中,如果String是可变的,请考虑以下示例:

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

回答by Alex Mathew

Java Developers decide Strings are immutable due to the following aspect design, efficiency, and security.

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

DesignStrings 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.

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

According to thisarticle on DZone:

根据文章DZone:

SecurityString 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.

EfficiencyThe 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.

SecurityString 被广泛用作许多java 类的参数,例如网络连接、打开文件等。如果String 不是一成不变的,连接或文件将被更改并导致严重的安全威胁。可变字符串也可能导致反射中的安全问题,因为参数是字符串。

效率字符串的哈希码在 Java 中经常使用。例如,在 HashMap 中。不可变保证了 hashcode 始终相同,这样就可以缓存而不必担心更改。也就是说,每次使用时都不需要计算 hashcode。

回答by Tho

I read this post Why String is Immutable or Final in Javaand suppose that following may be the most important reason:

我读了这篇文章Why String is Immutable or Final in Java,并假设以下可能是最重要的原因:

String is Immutable in Java because String objects are cached in String pool. Since cached String literals are shared between multiple clientsthere is always a risk, where one client's action would affect all another client.

String 在 Java 中是不可变的,因为 String 对象缓存在 String pool 中。由于缓存的字符串文字在多个客户端之间共享,因此始终存在风险,其中一个客户端的操作会影响所有另一个客户端。

回答by Akshay

You are right. Stringin java uses concept of String Poolliteral. When a string is created and if the string already exists in the pool, the reference of the existing string will be returned, instead of creating a new object and returning its reference.If a string is not immutable, changing the string with one reference will lead to the wrong value for the other references.

你是对的。String在java中使用String Pool文字的概念。创建字符串时,如果字符串已存在于池中,则将返回现有字符串的引用,而不是创建新对象并返回其引用。如果字符串不是不可变的,则使用一个引用更改字符串将导致其他引用的错误值。

I would add one more thing, since Stringis immutable, it is safe for multi threading and a single String instance can be shared across different threads. This avoid the usage of synchronization for thread safety, Strings are implicitly thread safe.

我还要添加一件事,因为String它是不可变的,它对于多线程是安全的,并且单个 String 实例可以在不同的线程之间共享。这避免了使用同步来保证线程安全,字符串是隐式的thread safe

回答by chaithanya krishna gogineni

String is given as immutable by Sun micro systems,because string can used to store as key in map collection. StringBuffer is mutable .That is the reason,It cannot be used as key in map object

Sun 微系统将字符串指定为不可变的,因为字符串可以用作地图集合中的键。StringBuffer 是可变的。这就是原因,它不能用作映射对象中的键

回答by darxtrix

From the Securitypoint of view we can use this practical example:

从这个Security角度来看,我们可以使用这个实际的例子:

DBCursor makeConnection(String IP,String PORT,String USER,String PASS,String TABLE) {

    // if strings were mutable IP,PORT,USER,PASS can be changed by validate function
    Boolean validated = validate(IP,PORT,USER,PASS);

    // here we are not sure if IP, PORT, USER, PASS changed or not ??
    if (validated) {
         DBConnection conn = doConnection(IP,PORT,USER,PASS);
    }

    // rest of the code goes here ....
}

回答by Sameer Sinha

The most important reason of a String being made immutable in Java is Securityconsideration. Next would be Caching.

在 Java 中将 String 设为不可变的最重要原因是安全考虑。接下来是缓存

I believe other reasons given here, such as efficiency, concurrency, design and string poolfollows from the fact that String in made immutable. For eg. String Pool could be created because String was immutable and not the other way around.

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

Check Gosling interview transcript here

在此处查看 Gosling 采访记录

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

从战略的角度来看,他们往往更容易无故障。而且通常有些事情你可以用不可变的东西做而你不能用可变的东西做,比如缓存结果。如果将字符串传递给文件打开方法,或者将字符串传递给用户界面中标签的构造函数,则在某些 API(如许多 Windows API)中,您将传递字符数组。该对象的接收者确实必须复制它,因为他们对它的存储寿命一无所知。他们不知道物体发生了什么,是否在他们脚下发生了变化。

您最终几乎被迫复制该对象,因为您不知道是否可以拥有它。不可变对象的好处之一就是答案是:“是的,你当然知道。” 因为不存在谁有权更改所有权的问题。

迫使字符串不可变的一件事是安全性。你有一个文件打开方法。你传递一个字符串给它。然后它会在开始执行操作系统调用之前进行各种身份验证检查。如果你设法在安全检查之后和操作系统调用之前做一些有效地改变字符串的事情,那么繁荣,你就进去了。但是字符串是不可变的,所以这种攻击是行不通的。那个精确的例子是真正要求字符串不可变的

回答by Naresh Joshi

We can not be sure of what was Java designers actually thinking while designing Stringbut we can only conclude these reasons based on the advantages we get out of string immutability, Some of which are

我们无法确定 Java 设计人员在设计时实际在想什么,String但我们只能根据我们从字符串不变性中获得的优势得出这些原因,其中一些是

1. Existence of String Constant Pool

一、字符串常量池的存在

As discussed in Why String is Stored in String Constant Poolarticle, every application creates too many string objects and in order to save JVM from first creating lots of string objects and then garbage collecting them. JVM stores all string objects in a separate memory area called String constant pool and reuses objects from that cached pool.

正如为什么字符串存储在字符串常量池一文中所讨论的那样,每个应用程序都会创建过多的字符串对象,为了避免 JVM 先创建大量字符串对象,然后对其进行垃圾回收。JVM 将所有字符串对象存储在称为字符串常量池的单独内存区域中,并重用该缓存池中的对象。

Whenever we create a string literal JVM first sees if that literal is already present in constant pool or not and if it is there, new reference will start pointing to the same object in SCP.

每当我们创建一个字符串字面量时,JVM 首先查看该字面量是否已经存在于常量池中,如果存在,新引用将开始指向 SCP 中的同一个对象。

String a = "Naresh";
String b = "Naresh";
String c = "Naresh";

In above example string object with value Nareshwill get created in SCP only once and all reference a, b, cwill point to the same object but what if we try to make change in ae.g. a.replace("a", "").

在与值上面的例子中的字符串对象Naresh将在SCP获得创建只有一次,所有参考abc会如果我们试图在改变指向同一个对象,但什么aa.replace("a", "")

Ideally, ashould have value Nreshbut b, cshould remain unchanged because as an end user we are making the change in aonly. And we know a, b, call are pointing the same object so if we make a change in a, others should also reflect the change.

理想情况下,a应该有值Nresh,但是bc应该维持不变,因为我们一直在变动中的最终用户a只。而且我们知道a, b,c都指向同一个对象,因此如果我们在 中进行更改a,其他人也应该反映该更改。

But string immutability saves us from this scenario and due to the immutability of string object string object Nareshwill never change. So when we make any change in ainstead of change in string object NareshJVM creates a new object assign it to aand then make change in that object.

但是字符串不变性使我们免于这种情况,并且由于字符串对象的不变性,字符串对象Naresh永远不会改变。因此,当我们a在字符串对象中进行任何更改而不是更改时,NareshJVM 会创建一个新对象并将其分配给该对象a,然后在该对象中进行更改。

So String pool is only possible because of String's immutability and if String would not have been immutable, then caching string objects and reusing them would not have a possibility because any variable woulds have changed the value and corrupted others.

所以字符串池是唯一可能的,因为字符串的不变性,如果字符串不是不可变的,那么缓存字符串对象并重用它们就不可能,因为任何变量都会改变值并破坏其他变量。

And That's why it is handled by JVM very specially and have been given a special memory area.

这就是为什么它被 JVM 非常特殊地处理并被赋予了一个特殊的内存区域。

2. Thread Safety

2. 线程安全

An object is called thread-safe when multiple threads are operating on it but none of them is able to corrupt its state and object hold the same state for every thread at any point in time.

当多个线程在其上运行但没有一个线程能够破坏其状态并且对象在任何时间点为每个线程保持相同状态时,该对象被称为线程安全的。

As we an immutable object cannot be modified by anyone after its creation which makes every immutable object is thread safe by default. We do not need to apply any thread safety measures to it such as creating synchronized methods.

因为我们一个不可变对象在创建后不能被任何人修改,这使得每个不可变对象在默认情况下都是线程安全的。我们不需要对其应用任何线程安全措施,例如创建同步方法。

So due to its immutable nature string object can be shared by multiple threads and even if it is getting manipulated by many threads it will not change its value.

因此,由于其不可变的性质,字符串对象可以被多个线程共享,即使它被多个线程操作,它也不会改变它的值。

3. Security

3. 安全

In every application, we need to pass several secrets e.g. user's user-name\passwords, connection URLs and in general, all of this information is passed as the string object.

在每个应用程序中,我们需要传递几个秘密,例如用户的用户名\密码、连接 URL,并且通常所有这些信息都作为字符串对象传递。

Now suppose if String would not have been immutable in nature then it would cause a serious security threat to the application because these values are allowed to get changed and if it is allowed then these might get changed due to wrongly written code or any other person who have access to our variable references.

现在假设如果 String 本质上不是不可变的,那么它将对应用程序造成严重的安全威胁,因为这些值被允许更改,如果被允许,那么这些值可能会由于错误编写的代码或任何其他人可以访问我们的变量引用。

4. Class Loading

4. 类加载

As discussed in Creating objects through Reflection in Java with Example, we can use Class.forName("class_name")method to load a class in memory which again calls other methods to do so. And even JVM uses these methods to load classes.

正如在 Java 中通过反射创建对象和示例中所讨论的那样,我们可以使用Class.forName("class_name")方法在内存中加载一个类,该类再次调用其他方法来执行此操作。甚至 JVM 也使用这些方法来加载类。

But if you see clearly all of these methods accepts the class name as a string object so Strings are used in java class loading and immutability provides security that correct class is getting loaded by ClassLoader.

但是,如果您清楚地看到所有这些方法都接受类名作为字符串对象,因此在 java 类加载中使用字符串,而不变性提供了安全性,确保正确的类被ClassLoader.

Suppose if String would not have been immutable and we are trying to load java.lang.Objectwhich get changed to org.theft.OurObjectin between and now all of our objects have a behavior which someone can use to unwanted things.

假设 String 不是不可变的,并且我们正在尝试加载在两者之间java.lang.Object更改的内容org.theft.OurObject,现在我们所有的对象都具有某人可以用来处理不需要的东西的行为。

5. HashCode Caching

5. HashCode 缓存

If we are going to perform any hashing related operations on any object we must override the hashCode()method and try to generate an accurate hashcode by using the state of the object. If an object's state is getting changed which means its hashcode should also change.

如果我们要对任何对象执行任何与散列相关的操作,我们必须覆盖该hashCode()方法并尝试使用对象的状态生成准确的散列码。如果一个对象的状态正在改变,这意味着它的哈希码也应该改变。

Because String is immutable so the value one string object is holding will never get changed which means its hashcode will also not change which gives String class an opportunity to cache its hashcode during object creation.

因为 String 是不可变的,所以一个字符串对象持有的值永远不会改变,这意味着它的哈希码也不会改变,这使 String 类有机会在对象创建期间缓存其哈希码。

Yes, String object caches its hashcode at the time of object creation which makes it the great candidate for hashing related operations because hashcode doesn't need to be calculated again which save us some time. This is why String is mostly used as HashMapkeys.

是的,String 对象在对象创建时缓存其哈希码,这使其成为哈希相关操作的绝佳候选者,因为不需要再次计算哈希码,这为我们节省了一些时间。这就是为什么 String 主要用作HashMap键的原因。

Read More on Why String is Immutable and Final in Java.

阅读更多关于为什么 String 在 Java 中是不可变和最终的