公众号:jvm知识库
JAVA里面存在的是值传递还是引用传递,是不是对基本类型采取的是值引用,而对象(引用)类型采取的是引用传递?
首先需要先弄清楚什么是值传递,什么是引用传递???
值传递:将副本传递给方法,调用方法改变副本的值,但是并不改变原值
引用传递:传递的是对象的引用,对其修改,会改变原值。
Java中只存在值传递,不存在引用传递。
Java中方法参数的使用情况:
一个方法不能够修改基本数据类型的参数。
原因在于基本数据类型参数,比如main方法中的参数,是存储在自身的栈帧中的,当调用方法时,会相应的建立新的栈帧,拷贝传入的参数,调用方法所做的修改也只是针对拷贝后的参数进行的,当离开这个函数,方法栈帧被销毁,被修改的参数也会被销毁。回到main栈帧中,原来的变量并没有被修改。
一个方法可以修改对象类型的参数。
原因在于传入对象类型作为参数时,传入的对象的地址,子方法根据地址找到对象对子方法内的引用进行赋值,方法内通过子方法对对象可以进行修改。方法结束时,栈桢被销毁,而main方法的引用的地址还是传入是的对象(对象并未销毁,但是可以在子方法被修改)。
具体流转过程请参考下面的代码及注释,来展示。
基本类型传参及内部处理的具体过程。
/** * 基本类型传参过程 * 1.启动main函数,开辟内存栈空间。 * 2.在main函数内存栈空间定义变量(引用)“i” * 3.在main函数内存栈空间对“i”进行赋值100 * 3.1.从局部变量表查找是否有100,查找无100 * 3.2.创建100并赋值给“i”,将100放入到局部变量表中。 * 4.在main函数内存栈空间定义变量“u” * 5.在main函数内存栈空间对“u”进行赋值100 * 5.1.从局部变量查找存在100 * 5.2.将100赋值给u。此时“i”和“u”使用的局部变量表的同一个值100 * 6.将i的值100(对象)递给方法transParam方法,值传递,不影响main函数中i的值。 * * 7.创建新的内存栈空间。 * 8.在add函数内存栈空间创建变量a * 9.在add函数内存栈空间将传入的值100赋值给a。 * 注意:main方法的“i”和add方法的“a”是不同的变量(引用),占用不同的内存空间 (即使i和a命名一致也不影响) * 10.在add函数内存栈空间定义变量(引用)“b”. * 11.在add函数内存栈空间对“b”进行赋值5 * 11.1.在add函数内存栈空间局部变量表查找5,查找不存在5 * 11.2.创建5并赋值给a,将5放入到局部变量表中。 * 12.add函数打印出“add方法a的值为:5” * 13.add函数结束,对应的局部变量以及开辟的内存空间栈消失。 * 14.回到main函数,打印出“main函数i的值为:100” */ public static void main(String[] args) { int i = 100; int u = 100; add(i); System.out.println("main函数i的值为:" + i); } public static void add(int a) { int b = 10; a = 5; System.out.println("add方法a的值为:" + a); }
对象类型传参及内部处理的具体过程:
/** * 对象类型传参过程 * 1.启动main函数,开辟内存栈空间。 * 2.在main函数内存栈空间定义变量(引用)“user” * 3.在堆中创建新的User对象,假设对应的内存地址为“xxxxx1” * 3.在main函数内存栈空间对user赋值,指向的内存地址为“xxxxx1” * 4.在main函数对name和age进行赋值,会从局部变量表查找是否存在, 参考(基本类型传参过程方法内赋值) * 5.打印出“main函数调用change方法前:张三的年龄是50” * 6.将“user”应用对应的内存地址“xxxxx1”传递给change方法,传递的是引用指向的地址。 * * 7.创建新的内存栈空间。 * 8.在change函数内存栈空间创建变量(引用)“u” * 9.对“u”进行赋值,从内存中找到地址为“xxxxx1”的对象,赋值给“u”。 * 注意:main方法的“user”和change方法的“u”是不同的变量(引用), 占用不同的内存空间(即使i和a命名一致也不影响) * 10.在change函数对地址为"xxxxx1"的对象的age属性重新赋值为51。 * 13.change函数结束,但是地址为"xxxxx1"的张三的年龄老了一岁,但仍然还是张三那个人。 * 14.回到main函数,打印出“main函数调用change方法后:张三的年龄是51” */ public static void main(String[] args) { User user = new User(); user.name = "张三"; user.age = 50; System.out.println("main函数调用change方法前:" + user.name + "的年龄是" + user.age); change(user); System.out.println("main函数调用change方法后:" + user.name + "的年龄是" + user.age); } public static void change(User u) { u.age = 51; }
更底层的过程就留给jvm工程师吧,知道的太多了也不好(主要是菜)。