为什么字符串在Java中是不可变的?

为什么字符串在Java中是不可变的?,java,string,Java,String,我在一次采访中被问到为什么字符串是不可变的 我这样回答: 当我们在java中创建一个字符串时,比如strings1=“hello”然后是一个 对象将在字符串池(hello)中创建,并且s1将 指向hello。现在,如果我们再次执行String s2=“hello”然后 不会创建另一个对象,但s2将指向hello 因为JVM将首先检查同一对象是否存在于 字符串池或不存在。如果不存在,则只创建一个新池,否则不创建 现在假设java允许字符串可变,那么如果我们将s1更改为hello world,那么s

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

我这样回答:

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

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


任何人能告诉我我的答案是对的还是错的吗?

字符串类是FINAL
,这意味着你不能创建任何类来继承它,改变基本结构,使Sting可变

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


您添加的原因并没有使字符串不可变。这说明了字符串是如何存储在堆中的。此外,字符串池在性能上产生了巨大的差异。

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

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

安全性

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


希望它能对您有所帮助。

String
是不可变的,原因如下:

  • 安全性:在网络连接、数据库连接URL、用户名/密码等中,参数通常表示为
    字符串
    。如果参数是可变的,则可以轻松更改这些参数
  • 同步和并发:使字符串不可变会自动使其线程安全,从而解决同步问题
  • 缓存:当编译器优化字符串对象时,它会看到如果两个对象具有相同的值(a=“test”和b=“test”),那么您只需要一个字符串对象(对于a和b,这两个对象将指向同一个对象)
  • 类加载
    字符串
    用作类加载的参数。如果可变,则可能导致加载错误的类(因为可变对象更改其状态)
这就是说,
String
的不变性只意味着您不能使用它的公共API来更改它。实际上,您可以使用反射绕过普通API。请参见答案

在您的示例中,如果<代码>字符串是可变的,那么考虑下面的例子:

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

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

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

根据关于DZone的文章:

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

效率 字符串的哈希代码在Java中经常使用。例如,在HashMap中。不可变保证了hashcode始终不变,因此可以缓存它而不必担心更改。这意味着,无需每次使用hashcode时都计算它

我读了这篇文章,认为以下可能是最重要的原因:

字符串在Java中是不可变的,因为字符串对象在 字符串池。因为缓存的字符串文本在多个 客户总有风险,一个客户的行为会影响 所有其他客户


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


我还要补充一点,因为
String
是不可变的,所以多线程是安全的,单个字符串实例可以在不同线程之间共享。这避免了为线程安全而使用同步,字符串是隐式的
线程安全的

字符串由Sun micro systems提供为不可变的,因为字符串可用于存储为地图集合中的键。
StringBuffer是可变的。这就是原因,它不能用作来自
安全性的映射对象中的键
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 ....
}
String a = "Naresh";
String b = "Naresh";
String c = "Naresh";
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
    }
}
char[] charArr = 'HELLO';
char[1] = 'I'; //you can do this