数组是不可变的
Demo and Analysis
数组是不可变的,与字符串的不可变一样。下面看起来好像数组改变了,实际上数组是不可改变的,改变的是变量ns的 “指向” 。
public static void main(String[] args) {
int[] ns;
ns = new int[] { 68, 79, 91, 85, 62 };
System.out.println(ns.length); // 5
ns = new int[] { 1, 2, 3 };
System.out.println(ns.length); // 3
}
执行 ns = new int[] { 68, 79, 91, 85, 62 }
时,JVM虚拟机先创建了一个数组,然后把数组变量ns指向它;
ns
│
▼
┌───┬───┬───┬───┬───┬───┬───┐
│ │68 │79 │91 │85 │62 │ │
└───┴───┴───┴───┴───┴───┴───┘
执行 ns = new int[] { 1, 2, 3 }
时,JVM虚拟机创建了一个新的数组,然后把数组变量ns指向它;
ns ──────────────────────┐
│
▼
┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐
│ │68 │79 │91 │85 │62 │ │ 1 │ 2 │ 3 │ │
└───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘
数组元素的可变性
数组元素的可变性与数组无关,取决于元素类型。
1)数组元素是不可变的字符串
比如下面程序中,数组元素是字符串类型,原字符串 “XYZ” 的内容是不可改变的,我们只能创建新的字符串并让数组元素指向新创建的字符串。
public static void main(String[] args) {
String[] names = {"ABC", "XYZ", "zoo"};
String s = names[1];
names[1] = "cat";
System.out.println(s); // 输出XYZ
System.out.println(names[1]); // 输出cat
}
对于String[]类型的数组变量names,它实际上包含3个元素,但每个元素都指向某个字符串对象。
┌─────────────────────────┐
names │ ┌─────────────────────┼───────────┐
│ │ │ │ │
▼ │ │ ▼ ▼
┌───┬───┬─┴─┬─┴─┬───┬───────┬───┬───────┬───┬───────┬───┐
│ │░░░│░░░│░░░│ │ "ABC" │ │ "XYZ" │ │ "zoo" │ │
└───┴─┬─┴───┴───┴───┴───────┴───┴───────┴───┴───────┴───┘
│ ▲
└─────────────────┘
names[1] = "cat"
,就是创建了新的字符串 “cat” ,然后将数组names[1]指向它。也就是字符串””是不可变的
┌─────────────────────────────────────────────────┐
names │ ┌─────────────────────────────────┐ │
│ │ │ │ │
▼ │ │ ▼ ▼
┌───┬───┬─┴─┬─┴─┬───┬───────┬───┬───────┬───┬───────┬───┬───────┬───┐
│ │░░░│░░░│░░░│ │ "ABC" │ │ "XYZ" │ │ "zoo" │ │ "cat" │ │
└───┴─┬─┴───┴───┴───┴───────┴───┴───────┴───┴───────┴───┴───────┴───┘
│ ▲
└─────────────────┘
2)数组元素是可变的整型
如果数组元素是整型,由于整型是可变的,所以数组元素也是可变的。 ns[1] = 66
是使用新的值66覆盖 ns[1]
在内存中存储单元保存的旧值。
public static void main(String[] args) {
int[] ns = {50, 70, 90};
ns[1] = 66;
}
执行 int[] ns = {50, 70, 90}
,在内存单元中结果如下所示;
ns
│
▼
┌───┬───┬───┬───┬───┬───┬───┐
│ │50 │70 │90 │ │ │ │
└───┴───┴───┴───┴───┴───┴───┘
执行 ns[1] = 66
,在内存单元中结果如下所示。
由于为数组分配的是连续的存储单元,所以根据数组的引用(图中的指针)和数组下标,我们可以知道 ns[1]
的内存地址并使用新的值覆盖该存储单元保存的旧值。
ns
│
▼
┌───┬───┬───┬───┬───┬───┬───┐
│ │50 │66 │90 │ │ │ │
└───┴───┴───┴───┴───┴───┴───┘
他の者にできたか?ここまでやれたか?この先できるか?いいや、仆にしかできない!