Java - 字符串不变性和数组可变性

时间:2015-09-16 13:14:14

标签: java string immutability

我知道数组ab指向与字符串s1s2不同的地方。为什么?

代码:

    String[] a = {"a","b","c"};
    String[] b = a;
    a[0] = "Z";
    String s1 = "hello";
    String s2 = s1;
    s1 = "world";
    System.out.println(Arrays.toString(a) + " - a"); //a and b are same
    System.out.println(Arrays.toString(b) + " - b");
    System.out.println(s1 + " "+ s2); // s1 and s2 are not same.

输出:

    [Z, b, c] - a
    [Z, b, c] - b
    world hello

4 个答案:

答案 0 :(得分:5)

在第(2)点,s1s2指向池中的相同文字。但是当你改变s1时,会创建另一个文字并且字符串不再指向同一个地方。

String s1 = "hello";
String s2 = s1; (2)
s1 = "world";

您可以通过打印

的结果来验证这一点
s1 == s2

请注意,我没有使用equals因为我对比较引用感兴趣。现在,只要您为s1分配不同的值,事情就会如下:

+-------+
| world |  <- s1
+-------+

+-------+
| hello |  <- s2
+-------+

答案 1 :(得分:2)

ab是对同一个数组的引用(内存中有一个Array对象。)

a ---> ["a", "b", "c"] <---- b

您正在使用以下行更改此数组值:

a[0] = "Z"

所以你知道在记忆中有这个:

a ---> ["Z", "b", "c"] <---- b

对于弦乐来说,情况有所不同。

首先,您有两个指向相同值的变量:

String s1 = "hello";
String s2 = s1;

你在内存中有这个:

s1 ---> "hello" <---- s2

但是,您可以使用以下代码将s1分配给新值:

s1 = "world";

变量s2仍然指向字符串“hello”。现在内存中有2个字符串对象。

s1 ---> "world" 
s2 ---> "hello"

在Java中,字符串是不可变的,但数组是可变的。 另请参阅this question

请注意,如果您定义了一个类,则行为将更接近Array。

public class Foo() {
  private int _bar = 0;
  public void setBar(int bar) {
    this._bar = bar   
  }
  public void getBar() {
    return this._bar;
  }
}


Foo f1 = new Foo();
Foo f1 = f2;

你有这个:

f1 ----> Foo [ _bar = 0 ] <---- f2

您可以处理该对象:

f1.setBar(1)
f2.setBar(2) // This is the same object

这使得某些东西有点像“数组”:

f1 ----> Foo [ _bar = 2 ] <---- f2

但是如果你将f2分配给另一个值,你得到这个:

f2 = new Foo();

在内存中创建一个新值,但仍保留第一个引用 指向第一个对象。

f1 ----> Foo [ _bar = 2 ] 
f2 ----> Foo [ _bar = 0 ]

答案 2 :(得分:1)

数组是对象,因此如果更改数组元素,则更改<ItemGroup> <Compile Include="folder\file1.fs" /> <Compile Include="file.fs" /> <-- this can't be between the folder files, all folder files have to be listed together <Compile Include="folder\file2.fs" /> </ItemGroup> a指向的对象。

字符串是不可变对象,因此您只能更改引用,即在调用b时正在执行的操作。

更深入的解释:

的字符串:

s1 = "world"

所以最后s1将指向一个值为“world”的不同字符串对象。

阵列:

String s1 = "hello"; //creates a new String object with value "hello" and assigns a reference to that object to s1
String s2 = s1;  //s2 now points to the same object as s1
s1 = "world"; //creates a new String object with value "world" and assigns a reference to that object to s1

这里你永远不会改变作为数组引用的String[] a = {"a","b","c"}; //creates the array and assigns a reference to it to variable a String[] b = a; //copies the reference of a to b, so both point to the same object a[0] = "Z"; //changes the 1st element in the array, a and b still point to it 的实际值,而是更改数组第一个元素的值,它本身就是对字符串“Z”的引用。

答案 3 :(得分:1)

关键的区别在于重新分配与修改。

重新分配x = ...)使变量指向新对象,但不会更改基础对象,因此指向原始对象的任何其他变量都不会更改

修改x.something = ...x[...] = ...)仅更改基础对象,因此指向同一对象的任何其他变量都将反映更改。

请注意,字符串是不可变的 - 它们没有修改它们的方法,也没有(非最终的)公共成员变量,所以它们不能被修改(没有反射)。

你可以想到人们指着书籍是你的变量而书本身就是基础对象。

很多人都可以指出同一本书。您可以让某人指向不同的图书,而无需更改图书本身或其他任何人指向的图书。如果你在书中写一些东西,有人指着指向那本书的每个人都会看到这些变化。

int[] a = {0,1,2,3,4}; // Assign a to, let's say, "Object 1"
int[] b = {5,6,7,8};   // Assign b to, let's say, "Object 2"
int[] c = a;           // Assign c to Object 1
a[0] = 2;              // Change Object 1's 0th element
assert c[0] == 2;      // c points to Object 1, whose 0th element is now 2
a = b;                 // Assign a to Object 2
assert c[0] == 2;      // c still points to Object 1