聊聊 Java 中参数传递的原理~

220 篇文章 1 订阅
43 篇文章 2 订阅

今天,想和大家聊聊关于java中的参数传递的原理,参数的传递有两种,值传递和引用传递。

值传递:是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。

引用传递:是指在调用函数时将实际参数的地址传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。

基本类型传递

先来看看下面这段最基本的代码:

@Test
public void test() {
    int n = 10;
    test01(n);
    System.out.println("最终结果n==" + n);
}

private void test01(int m) {
    System.out.println("修改之前m==" + m);
    m = 20;
    System.out.println("修改之后m==" + m);
}
复制代码

输出结果:

修改之前m==10
修改之后m==20
最终结果n==10
复制代码

如果跟你预期的不同,那我想你还是没有理解参数的值传递与引用传递的原理。

结合生活中的场景,深入理解一下值传递和引用传递:

你有一把钥匙,当你的朋友想要去你家的时候,如果你直接把你的钥匙给他了,这就是引用传递。这种情况下,如果他对这把钥匙做了什么事情,比如他在钥匙上刻下了自己名字,那么这把钥匙还给你的时候,你自己的钥匙上也会多出他刻的名字。

你有一把钥匙,当你的朋友想要去你家的时候,你复刻了一把新钥匙给他,自己的还在自己手里,这就是值传递。这种情况下,他对这把钥匙做什么都不会影响你手里的这把钥匙。

下面我们来画图更好的理解上述代码的例子:

image-20211128174051399

当发生函数调用的时候 n 将自己传入到 test01 方法中,同时将自己的值复制了一份并赋值给了一个新变量 m 从图中可以看出这是 nm 两个变量没有一毛钱关系(m只是n的复制品),所以对 m 的修改并不会影响到 n

如果想要改变n的值,可以使用方法的返回值:

n = test01(n);
复制代码

引用类型传递

下面来看看引用类型的传递:

public class Dog {

    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Dog(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Dog{" +
                "name='" + name + '\'' +
                '}';
    }
}


@Test
public void test() {
    Dog dog1 = new Dog("小白");
    test01(dog1);
    System.out.println("最终结果dog==" + dog1);
}

private void test01(Dog dog) {
    System.out.println("修改之前 dog==" + dog);
    dog.setName("小黑");
    System.out.println("修改之后 dog==" + dog);
}
复制代码

输出结果:

修改之前 dog==Dog{name='小白'}
修改之后 dog==Dog{name='小黑'}
最终结果dog1==Dog{name='小黑'}
复制代码

为了方便大家理解,还是画图来分析一下:

image-20211128171133053

test 方法中我们创建了一个 dog1 的对象,该对象存放于堆内存中,假设内存地址为 0x1120 ,于是 dog1 这个变量便应用了这块内存地址。

当我们调用 test01 这个方法的时候会在该方法栈中创建一个变量 dog ,这个 dog 变量是由原本的入参 dog1 复制而来,所以它所对应的堆内存依然是 0x1120

所以当我们通过 dog 这个变量修改了数据后,本质上修改的是同一块堆内存中的数据。从而原本引用了这块内存地址的 dog1 也能查看到对应的变化。

如果不理解上面的话,那么记住下面的两句话就行了:

传递引用类型的数据时,传递的并不是引用本身,依然是值;只是这个值是内存地址罢了。

因为把相同的内存地址传过去了,所以对数据的操作依然会影响到外部。

那我们继续看看下面的代码,这种情况能否改变参数的值

@Test
public void test() {
    Dog dog1 = new Dog("小白");
    test01(dog1);
    System.out.println("最终结果dog1==" + dog1);
}

private void test01(Dog dog) {
    System.out.println("修改之前 dog==" + dog);
    dog = new Dog("小黑");
    System.out.println("修改之后 dog==" + dog);
}
复制代码

输出结果:

修改之前 dog==Dog{name='小白'}
修改之后 dog==Dog{name='小黑'}
最终结果dog1==Dog{name='小白'}
复制代码

假设 Java 是引用传递那最终的结果应该是打印 小黑 才对,从结果看这里依然是值传递。

还是画图来分析一下:

image-20211128172501300

如果是引用传递,原本的 0x1120 应该是被直接替换为新创建的 0x1121 才对;而实际情况如上图所示,dog 直接重新引用了一个对象dog = new Dog("小黑"),两个对象之间互不干扰。

小结

Java中参数传递其实还是值传递的,只不过对于引用类型参数,值的内容是对象的引用。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值