欢迎访问昆山宝鼎软件有限公司网站! 设为首页 | 网站地图 | XML | RSS订阅 | 宝鼎邮箱 | 宝鼎售后问题提交 | 后台管理


新闻资讯

MENU

软件开发知识

Java 函数挪用是传值照旧传 劳务派遣信息管理系统 引用?从字节码角度来看看 !

点击: 次  来源:宝鼎软件 时间:2017-07-28

原文出处: 岑凯伦(微信公号 - 凯伦说,ID:KailunTalk)

一个小问题

在开源中国看到这样一则问题

https://www.oschina.net/question/2507499_2244027,个中的变量a前后的输出是什么?

我答错了,我认为传入function的就是main函数中的a,在function中修改了a的地点,因此回到主函数后,a的地点已经酿成了function中所赋予的a2的地点,因此颠末function处理惩罚后a的值已经改变了。 但功效并不是,因为我忽略了Java的基本常识点之一。

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的根基组件图。

Java 函数调用是传值还是传 劳务调派信息打点系统 引用?从字节码角度来看看 !

先容几个根基的组件

  1. 措施计数器: 存储每个线程下一步将执行的JVM指令。
  2. JVM栈(JVM Stack): JVM栈是线程私有的,每个线程建设的同时城市建设JVM栈,JVM栈中存放的为当前线程中局部根基范例的变量(java中界说的八种根基范例:boolean、char、byte、short、int、long、float、double)、部门的返回功效以及Stack Frame(每个要领城市开发一个本身的栈帧),非根基范例的工具在JVM栈上仅存放一个指向堆上的地点
  3. 堆(heap): JVM用来存储工具实例以及数组值的区域,可以认为Java中所有通过new建设的工具的内存都在此分派,Heap中的工具的内存需要期待GC举办接纳。
  4. 要领区(Method Area): 要领区域存放了所加载的类的信息(名称、修饰符等)、类中的静态变量、类中界说为final范例的常量、类中的Field信息、类中的要领信息,当开拓人员在措施中通过Class工具中的getName、isInterface等要领来获取信息时,这些数据都来历于要领区域。
  5. 当处所法栈(Native Method Stacks): JVM回收当处所法栈来支持native要领的执行,此区域用于存储每个native要领挪用的状态。
  6. 运行时常量池(Runtime Constant Pool): 存放的为类中的牢靠的常量信息、要领和Field的引用信息等,其空间从要领区域中分派。JVM在加载类时会为每个class分派一个独立的常量池,可是运行时常量池中的字符串常量池是全局共享的。