Java是值传递还是引用传递?区别是什么? - Java技术债务


在Java中参数的传递主要有两种:值传递引用传递

值传递

实参传递给形参的是值

形参和实参在内存上是两个独立的变量

对形参做任何修改不会影响实参

也就是说:在方法调用时,传入方法内部的是实参引用的拷贝,因此对形参的任何操作都不会影响到实参。

public class Main {
        public static void main(String[] args) {
            int b =20;
						// 实参  实际上的参数
            change(b);
            System.out.println(b);
        }
        public static void change(int a){//形参  形式上的参数
            a = 100;
        }
}

结果:20

Java是值传递还是引用传递?区别是什么? - Java技术债务

形参只是实参创建的一个副本,副本改变了,原本当然不可能跟着改变;

引用传递

实参传递给形参的是参数对于堆内存上的引用地址

实参和形参在内存上指向了同一块区域

对形参的修改会影响实参

public class Main {
    public static void main(String[] args) {
        List list1 = new ArrayList<>();
        list1.add(2);
        list1.add(3);
        list1.add(4);
        list1.add(5);
        System.out.println(list1);
        change(list1);
        System.out.println(list1);
    }

    public static void change(List list2) {
        list2.add(6);
    }
}

结果: [2, 3, 4, 5] [2, 3, 4, 5, 6]

可以在IDEA上debug以下,如图:

Java是值传递还是引用传递?区别是什么? - Java技术债务

Java是值传递还是引用传递?区别是什么? - Java技术债务

从debug的结果可以看出,创建出来的list1的对象ID是484,list2的对象ID也是484,传过去的参数其实是list1的对象ID**。**

Java是值传递还是引用传递?区别是什么? - Java技术债务

由于引用传递,传递的是地址,方法改变的都是同一个地址中的值。

原来list1指向0xxx地址,有4个数字,后来在change方法对0xxx地址添加了一个数字,变成了5个数字,地址都是指向同一块内存。

两者区别

  • 值传递是对基本型变量而言的,传递的是该变量的一个副本,改变副本不影响原变量.
  • 引用传递一般是对于对象型变量而言的,传递的是该对象地址的一个副本, 并不是原对象本身 。 所以对引用对象进行操作会同时改变原对象.

Java到底是值传递还是引用传递

在Java方法中参数列表有两种类型的参数,基本类型和引用类型。

  • **基本类型:**值存放在局部变量表中,无论如何修改只会修改当前栈帧的值,方法执行结束对方法外不会做任何改变;此时需要改变外层的变量,必须返回主动赋值。
  • **引用数据类型:**指针存放在局部变量表中,调用方法的时候,副本引用压栈,赋值仅改变副本的引用。但是如果通过操作副本引用的值,修改了引用地址的对象,此时方法以外的引用此地址对象当然被修改。(两个引用,同一个地址,任何修改行为2个引用同时生效)。

这两种类型都是将外面的参数变量拷贝一份到局部变量中,基本类型为值拷贝,引用类型就是将引用地址拷贝一份。

网上众说纷纭,说什么的都有,但是我倾向于Java的传递是值传递

如果传的时基本数据类型,只改变传递的副本不会改变原变量;如果传递的时对象类型,传递的变量是对象类型的地址,修改此地址指向的对象值 = 直接去对地址指向的对象,但是不会修改原对象的引用

比如:交换两个对象

public class Main {
 
    public static void swapObjectReference(ParamObject object1, ParamObject object2) {
        ParamObject temp = object1;
        object1 = object2;
        object2 = temp;
    }
 
    public static void main(String[] args) {
        ParamObject a = new ParamObject(true, 1);
        ParamObject b = new ParamObject(false, 2);
        System.out.println("a : " + a + " b : " + b);
        swapObjectReference(a, b);
        System.out.println("a : " + a + " b : " + b);
    }
}

结果:

a : ParamObject{flg=true, num=1} b : ParamObject{flg=false, num=2}

a : ParamObject{flg=true, num=1} b : ParamObject{flg=false, num=2}

有了上面的知识之后,我们会发现这个方法中的引用地址交换,只不过是一个把戏而已,只是对方法中的两个局部变量的对象引用值进行了交换,不会对原变量引用产生任何影响的。

Java是值传递还是引用传递?区别是什么? - Java技术债务

当然,完全说Java是值传递也不是严谨的,毕竟值传递的概念是:在方法调用时,传入方法内部的是实参引用的拷贝,因此对形参的任何操作都不会影响到实参。但是Java中有引用类型也就是包装类型的对象传递,传递其实是地址,在方法中修改形参会影响到实参的,因为形参和实参指向堆中同一块内存。

可以借鉴之前看到的一个解释:

java 使用的是一种名为值传递的求值策略,这种策略在传值过程中会复制实参的引用,并将这份拷贝传入到方法形参中,所以对形参的任何重赋值操作都不会对实参产生影响。

   登录后才可以发表评论呦...

专注分享Java技术干货,包括
但不仅限于多线程、JVM、Spring Boot
Spring Cloud、 Redis、微服务、
消息队列、Git、面试题 最新动态等。

想交个朋友吗
那就快扫下面吧


微信

Java技术债务

你还可以关注我的公众号

会分享一些干货或者好文章

Java技术债务