一个小问题
在开源中国看到这样一则问题
https://www.oschina.net/question/2507499_2244027,个中的变量a前后的输出是什么?
我答错了,我认为传入function的就是main函数中的a,在function中修改了a的地点,因此回到主函数后,a的地点已经酿成了function中所赋予的a2的地点,因此颠末function处理惩罚后a的值已经改变了。 但功效并不是,因为我忽略了Java的基本常识点之一。
下文将从字节码的角度,阐明Java中根基范例传参和工具传参。
根基范例传参
以下是处理惩罚类Porcess,代码应该已经可以或许自表明白。function1是将传参a酿成2,function2是初始化int b,赋值为5,然后将b赋值给a。
public class Process { public void function3(int a) { a = 2; } public void function4(int a) { int b = 5; a = b; } }
我们继承看测试类TestPrimitive
public class TestPrimitive { public static void main(String[] args) { Process process = new Process(); int age = 18; System.out.println(age); process.function3(age); System.out.println(age); } }
功效是在颠末function3的处理惩罚后,输出功效是
18 18
修改测试类代码,在颠末function4处理惩罚后,仍然一致。
18 18
结论: 根基范例的传参,对传参举办修改,不影响原本参数的值。
工具范例传参
以下是处理惩罚类Porcess,function1,将参数car的颜色配置成blue。function2,新建了car2,将car2赋值给了参数car。
public class Process { public void function1(Car car) { car.setColor("blue"); } public void function2(Car car) { Car car2 = new Car("black"); car = car2; car.setColor("orange"); } }
我们继承看测试类TestReference
public class TestReference { public static void main(String[] args) { Process process = new Process(); Car car = new Car("red"); System.out.println(car); process.function1(car); System.out.println(car); } }
功效是在颠末function1的处理惩罚后,输出功效是
Car{color='red'} Car{color='blue'}
修改测试类,在颠末function2的处理惩罚后
Car{color='red'} Car{color='red'}
结论: 工具范例的传参,直接挪用传参set要领,可以对原本参数举办修改。假如修改传参的指向地点,挪用传参的set要领,无法对原本参数的值举办修改。
综上所述,根基范例的传参,软件开发,在要领内部是值拷贝,有一个新的局部变量获得这个值,对这个局部变量的修改不影响本来的参数。工具范例的传参,通报的是堆上的地点,在要领内部是有一个新的局部变量获得引用地点的拷贝,对该局部变量的操纵,影响的是同一块地点,因此原本的参数也会受影响,反之,若修改局部变量的引用地点,则不会对原本的参数发生任何大概的影响。
上文已经获得结论,我们从JVM的字节码的角度看一下进程是怎么样的。
首先大抵JVM的根基布局,对根基范例,和工具存放的位置有一个大抵的相识。下图是JVM的根基组件图。
先容几个根基的组件