JAVA中对象的赋值与引用

前言

最近在学习红黑树,当我尝试不使用递归来实现时,发现自己的大脑陷入了混乱。

究其原因,是对JAVA中的基本类型和引用类型有所误解。

特地重新搜索+实践一番,涨个姿势。

先放出我参考的文章:
@Intopass的知乎回答 java到底是值传递还是引用传递

@focusChen的博客 JAVA 对象引用,以及对象赋值

一番折腾

先找个对象过年

class Node {
        int value;
        Node left;
        Node right;
        Node(int value) {
            this.value = value;
        }
    }

对象赋值,引用还是复制值?

我出现的问题就在于弄混了下面的代码,没有理解清楚传值和传址。

        Node root;
        //初始化
        root = new Node(8);
        root.left = new Node(6);
        root.right = new Node(10);
        //我弄混的地方
        root = root.left;
        root.left = new Node(6);

经过初始化后,如图所示

LO1

然后我理解错误的地方出现了,就是这句

root = root.left;

我的理解出现了偏差,执行后,请看下图

LO2

为啥呢?

LO3

发现,new出来的对象被存的都是地址,而地址指向实际的对象。

也就是说,对象是引用类型。

再看对已有的对象用“=”赋值

LO4

现在,可以确认了,JAVA中对象赋值是传递地址的!

真·引用类型。

之前,我一直以为是传值。


如果将对象的地址想象成房号,变量root原本在463号。

root = root.left;

按我之前的理解,这行代码是告诉root把463号的物品都扔了。
再按照465号房间里的物品,买一份一模一样的放在463号。

实际呢

是告诉root,搬到465号去。
463号不再是它的房间了。

区别就在于

如果原本还住463号,只是复制的物品,那么它跟464号还是邻居,还可以互相串门。

但若搬到465号就不再与464号相邻,没办法串门到464号去,只能剩下465号一个房间。

小结

对对象使用“=”赋值,赋的是地址而不是值。

这么基础的问题,赤果果暴露了我的基础水平- -

还是某领导说得好啊,“实践是检验真理的唯一标准”。
仅仅听说是不够的,还需要亲身实践。

如果是方法之间的参数呢?

上面我们说到对象之间赋值,都是地址。

那么如果把对象当作参数传进方法里,也是传对象的地址吗?

答案是,是的。

不过此处有个坑,请看以下代码

public class TestObject {
    public static void main(String[] args) {
        TestObject o = new TestObject();
        int baseInt = 1;
        Integer objInt = 1;
        System.out.println("baseInt: " + baseInt);
        System.out.println("objInt: " + objInt);
        o.changeInt(baseInt);
        o.changeInteger(objInt);
        System.out.println("baseInt: " + baseInt);
        System.out.println("objInt: " + objInt);
    }

    public void changeInt(int baseInt) {
        baseInt = 3;
    }

    public void changeInteger(Integer objInt) {
        objInt = 3;
    }
}

结果:

baseInt: 1
objInt: 1

baseInt: 1
objInt: 1

不科学啊。如果传的是地址进去,为什么objInt没有改变呢!
跟说好的不一样是不是?
来看看到底发生了什么

LO5

可以看到objInt确实是引用类型的对象,其地址为@464。
再看看进入到方法时,地址是什么。

LO6

还是@464,说明的确按照地址传去的。

但是执行完赋值语句后

LO7

地址变成了@468。。

我的猜测

objInt = 3;

的操作是

objInt = new Integer(3);

由于new关键字导致objInt改变了引用,从@464变成了@468。
所以改的不是@464里的值。

执行完该方法后,回到主方法里,地址变回了@464,也就看到了结果没有发生改变。

那么只要不创建新对象,改变是会生效的。

请看如下代码:

public class TestObject {
    public static void main(String[] args) {
        TestObject o = new TestObject();
        int baseInt = 1;
        Integer objInt = 1;
        MyInt myInt = new MyInt(1);
        System.out.println("baseInt: " + baseInt);
        System.out.println("objInt: " + objInt);
        System.out.println("myInt: " + myInt.v);
        o.changeInt(baseInt);
        o.changeInteger(objInt);
        o.changeMyInt(myInt);
        System.out.println("改变后....");
        System.out.println("baseInt: " + baseInt);
        System.out.println("objInt: " + objInt);
        System.out.println("myInt: " + myInt.v);
    }

    public void changeInt(int baseInt) {
        baseInt = 3;
    }

    public void changeInteger(Integer objInt) {
        objInt = 3;
    }

    public void changeMyInt(MyInt myInt) {
        myInt.setV(3);
    }
}
class MyInt {
    int v;
    MyInt(int v) {
        this.v = v;
    }

    public void setV(int v) {
        this.v = v;
    }
}

结果:

baseInt: 1
objInt: 1
myInt: 1
改变后....
baseInt: 1
objInt: 1
myInt: 3

生效了。
说明传进方法里的参数,只要不用new创建新对象,引用的就是传进来的对象。

总结

对象之间使用=号进行赋值时,赋的是地址的值,拥有该地址的都是指向该地址对应的对象。
即多对一的关系。

如果用了new关键字,一定会有新对象产生,有新对象也肯定有新地址。

至于Integer这些包装类,我猜它们的=号就是new新对象,同时其没有提供对外的方法更改对象里的值,所以可以看作基本类型。

我算是明白了一丢丢,继续写红黑去- -

END

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值