java中值与引用问题的简单笔记
java中传值与传引用的问题由来已久,今天上网无意中又发现了这个问题的讨论,于是自己也复习了一下,想想还是整理一下思路,记下来供概念还有些模糊的童鞋参考参考。
关于值与引用的问题,最直观的可以用一段代码来表示:
public class Test {
public static void main(String[] args) {
String a = new String("hello");
String b = new String("hello");
if(a==b) System.out.println("true");
else System.out.println("false");
}
}
这段代码返回的是“flase”,显然可以看出来:比较(==)两个String数据的时候,并不是比较的两个数据的“值”,而是比较两个数据的“引用”是否指向同一个对象
PS.进行“比较”,也就是“==”的时候, 如果比较的是两个基本数据类型(char,byte,short,int,long,float,double,boolean),则是判断它们的值是否相等。 如果比较的不是两个基本数据类型,而是两个对象变量,则是判断它们的引用是否指向同一个对象,也就是看引用地址是否一致。 引申一下:java的基本数据类型都是传“值”的,其他的则是传“引用” (“引用”指的是内存里保存这个“值”的地址标识,本质上还是一个“值”)
所谓的“值”指的是内存里的数据值,这里是“hello”;而“引用”指的是内存里这个数据值的地址。这段代码里a与b是分别实例化的,在内存里的地址显然是不同,所以比较的结果就是“false”。
========================
这边偏一下题:创建String对象除了new,常用还有通过引号来创建,比如
public class Test {
public static void main(String[] args) {
String a = "hello";
String b = "hello";
if(a==b) System.out.println("true");
else System.out.println("false");
}
}
这中情况下返回的是“true”!这个就与JAVA虚拟机(JVM)中的字符串池有关系了。字符串池里的String对象是可以被共享使用的,因此它提高了效率。并且由于String类是final的,它的值一经创建就不可改变,因此不会因为String对象共享而带来程序的混乱。
当执行String a = "hello";的时候,JVM首先在字符串池中查找是否已经存在了值为"hello"的这么一个对象,它的判断依据是String类equals(Object obj)方法的返回值。如果字符串池中已经存在,则不再创建新的对象,直接返回已存在对象的引用;如果不存在,则先创建这个值为“hello”的对象,再把这个对象加入到字符串池中,最后将这个对象的引用返回。
因此,在这段程序中,执行String a= "hello";的时候,由于字符串池中不存在“hello”,程序创建了一个新的对象“hello”,保存到池里,并把这个对象的引用地址返回;当执行String b = "hello";的时候,由于字符串池中已经存在了刚刚创建的“hello”对象,所以直接获得了这个hello对象的引用地址,并赋值给了b。
所以这个时候,a跟b进行比较的时候,a跟b的引用地址是一样的(都是执行String a= "hello";的时候返回的那个引用地址),所以最终的比较结果是“true”。
========================
回到正题:再来看一段简单的代码