在讲值传递和引用传递之前,我们应该先了解一下什么是值类型和引用类型。
什么是值类型?
值类型:也就是基本数据类型,基本数据类型常被称为四类八种。
四类:1-整型;2-浮点型;3-字符型;4-逻辑型
八种:
1:整型3种 byte,short,int,long
2:浮点型2种 float,double
3:字符型1种 char
4:逻辑型1种 boolean
什么是引用类型?
引用类型:除了四类八种基本类型外,所有的类型都称为引用类型(数组,类,接口,字符串)。
值传递:基本数据类型赋值都属于值传递,值传递传递的是实实在在的变量值,是传递原参数的拷贝,值传递后,实参传递给形参的值,形参发生改变而不影响实参。
引用传递:引用类型之间赋值属于引用传递。引用传递传递的是对象的引用地址,也就是它的本身(自己最通俗的理解)。就是将实参的地址传递给形参,形参改变了,实参当然被改变了,因为他们指向相同的地址。
内存分配:
一个具有值类型(value type)的数据存放在栈内的一个变量中。即是在栈中分配内存空间,直接存储所包含的值,其值就代表数据本身。
值类型的数据具有较快的存取速度。
一个具有引用类型(reference type)的数据并不驻留在栈中,而是存储于堆中。即是在堆中分配内存空间,不直接存储所包含的值,而是指向所要存储的值,其值代表的是所指向的地址。当访问一个具有引用类型的数据时,需要到栈中检查变量的内容,该变量引用堆中的一个实际数据。引用类型的数据比值类型的数据具有更大的存储规模和较低的访问速度。
Java中有垃圾回收机制,栈内存中的变量随着方法的结束内存自然销毁了,而用引用类型的时候,当方法结束的时候,这个对象可能被另一个引用类型所应用,不会销毁,只有当一个对象没有任何引用变量引用的时候,垃圾回收机制才会回收。
用两段代码来演示一下,先看第一段代码:
public class Test {
public static void main(String[] args) {
int a = 0, b = a;
a = 1;
System.out.println("b="+b);
}
}
这段代码输出的结果是:
b=0
我们再看下第二段代码:
public class Test {
public static void main(String[] args) {
Te a = new Te(0);
Te b = a;
a.value = 1;
System.out.println("b.value="+b.value);
}
}
class Te {
int value;
public Te(){}
public Te(int v){
this.value = v;
}
}
这段代码的输出结果是:
b.value=1
为什么两段代码得到的结果不一样呢?
因为第一段代码使用的是值传递,而第二段代码使用的是引用传递。
第一段代码如下图所示:
第二段代码如图所示:
在写上述代码的时候遇到了一个坑,在此记录一下。当我们用字符串来测试的时候,代码如下:
public class Test {
public static void main(String[] args) {
String a = "0", b = a;
a = "1";
System.out.println("b="+b);
}
}
这时,我们会发现得到的结果确跟我们想到不一样,结果如下:
b=0
有人就会奇怪了,为什么会这样呢?字符串不是引用类型吗?那就应该是引用传递才对啊,所以最后的结果应该是b=1才对啊!可为什么最后的结果是b=0?
我们看下a=”1”这段代码,JDK在编译的时候,其实是将a=”1”编译成了a=new String(“1”),这就相当于创建了一个新的对象,如图:
SO!b的值是不会有变化的!好坑!
除了String类型之外,Integer、Double、Float、Character、Boolean等等之类引用类型也需要注意!