Java中String类型的不变性
今天做有关String的练习,发现有两个地方难以理解,就是关于String类型的不可变性,现在做一个总结:
String类型的不可变性有两种情况:
- 第一种
public static void main(String[] args) {
String s1 = "hello";
String s2 = "hello";
s1 = "world";//没有删除"hello",只是新开辟了内存空间存储"world"
System.out.println(s1);//world
System.out.println(s2);//hello
System.out.println(s1 == s2);//false
}
首先分别创建两个String类型对象s1,s2,使其指向内容都为"hello",然后又让s1 = “world”,从三个输出结果来看,s1指向的内容为"world",s2的值为"hello",s1不等于s2。接下来从其内存结构的角度进行解释:
s1只是一个String对象的引用,并不是对象本身,存在栈中,“hello"字符串存放在常量池中。对象在内存中是一块内存区,成员变量越多,这块内存区占的空间越大。引用只是一个4字节的数据,里面存放了它所指向的对象的地址,通过这个地址可以访问对象。也就是说,s1只是一个引用,它指向了一个具体的对象,当执s1=“world”时,又创建了一个新的对象“world”, 而引用s1重新指向了这个新的对象,并不是将"hello"改为"world”,而是重新分配空间存储"world",原来的对象"hello”还在内存中存在,并没有改变。s1存储的地址由之前的0x1101变为0x2211,而s2仍然指向0x1101,所以输出s1==s2的结果为false。
- 第二种
package com.zretc.java;
public class Test04 {
String str = new String ("good");
char [] ch = {'t','e','s','t'};
public void change(String str,char ch[]) {
str = "test ok";
System.out.println(str);
ch[0] = 'b';
}
public static void main(String[] args) {
Test04 test = new Test04();
test.change(test.str, test.ch);
System.out.println(test.str);
System.out.println(test.ch);
}
}
上述代码中,在调用change(test.str,test.ch)方法,执行 str=”test ok"语句时,如果从第一种的角度来看,好像test.str最后应该指向"test ok",但是结果不是这样的:
可以看的最后输出test.str仍然是之前创建对象时赋值的"good",而test.ch在方法内部经过ch[0]=“b"语句后,最后输出为best”,这是为什么呢?为什么str的重新赋值语句没有改变test.str的值,而ch[0]重新赋值以后却发生了改变呢?
其实这并不违背第一种情况。参数传递有两种情况:基本数据类型传递的是值,引用数据类型传递地址。而这里传递的test.str和test.ch传递的都是引用数据类型,但是当String对象作为形参传递到方法里的时候,实际上传递的是test.str引用的拷贝,改变的是test.str引用的拷贝,而当方法结束后,形参test.str被销毁, 原test.str的引用保持不变,还是指向原常量池中的"good",而数组ch就是引用类型,没有不可变特征,所以"test"被改为"best"。