美文网首页Java · 成长之路javaJava杂谈
[Java] 有趣的小问题-Java方法传参浅析

[Java] 有趣的小问题-Java方法传参浅析

作者: 凯伦说 | 来源:发表于2017-06-05 22:05 被阅读76次

    一个小问题

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

    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;
        }
    }
    

    我们继续看测试类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的基本组件图。

    个人介绍.jpg

    相关文章

      网友评论

      本文标题:[Java] 有趣的小问题-Java方法传参浅析

      本文链接:https://www.haomeiwen.com/subject/wvpwfxtx.html