Java中只有值传递?一篇文章彻底弄懂

新手上路,记录自己的理解。
在C++中,函数传值有两种方式,即值传递和引用传递。而在Java中,只有值传递,即便传递的对象为引用类型(如String)。所谓的值传递是指在调用函数时将实参复制一份传递到函数中,这样函数中操作的是实参的副本,不会对实参造成修改;所谓的引用传递是指在调用函数时将实参的地址传递到函数中,这样函数中操作的是实参对象,函数内部的修改会影响到实参。
由此可见,值传递与引用传递的本质区别是:值传递会产生一个副本,而引用传递不会。因此,值传递才不会改变原实参的值,而引用传递会。
下面以三个例子(基本数据类型、字符串、类)进行阐述:

//基本数据类型
public static void main(String[] args)
{
    int a = 1;
    System.out.println("调用函数前a的值为:" + a);
    System.out.println("a的内存地址为:" + System.identityHashCode(a));
    fun(a);
    System.out.println("调用函数后a的值为:" + a);
}

public static void fun(int b)
{
    b = 2;
    System.out.println("b的内存地址为:" + System.identityHashCode(b));
}
调用函数前a的值为:1
a的内存地址为:1989780873
b的内存地址为:1480010240
调用函数后a的值为:1
/引用类型:字符串
public static void main(String[] args)
{
    String a = "河图";
    System.out.println("调用函数前a的值为:" + a);
    System.out.println("a的内存地址为:" + System.identityHashCode(a));
    fun(a);
    System.out.println("调用函数后a的值为:" + a);
}

public static void fun(String b)
{
    b = "洛书";
    System.out.println("b的内存地址为:" + System.identityHashCode(b));
}
调用函数前a的值为:河图
a的内存地址为:1078694789
b的内存地址为:81628611
调用函数后a的值为:河图
public class Practice
{
    //引用类型:类和对象
    public static void main(String[] args)
    {
        Person a = new Person();
        a.age = 18;
        System.out.println("调用函数前a的值为:" + a.age);
        System.out.println("a的内存地址为:" + System.identityHashCode(a));
        System.out.println("a属性的内存地址为:" + System.identityHashCode(a.age));
        fun(a);
        System.out.println("调用函数后a的值为:" + a.age);
    }

    public static void fun(Person b)
    {
        b.age = 0;
        System.out.println("b的内存地址为:" + System.identityHashCode(b));
        System.out.println("b属性的内存地址为:" + System.identityHashCode(b.age));
    }
}

class Person
{
    int age;
}
调用函数前a的值为:18
a的内存地址为:1480010240
a属性的内存地址为:81628611
b的内存地址为:1480010240
b属性的内存地址为:1828972342
调用函数后a的值为:0

对基本数据类型而言,其值存在栈中。参数传递时,形参从栈上复制实参的值,但本身已是两个对象,因此不改变实参值。
在这里插入图片描述
对引用类型(字符串)而言,其引用存在栈中,其值存在堆中。形参从栈上复制其引用,因此可以访问到堆上的值。而函数中b变更了引用,此时b指向堆中另一片内存,无法访问实参引用所指向堆中的值,但不影响实参值。
在这里插入图片描述
在这里插入图片描述
对引用类型(类)而言,其引用存在栈中,其值存在堆中。形参从栈上复制其引用,因此可以访问到堆上的值。函数中b变更了属性的值,但并未变更其引用,因此b仍然可以访问到实参引用所指向堆中的值。而栈中的值不可更改,堆中的值可以更改,因此最终属性age的值被更改。
在这里插入图片描述
在这里插入图片描述
我们可以稍微更改下代码:

public class Practice
{
    //引用类型:类和对象
    public static void main(String[] args)
    {
        Person a = new Person();
        a.age = 18;
        System.out.println("调用函数前a的值为:" + a.age);
        System.out.println("a的内存地址为:" + System.identityHashCode(a));
        System.out.println("a属性的内存地址为:" + System.identityHashCode(a.age));
        fun(a);
        System.out.println("调用函数后a的值为:" + a.age);
    }

    public static void fun(Person b)
    {
        b = new Person();//在这里更改b自身的引用
        b.age = 0;
        System.out.println("b的内存地址为:" + System.identityHashCode(b));
        System.out.println("b属性的内存地址为:" + System.identityHashCode(b.age));
    }
}

class Person
{
    int age;
}
调用函数前a的值为:18
a的内存地址为:1480010240
a属性的内存地址为:81628611
b的内存地址为:1828972342
b属性的内存地址为:1452126962
调用函数后a的值为:18

显而易见,a与b的地址不同了,此时在b中改变属性不会再影响到a。
所以,Java中只有值传递。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值