考虑下面的例子。

String str = new String();

str  = "Hello";
System.out.println(str);  //Prints Hello

str = "Help!";
System.out.println(str);  //Prints Help!

在Java中,String对象是不可变的。那么为什么对象str可以被赋值为"Help!"呢?这难道不是与Java中字符串的不变性相矛盾吗?有人能给我解释一下不变性的确切概念吗?

编辑:

好的。我现在明白了,但还有一个问题。下面的代码呢:

String str = "Mississippi"; 
System.out.println(str); // prints Mississippi 

str = str.replace("i", "!"); 
System.out.println(str); // prints M!ss!ss!pp! 

这是否意味着将再次创建两个对象(“Mississippi”和“M!ss!ss!pp!”),并且在replace()方法之后引用str指向不同的对象?


当前回答

字符串类是不可变的,你不能改变不可变对象的值。 但在String的情况下,如果你改变了String的值,它会在字符串池中创建新的字符串,而不是旧的字符串引用。通过这种方式,字符串是不可变的。 举个例子,

String str = "Mississippi";  
System.out.println(str); // prints Mississippi 

它将创建一个字符串“Mississippi”,并将其添加到字符串池 所以现在str指向密西西比。

str = str.replace("i", "!");  
System.out.println(str); // prints M!ss!ss!pp! 

但经过上述操作, 另一个字符串将被创建"M!ss!ss!pp!" 它将被添加到String池。而且 现在str指向M!ss!ss!pp!而不是密西西比州。

通过这种方式,当你改变string对象的值时,它会创建一个新的对象并将其添加到string池中。

让我们再看一个例子

String s1 = "Hello"; 
String s2 = "World"; 
String s = s1 + s2;

上面的3行代码将向字符串池中添加3个字符串对象。 1)你好 2)世界 3) HelloWorld

其他回答

关于你问题的替换部分,试试这个:

String str = "Mississippi"; 
System.out.println(str); //Prints Mississippi 

String other = str.replace("i", "!"); 
System.out.println(str); //still prints Mississippi 
System.out.println(other);  // prints M!ss!ss!pp!

因为String是不可变的,所以如果你不把function的返回值赋给String,就不会发生变化。所以在你的问题中,将swap函数的返回值赋给s。

S =swap(S, n1, n2);那么字符串S的值将会改变。

我也得到了不变的值,当我写程序得到一些排列字符串(虽然它没有给出所有的排列,但这是为了回答你的问题)

这里有一个例子。

> import java.io.*;  public class MyString { public static void
> main(String []args)throws IOException {  BufferedReader br=new
> BufferedReader(new InputStreamReader(System.in));  String
> s=br.readLine().trim(); int n=0;int k=0;  while(n!=s.length()) {
> while(k<n){  swap(s,k,n); System.out.println(s); swap(s,k,n); k++; }
> n++; } }  public static void swap(String s,int n1,int n2) { char temp;
> temp=s.charAt(n1); StringBuilder sb=new StringBuilder(s);
> sb.setCharAt(n1,s.charAt(n2)); sb.setCharAt(n2,temp); s=sb.toString();
> } }

但是我没有从上面的代码得到字符串的排列值。因此,我将swap函数的返回值分配给字符串,并得到了更改的字符串值。在分配返回值后,我得到了字符串的排列值。

/import java.util.*; import java.io.*; public class MyString { public static void main(String []args)throws IOException{
BufferedReader br=new BufferedReader(new InputStreamReader(System.in)); 
String s=br.readLine().trim(); int n=0;int k=0; 
while(n!=s.length()){ while(k<n){ s=swap(s,k,n); 
System.out.println(s); s=swap(s,k,n); k++; } n++; } } 
public static String swap(String s,int n1,int n2){
char temp; temp=s.charAt(n1); StringBuilder sb=new StringBuilder(s); sb.setCharAt(n1,s.charAt(n2)); sb.setCharAt(n2,temp); s=sb.toString(); return s; } }

让我们把它分成几个部分

String s1 = "hello";

此语句创建包含hello的字符串并占用内存空间,即在常量字符串池中,并将其分配给引用对象s1

String s2 = s1;

这条语句将相同的字符串hello赋值给新引用s2

         __________
        |          |
s1 ---->|  hello   |<----- s2
        |__________| 

两个引用都指向相同的字符串,因此输出相同的值,如下所示。

out.println(s1);    // o/p: hello
out.println(s2);    // o/p: hello

虽然String是不可变的,但可以赋值,因此s1现在将引用新的值堆栈。

s1 = "stack";    
         __________
        |          |
s1 ---->|  stack   |
        |__________|

但是指向hello的s2对象呢它还是原来的样子。

         __________
        |          |
s2 ---->|  hello   |
        |__________|

out.println(s1);    // o/p: stack
out.println(s2);    // o/p: hello

由于字符串是不可变的,Java虚拟机不允许我们通过它的方法修改字符串s1。它将在池中创建所有新的String对象,如下所示。

s1.concat(" overflow");

                 ___________________
                |                   |
s1.concat ----> |  stack overflow   |
                |___________________|

out.println(s1);    // o/p: stack
out.println(s2);    // o/p: hello
out.println(s1.concat); // o/p: stack overflow

注意,如果String将是可变的,那么输出将是

out.println(s1);    // o/p: stack overflow

现在,您可能会感到惊讶,为什么String需要修改concat()这样的方法。下面的代码片段将消除您的困惑。

s1 = s1.concat(" overflow");

这里我们将修改后的string值赋值给s1引用。

         ___________________
        |                   |
s1 ---->|  stack overflow   |
        |___________________|


out.println(s1);    // o/p: stack overflow
out.println(s2);    // o/p: hello

这就是为什么Java决定将String作为最终类,否则任何人都可以修改和改变String的值。 希望这能有所帮助。

如果HELLO是你的字符串,那么你不能把HELLO改成HILLO。这个性质叫做不可变性。

你可以有多个指针字符串变量指向HELLO字符串。

但是如果HELLO是char Array,那么你可以将HELLO改为HILLO。例如,

char[] charArr = 'HELLO';
char[1] = 'I'; //you can do this

编程语言具有不可变的数据变量,因此可以作为键、值对中的键使用。

字符串不会改变,但对它的引用会改变。你混淆了不可变性和final字段的概念。如果一个字段被声明为final,那么一旦它被赋值,就不能重新赋值。