面向对象语言中值传递和引用传递(以JAVA为例)

摘要/Abstract

参数传递有两种形式:值传递(Pass By Value)和引用传递(Pass By Reference)。一般而言,基本数据类型是值传递,对象数据类型是引用传递。而有的时候,我们需要对象的“值传递”,实现方法之一是重写Object的clone()方法。

1.值传递

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

代码示例1-1:

    public static void main(String[] args) {
        int n = 1;
        change(n);
        System.out.println(n);
    }
    
    public static void change(int n) {
        n = 123;
    }
    // output:
    // 1

2.引用传递

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

代码示例2-1:

    public static void main(String[] args) {
        A a = new A(1);
        change(a);
        System.out.println(a.getN());
    }

    public static void change(A a) {
        a.setN(123);
    }

    static class A {
        private int n;
        
        A() {
        }

        A(int n) {
            this.n = n;
        }

        public int getN() {
            return this.n;
        }

        public void setN(int newN) {
            this.n = newN;
        }
    }
    // output:
    // 123

另外,我们写代码时经常会用到赋值,即把一个变量用等号(“=”)赋值给另一个变量。对于基本数据类型,赋值后的两个变量除了数值上相等,其他毫无关联,而对于对象变量,等号的赋值仅仅是把一个对象指针指向另一个变量名,实际只存在一个对象,如果你修改其中的一个变量,也会“影响”另外一个变量。

将代码示例2-1中main函数修改成如下,其他不变。
代码示例2-2:

public static void main(String[] args) {
        A a = new A(1);
        A newa = a;
        change(newa);
        System.out.println(a.getN());
        System.out.println(newa.getN());
    }
    // output:
    // 123
    // 123

3.实现对象的值传递

重写Object的clone()方法。需要注意的是,重写方法后,类还需要实现Cloneable接口,不然会报错。

代码示例3-1:

    public static void main(String[] args) throws CloneNotSupportedException {
        A a = new A(1);
        A newa = (A) a.clone();
        change(newa);
        System.out.println(a.getN());
        System.out.println(newa.getN());
    }

    public static void change(A a) {
        a.setN(123);
    }

    static class A implements Cloneable{
        private int n;
        
        A() {
        }

        A(int n) {
            this.n = n;
        }

        public int getN() {
            return this.n;
        }

        public void setN(int newN) {
            this.n = newN;
        }

        @Override
        protected Object clone() throws CloneNotSupportedException {
            return super.clone();
        }
		// output:
		// 1
		// 123

看到这里,你可能觉得上述例子已经实现了对象的值传递,但实际上还没有,当对象的属性是另外一种对象时,又回到了“起点”。

代码示例3-2:

    public static void main(String[] args) throws CloneNotSupportedException {
        B b = new B(1);
        A a = new A(b);
        A newa = (A) a.clone();
        change(newa);
        System.out.println(a.getN().getBN());
        System.out.println(newa.getN().getBN());
    }

    public static void change(A a) {
        a.getN().setBN(123);
    }

    static class A implements Cloneable{
        private B n;

        A() {
        }

        A(B n) {
            this.n = n;
        }

        public B getN() {
            return this.n;
        }

        public void setN(B newN) {
            this.n = newN;
        }

        @Override
        protected Object clone() throws CloneNotSupportedException {
            return super.clone();
        }
    }

    static class B {
        private int n;

        B() {
        }

        B(int n) {
            this.n = n;
        }

        public int getBN() {
            return this.n;
        }

        public void setBN(int newN) {
            this.n = newN;
        }
    }
    // output:
    // 123
    // 123

对象的对象也需要重写clone()方法,并且在对象中显式地调用属性的clone()。如果仅仅是上述例子,只有一层,改写也比较方便。但请试想如果出现“套娃”,那么,每有一层就需要重写一次clone()方法,这代码相当麻烦。更多关于clone()方法的内容可以查看[3]。

参考文献/References

[1] https://baike.baidu.com/item/%E5%80%BC%E4%BC%A0%E9%80%92/13009399?fr=aladdin
[2] https://baike.baidu.com/item/%E5%BC%95%E7%94%A8%E4%BC%A0%E9%80%92/2880658?fr=aladdin
[3] https://blog.csdn.net/qq_33314107/article/details/80271963

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值