java是值传递还是引用传递?

java是值传递还是引用传递?

java到底是值传递(Pass by value)还是引用传递(Pass by reference),被这个问题困扰了很久,一直也没有去深入了解问题的本质。最近看了一篇文章后觉得理解又加深了一点。但还是存在一些疑惑,于是继续深究下去。

1、为什么会有这样的困惑?

首先,为什么会产生这样的疑惑呢?下面就用例子来说明一下疑惑的是如何产生的。我们知道java数据类型分为基本类型(Primitive Types)和引用类型(Reference Types)两种,对于这两种类型我们分开讨论。

1.1 基本类型

对于基本类型的参数传递,我想以下的代码运行结果都比较清楚。

/**
* Created by andy on 2016/12/10.
*/
public class PassByValueOfPrimitive {
    public static void main(String[] args) {
        int num = 1;
        System.out.println("调用change()方法前 : num = " + num);
        change(num);
        System.out.println("调用change()方法后 : num = " + num);
    }

    private static void change(int arg) {
        arg = 2;
        System.out.println("在change()方法内部参数  : arg = " + arg);
    }
}

运行结果:

调用change()方法前 : num = 1
在change()方法内部参数  : arg = 2
调用change()方法后 : num = 1  

我们看到num的值在调用前后并没有发生改变,对于基本类型的参数传递还是比较好理解。接下来看一下引用类型的参数是如何传递的。

1.2 引用类型

首先分析以下代码的运行结果,然后再看后面的答案。

/**
 * Created by andy on 2016/12/10.
 */
public class PassByValueOfReference {
    public static void main(String[] args) {
        Dog d = new Dog();
        d.setName("旺财");
        System.out.println("调用change()方法前 : d.name = " + d.getName());
        change(d);
        System.out.println("调用change()方法后 : d.name = " + d.getName());
    }

    private static void change(Dog dog) {
        dog.setName("小强");
        System.out.println("在change()方法内部参数 : d.name = " + dog.getName());
    }

    public static class Dog {
        private String name;

        public String getName() {
            return name;
        }

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

运行结果:

调用change()方法前 : d.name = 旺财
在change()方法内部参数 : d.name = 小强
调用change()方法后 : d.name = 小强  

怎么回事?“旺财”咋变成“小强”了呢?为什么和基本类型的结果不同呢?正是这个结果困扰了我好久,百思不得其解。保留疑问,继续往下看>>>

2、求解的过程

在查找原因的过程中,逐渐发现我对一些概念的理解不到位。那么我们就先要清楚以下几组概念,然后再做分析。

2.1 值和引用

指的是变量存储的数据。
引用指的是数据在内存中的地址 。

2.2 值传递(Pass by value)VS 引用传递(Pass by reference

值传递:将实参的值拷贝传递给形参,无论在方法内怎么改变形参的值(因为形参是局部变量),实参的值是不会改变的。
引用传递:将实参在内存中的地址拷贝传递给形参。形参相当于是实参的“别名”,对形参的操作其实就是对实参的操作,在引用传递过程中,被调函数的形式参数虽然也作为局部变量在栈中开辟了内存空间,但是这时存放的是由主调函数放进来的实参变量的地址。被调函数对形参的任何操作都被处理成间接寻址,即通过栈中存放的地址访问主调函数中的实参变量。正因为如此,被调函数对形参做的任何操作都影响了主调函数中的实参变量。

2.3 java中的变量和值

java虚拟机规定了两种变量类型即:基本类型Primitive Types)和引用类型Reference Types),与此对应java有两种值类型即:基本值Primitive Values)和引用值Reference Values)。

2.4 原因分析

明白以上概念后,我们来分析一下java中传递引用类型的参数时为什么会发生1.2那样的结果。首先java的引用类型变量存放的是对象的引用地址,即此时变量保存的就是对象的引用地址。将引用类型变量作为参数传递时,由值传递的概念可知其实是将对象的地址传递给了形参,即形参和实参保存的是同一个对象的地址。这样对形参做的任何改变也会反应到实参所指向的对象。到这里也就解释了1.2的结果是如何产生的。

3、结论

经过以上的分析可以确定java确实是值传递。只是java传递引用类型的参数时变量中保存的就是对象的引用地址,这确实困扰了很多人,因为这些引用也是按照值传递的。

在比较或分析问题的时候首先要弄清楚概念然后再往下进行。因为概念给出了对应名词的限定和使用范围,只有在弄清概念的基础上才能深入分析了解问题的本质。而不是根据自己的理解和猜测去从字面上理解,这样只会让自己越来越迷惑。

参考

1、java参数传递(值传递还是引用传递)
2、Java String对象以“引用”方式被传递
3、C++ 值传递、指针传递、引用传递详解

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值