文章目录
首先,我们要知道
值传递
和引用传递
的区别;
然后要了解Java中基本类型
和引用类型
的区别,以及Java中"="
的作用;
最后我们再来判断Java到底是值传递还是引用传递。
一、值传递和引用传递
- 值传递:是指在调用函数时将实际参数复制一份到函数中,在函数中对参数修改的话,不会影响到实际参数。
- 引用传递:是指在调用函数时将实际参数的地址传递到函数中,在函数中对参数进行修改的话,将影响到实际参数。
值传递 | 引用传递 | |
---|---|---|
区别 | 创建副本 | 不创建副本 |
结果 | 函数中无法改变原始对象 | 函数中可以改变原始对象 |
二、基本类型和引用类型
- 基本类型:对于基本数据类型,值就直接保存在变量里面。例如图中的num,10直接保存在变量中。
- 引用类型:对于引用数据类型,变量保存的不是对象,而是对象的地址值(地址值是int / long类型的)。一般也称这个为“引用”,对象中保存着实际的内容,而引用则指向这个对象。
三、赋值运算符"="的作用
- 基本类型:对于基本类型,赋值运算符会直接改变变量的值。
- 引用类型:对于引用类型,赋值运算符会直接改变变量中的地址值。
但是原来的对象并不会被改变
。
若执行如下语句:
num = 20;
str = "world";
- 当执行
num = 20
时,赋值运算符会直接改变变量 num 的值,将其改为20
; - 当执行
str = "world"
时,赋值运算符会直接改变变量 str 中的地址,地址从0x10
变为了0x20
,但是原来的对象"Hello"
并没有被改变。(由于没有任何引用指向这个对象,所以在GC时会被JVM当作垃圾回收掉)
四、调用方法时发生了什么
1、基本类型
我们先给 num 赋值为10,然后调用方法 fun(int value)
在fun方法中,将 value 改为20
最后我们在最初的方法中输出num,发现它的值还是10
原因:因为调用fun()方法后,num 和value的值都是10,但valule是num的副本,所以在方法fun()中改变value的值后,原方法中num的值不会受到任何影响。
2、引用类型:提供了改变自身值的方法
- 我们先创建StringBuilder对象sb,并初始化它的值为
"Hello"
- 然后调用fun(StringBuilder builder)方法
- 在方法fun()中,我们使用对象本身的方法append来修改builder的值
- 回到最初的方法中,打印sb输出"Hello world"。我们发现sb的值被改变了
原因:调用fun()方法后,sb和builder其实都指向了同一个对象(如下图),此时builder使用方法改变值,其实就是对这个对象本身做了修改。由于sb也指向了这个对象,所以打印出的sb并不是"Hello",而是"Hello world"。
3、引用类型:提供了改变自身值的方法,但是不使用这个方法,而是使用了赋值运算符(=)
- 我们先创建StringBuilder对象sb,并初始化它的值为
"Hello"
- 然后调用fun(StringBuilder builder)方法
- 在方法fun()中,我们创建一个新的StringBuilder对象并初始化为" world",并使用赋值运算符
- 回到最初的方法中,打印sb输出"Hello",sb的值并没有被改变
原因:调用fun()方法后,sb和builder都指向了同一个对象。但是在fun()方法中创建了一个新对象,并使用赋值运算符(=),导致builder的地址被替换掉了。此时sb和builder指向的是不同的对象。
打印sb时,由于原对象"Hello"并没有被修改,所以sb的值并没有改变。
五、总结
在Java中:
- 如果参数是基本类型,传递的是基本类型的
字面量值
的拷贝; - 如果参数是引用类型,传递的是该变量所引用的对象在堆中
地址值
的拷贝。
所以,Java中只有值传递。