1. 题目引入
我们先来看这么一道题目,读者可以先尝试做一下:
选项A: tarena and abc 选项B: tarena and gbc
选项C: test ok and abc 选项D: test ok and gbc
你会选择哪一个呢?我一开始选择的是D,但是正确答案是B!!!数组里面的值改变了,但是String类型的值没有改变.
同样是引用类型,string类型和数组类型到底有什么区别呢,接下来我们分别介绍它们的特点和机制.
2. String类型引用
String str = new String("tarena");
这个语句执行的时候:
首先会检查字符串常量池有没有“tarena”,如果没有,就在字符串常量池创建一个“tarena”,然后根据字符串常量池的“tarena”,在堆中创建一个“tarena”对象,这个str指向堆中的“tarena”对象;如果字符串常量池有“tarena”,就直接在堆中创建一个“tarena”对象.
总的来说,就是在堆中有一个str成员变量,指向堆中的一个地址A,地址A中的值是“tarena”.且由于字符串是不可变的,那么这个地址A的值“tarena”是不变的.str的指向的字符串常量的值始终是“tarena”,除非将str指向其他地址.
3. 数组类型引用
在Java中,数组也是一种引用类型,但是相较于String类型,数组中引用的值是可以修改.
char[] ch = {"a","b","c"};
同样,上面语句在堆中创建一个成员变量ch,并创建一个地址B,B中的值是数组的元素:"a","b","c",该成员变量ch指向地址B.
4.题目具体分析
public void change(String str,char ch[]){
//引用类型变量,传递的是地址,属于引用传递。
str="test ok";
ch[0]="g";
}
上面语句执行的时候,在栈中创建2个局部变量str,ch:
局部变量str被赋予A地址的副本,指向A地址.而局部变量ch被赋予地址B的副本,指向地址B.
当 str="test ok"; 执行的时候,我们知道地址A的内容是不会变的,那么即使局部变量str指向地址A,它的值变化也不会引起地址A中的值(即字符串常量的值)变化,而是在栈中开辟一个地址C,地址C中的值是“test ok”,局部变量str指向地址C,而成员变量str仍然指向地址A,且值是“tarena”.
当 ch[0]="g"; 执行的时候,由于地址B中的值可变,那么局部变量ch的值的变化,会导致地址B中的值的变化,地址B中第一个值就从"a"变为"g",因此成员变量ch指向地址B,它的值也变化["g","b","c"].
本题关键:理解不同类型引用的值是否可变.