考虑下面的例子。

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指向不同的对象?


当前回答

不可变性意味着实例化对象的值不能改变,你永远不能把“Hello”变成“Help!”

变量str是一个对象的引用,当你给str赋一个新值时,你没有改变它引用的对象的值,你引用的是一个不同的对象。

其他回答

让我们把它分成几个部分

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的值。 希望这能有所帮助。

str引用的对象可以更改,但实际的String对象本身不能更改。

包含字符串“Hello”和“Help!”的String对象不能改变它们的值,因此它们是不可变的。

String对象的不可变性并不意味着指向该对象的引用不能改变。

防止str引用更改的一种方法是将其声明为final:

final String STR = "Hello";

现在,尝试将另一个String赋值给STR将导致编译错误。

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

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

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

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

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

因为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; } }

我可以说,不可变性是你不能改变字符串本身。假设你有字符串x,它的值是“abc”。现在您不能更改字符串,也就是说,您不能更改“abc”中的任何字符/s。

如果你必须改变字符串中的任何字符,你可以使用一个字符数组并改变它或使用StringBuilder。

String x = "abc";
x = "pot";
x = x + "hj";
x = x.substring(3);
System.out.println(x);

char x1[] = x.toCharArray();
x1[0] = 's';
String y = new String(x1);
System.out.println(y);

输出:

hj
sj