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

2022-08-31 06:08:15

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

我是这样回答的:

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

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

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


答案 1

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

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

话虽如此,不可变性仅意味着您无法使用其公共API更改它。实际上,您可以使用反射绕过正常的 API。请参阅此处的答案。String

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

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

答案 2

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

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

根据DZone上的这篇文章

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

效率字符串的哈希码在Java中经常使用。例如,在哈希映射中。不可变保证了哈希码将始终相同,因此可以对其进行缓存而不必担心更改。这意味着,没有必要在每次使用时都计算哈希码。