Java参数传递到底是值传递还是引用传递?

“Java的参数传递到底是值传递还是引用传递?”这个问题在网上一直有争论,很多人也是云里雾里摸不着头脑,查阅网上的资料时也是鱼龙混杂,让人感觉高深莫测。其实这个问题一点也不难,下面我们先抛开值传递、引用传递的概念角度,从参数传递的原理来对这个问题进行分析。

“拷贝”是Java参数传递的核心所在!只要搞清楚“拷贝”是如何在参数传递中发挥作用的,那么“值传递还是引用传递”这个问题将迎刃而解。

参数传递无非就是传递两种类型:基本类型和引用类型。首先来看基本类型:

  • 基本类型在传递时传递的是值的拷贝,在方法中改变的是值的拷贝,原值不会发生任何变化。如以下代码:

示例1:

public class ParameterTest1 {

    public void change(int i){
        i = 100;
    }

    public static void main(String[] args) {
        int i = 20;
        System.out.println("before change:"+i);
        ParameterTest1 pt1 = new ParameterTest1();
        pt1.change(i);
        System.out.println("after change:"+i);
    }

}

}

输出结果为:
这里写图片描述
通过输出结果,我们发现int类型i的值没有被改变,在方法中被改变的是基本类型值的拷贝。

  • 引用类型(也就是对象)在作为参数传递时传递的是对象所在内存地址的拷贝。看如下两个示例:

示例2:

public class ParameterTest2 {

    public void change(StringBuffer sb){
        sb.append(" luck");
    }

    public static void main(String[] args) {

        ParameterTest2 pt2 = new ParameterTest2();
        StringBuffer sb = new StringBuffer("good");
        System.out.println("before change:"+sb);
        pt2.change(sb);
        System.out.println("after change:"+sb);

    }

}

输出结果为:
这里写图片描述

示例3:

public class ParameterTest3 {

    public void change(StringBuffer sb){
        sb = new StringBuffer("great");
        sb.append(" luck");
    }

    public static void main(String[] args) {
        StringBuffer sb = new StringBuffer("good");
        System.out.println("before change:"+sb);
        ParameterTest3 pt3 = new ParameterTest3();
        pt3.change(sb);
        System.out.println("after change:"+sb);
    }
}

输出结果为:
这里写图片描述

通过以上两个示例,我们发现示例2中传入的对象被方法更改了,而示例3中传入的对象没有被方法更改,这是为什么呢?我们通过示意图来解析其中的原理:

首先来看示例2,我们一步步的进行分析:
①在main方法中首先执行StringBuffer sb = new StringBuffer("good") 这条语句,这时会产生一个sb字符串对象,并且sb的内容是“good”,也就是这个对象指向内存方法区中的字符串“good”。

这里写图片描述 0X11是假设对象所在的内存地址

②实例化ParameterTest2并且调用它的change()方法,编译器会拷贝一份sb对象的内存地址,将其传入方法中,拷贝的内存地址跟sb的内存地址完全相同,因此指向同一个字符串:

这里写图片描述sbCopy是传入方法中的对象内存地址的拷贝

③change()方法中使用了StringBuffer的append()方法对字符串进行了扩展,由于原对象跟其拷贝指向同一个字符串,所以当这个字符串改变时,sb的内容肯定改变。

这里写图片描述

所以示例2中的sb对象内容发生了改变。

接下来看示例3,也是一步步进行分析:
①跟示例2相同,首先执行了StringBuffer sb = new StringBuffer("good") ,产生一个sb字符串对象。

这里写图片描述

②实例化ParameterTest3并且调用它的change()方法,编译器拷贝一份sb对象的内存地址并将其传入方法中,在change()方法中执行sb = new StringBuffer("great"),sb内存地址拷贝重新new了一个StringBuffer对象,new会开辟一个新的内存空间,也就是说,sb内存地址拷贝指向了一个新的内存地址,如图所示:

这里写图片描述

③使用append()方法对字符串进行扩展:

这里写图片描述

由于sb的内存拷贝重新指向了一个新的内存地址,所以当append()扩展了字符串的时候不会对原对象sb造成任何影响,所以输出结果里sb的内容没有发生改变。

总结

那么问题来了,通过以上分析,Java参数传递到底是值传递还是引用传递?一般我们认为的引用传递是可以通过传引用参数来改变传入的参数的值(C++和C#就可以),而不会出现示例3的情况,归根到底,Java中传递的是拷贝,基本类型传递的是值的拷贝,引用类型传递的是内存地址的拷贝,当一个对象实例作为一个参数被传递到方法中时,参数的值就是对该对象的内存地址。所以Java的参数传递是值传递

部分参考自java参数传递(超经典)

相关推荐
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页