当前位置: 首页 > 科技观察

deadline面试系列,Java是按值传递还是按引用传递?

时间:2023-03-15 20:11:28 科技观察

Java是按值传递还是按引用传递?虽然这是个老生常谈的问题,但对于没有深入研究过这方面的同学,或者Java基础薄弱的同学来说,还是很难得到满意的回答。可能很多同学能轻松背出JVM、分布式事务、高并发、秒杀系统、领域模型等难题,却对Java基础问题不屑一顾。抓大放小的初衷是正确的。如果遇到深究基本细节的面试官,那你就瞎了。今天一灯就带大家深入剖析Java传输的底层原理。看完这篇文章去面试,面试官一定会对你竖起大拇指夸奖你:“小伙子,你懂Java传输!”1、什么是形参?和实参形参:就是形参,定义方法时使用的参数,用来接收调用者传递的参数。实参:就是实参,也就是调用时传递给方法的参数。参数在传递给其他方法之前已预先分配。/***@authorOneLightArchitecture*@apiNoteJava传输示例**/publicclassDemo{publicstaticvoidmain(String[]args){Stringname="OneLightArchitecture";//这里的名字是实参update(name);System.out.println(名字);}//这里的方法参数列表中的name就是形参privatestaticvoidupdate(Stringname){//doSomething}}在调用Java方法的过程中就是把实参传递给形参,并且形式参数的范围在方法内部。2、什么是值传递和引用传递?值传递:在调用方法时,将实参的副本传递给方法,这样在方法中修改形参时,实参不会受到影响。引用传递:也叫地址传递,是指在调用方法时将实参的地址传递给方法,这样方法中形参的修改就会影响到实参。也就是说传递的是值,传递的是一个副本。通过引用传递,传递的是实际内存地址。这是两者的本质区别,下面会用到。3、测试验证3.1基本数据类型验证首先使用基本数据类型验证:/***@authorYidengArchitecture*@apiNoteJavatransferexample**/publicclassDemo{publicstaticvoidmain(String[]args){整数计数=0;更新(计数);System.out.println("main方法中的计数:"+count);}privatestaticvoidupdate(intcount){count++;System.out.println("更新方法计数:"+count);}}输出结果:update方法中的count:1main方法中的count:0可以看到虽然update方法修改了形参count的值,但是main方法中的实参count的值并没有改变,但为什么没有改变呢?让我们深入研究基本原则。我们都知道Java基本数据类型是存放在虚拟机栈内存中的,栈帧是存放在栈中的。方法调用的过程就是栈帧入栈和出栈的过程。main方法执行时,向虚拟机栈中压入一个栈帧,栈帧中存储的局部变量信息count=0。执行update方法时,会向虚拟机栈中压入一个栈帧,栈帧中存储的局部变量信息count=0。修改更新栈帧中的数据显然不会影响main方法栈帧中的数据。3.2引用类型验证然后使用引用类型数据进行验证:/***@author一登架构*@apiNoteJava传输示例**/publicclassDemo{publicstaticvoidmain(String[]args){Useruser=new用户();用户.setId(0);更新(用户);System.out.println("main方法中的用户:"+user);}privatestaticvoidupdate(Useruser){user=newUser();用户.setId(1);System.out.println("更新方法中的用户:"+user);}}输出结果:userinupdatemethod:User(id=1)userinmainmethod:User(id=0)从代码得知,user对象在update方法中被重新初始化并重新赋值,不影响main方法中的实参数据。当main方法执行时,会在堆内存中开辟一块内存,将一个栈帧压入栈内存,栈帧中会存入一个引用,指向堆内存中的地址。当调用update方法时,会复制一份main方法的栈帧,然后压入栈内存,指向同一个堆内存地址。当更新方法被执行时,用户对象被重新初始化,值被重新赋值。它会在堆内存中开辟另一块内存,将栈内存中的更新栈帧指向新的堆内存地址,修改新堆内存中的数据。从这里可以看出,传了值,修改了形参中的数据,但是实参并没有相应的改变。3.3相同地址的引用类型验证/***@authorOneLightArchitecture*@apiNoteJava传输示例**/publicclassDemo{publicstaticvoidmain(String[]args){Useruser=newUser();用户。设置标识(0);更新(用户);System.out.println("main方法中的用户:"+user);}privatestaticvoidupdate(Useruser){user.setId(1);System.out.println("更新方法中的用户:"+user);}}输出结果:update方法中的user:User(id=1)main方法中的user:User(id=1)可以看出update方法修改了user对象的属性,main中的user对象方法也变了。这是否意味着Java支持通过引用传递?并不真地。这里,在传参的过程中,只是将实参的地址复制传给了形参。update方法中只修改了参数地址中的内容,并没有修改形参本身。4.总结经过以上分析,在Java参数传递中,无论是基本数据类型还是引用类型,都是值传递。在传递基本数据类型,如基本类型(int、long、char等)、包装类型(Integer、Long、String等)时,实参和形参存放在不同的栈帧中,栈形参的帧是修改后的数据,不影响实参的数据。当传递参数的引用类型、形参和实参指向同一个地址时,修改形参地址的内容会影响实参。当形参和实参指向不同的地址时,修改形参地址的内容不会影响实参。