值传递和引用传递,看这篇就够了!!
概念介绍
从学术严格角度来讲JAVA中只有值传递!!!
但是就像JAVA编程规范那样约定俗成业界习惯了说成值传递和引用传递。
值传递: JAVA中基本数据类型是值传递
引用传递: JAVA中引用类型是引用传递
实践说明
伟大的领导人说过,实践是检验真理的唯一标准。那么就从一道面试题开始吧。
首先创建一个实体Persion类(注意idea中安装Lombok插件)
import lombok.Data;
@Data
public class Persion {
int age;
String name;
int phone;
public Persion(String name) {
this.name = name;
}
}
之后创建一个测试类
import com.demo.entity.Persion;
public class TestTransferValue {
public void changeValue1(int age){
age = 30;
}
public void changeValue2(Persion persion){
persion.setName("changeValue2");
}
public void changeValue3(String string){
string = "changeValue3";
}
public static void main(String[] args) {
TestTransferValue testTransferValue = new TestTransferValue();
int age = 20;
testTransferValue.changeValue1(30);
System.out.println("age:" + age);
Persion persion = new Persion("abc");
testTransferValue.changeValue2(persion);
System.out.println("persion name :" + persion.getName());
String str = "abc";
testTransferValue.changeValue3(str);
System.out.println("str:" + str);
}
}
问题:以上代码输出结果是什么?
不卖关子直接上答案,从答案入手讲解值传递与引用传递的区别。
该问题也提问过群友,分别获得以下答案
剖析过程
首先程序的入口是main函数,在内存的栈区main方法属于栈低。
解析一: 声明基本数据类型age之后把age的值传递到changeValue1函数并且把值改变为30,此时涉及到变量作用域问题方法changeValue1中的变量age是30,但是main方法age在栈中指向的引用还是20的,所以第一个打印是age=20;基本数据类型都是值传递;
解析二: 接下来来到了persion变量。声明persion变量等号的左边叫做引用,右边new的对象存放在内存堆中,准确的说是存放在堆中新生代的伊甸园区,顺便扩展一下 新生代:养老代= 1:2,新生代中分为伊甸园区:幸存区0:幸存区1 = 8:1:1。 此篇文章不做更多jvm扩展,有需要了解的关注作者后续会更新JVM相关知识。persion传递到changeValue2中将值改变为value2此时栈中persion指向堆中的地址值改变为changeValue2;继而打印结果为persion name :changeValue2,解释说明了引用传递。
重点来了 第三个按照上述的persion理解引用传递应该打印的是changeValue3,可是为什么结果不对呢?听我娓娓道来: 铺垫知识,JAVA在创建String对象的时候会从字符串常量池中查找是否有和新建字符串相同的常量,如果有则返回此时两个对象的地址也就是hashcode是一样的,否则新建一个地址保存字符串;当字符串abc传递到changeValue3函数之后,查找发现池中并没有changeValue3字符串,此时需要新建一个地址changeValue3函数中的string变量有了新的地址;但是此改变并没有改变面函数中的str 地址所以打印的事str:abc。
BLOG地址:www.liangsonghua.com
关注微信公众号:松花皮蛋的黑板报,获取更多精彩!
公众号介绍:分享在京东工作的技术感悟,还有JAVA技术和业内最佳实践,大部分都是务实的、能看懂的、可复现的