Java中对象的赋值与引用

Java中对象的赋值与引用一直以来都理解的很模糊,所以打算写这篇博客理解透彻:

为了便于说明和理解,先定义一个简单的类:

public class Solution {

    private int a;
    private int b;

    public void setA(int a) {
        this.a = a;
    }
    public void setB(int b) {
        this.b = b;
    }
}

再讲对象的赋值与引用之前,我们先给出一个让很多人迷惑的现象:

     Solution s1 = new Solution();
     s1.setA(1);
     s1.setB(2);
     Solution s2 = s1;
     s2.setA(-1);

我们定义一个Solution类的对象s1,并给其成员变量赋值。然后再定义另一个对象s2,并令s2=s1,如果我现在令s2中的a=-1,现在s1和s2中的a的值会是多少呢?

这里写图片描述

这里写图片描述

很奇怪,为什么改变s2,s1也会改变呢?这就是对象的赋值与引用没理解透彻了,下面进入正题。

对于Solution s1 = new Solution();这条语句,这条语句执行的动作是创建一个对象,我们都很明白,但是它确包含了四个步骤:

  • 右边“new Solution”,表示以Solution类为模板,在堆空间中创建一个Solution类对象;
  • “()”,这对括号表示,在对象创建后,会立马调用Solution类的构造函数,由于没有给参数,所以会调用默认的无参构造。
  • 左边的“Solution s1 ”创建了一个Solution类的引用变量,也就是说用来指向Solution对象的对象引用。这和C语言中的指针可以理解为一个意思。
  • “=”,这个等号操作符表示使对象引用s1指向刚创建的Solution对象。

所以,这条语句包含了两个实体:一个是对象引用变量,一个是对象本身。

为了形象地说明对象、引用及它们之间的关系,可以做一个比喻:

A有一栋房子,他把地址告诉了B,B就知道了A家的地址,然后B又把A家的地址告诉了C。此时,B和C都知道了A家的地址,但是这栋房子确是属于A的。如果此时,B去A家拿了一个东西,然后C去了后会发现少了一样东西。所以B和C只是知道A家的地址,可以随时访问,但是确不是独有的。

所以,我们有以下结论:

从以上叙述再推演下去,我们可以获得以下结论:

(1)一个对象引用可以指向0个或1个对象(一个人可以知道房子的地址,也可以不知道);

(2)一个对象可以有N个引用指向它(可以有N个人知道房子的地址)。

Java对象和引用的关系可以说是互相关联,却又彼此独立。彼此独立主要表现在:引用是可以改变的,它可以指向别的对象。

从存储空间上来说,对象和引用也是独立的,它们存储在不同的地方,对象一般存储在堆中,而引用存储在速度更快的堆栈中。

引用可以指向不同的对象,对象也可以被多个引用操纵。如上面说的s1和s2都指向了同一个对象。既然两个引用指向同一个对象,那么不管使用哪个引用操纵对象,对象的内容都发生改变,并且只有一份,通过s1和s2得到的内容自然也一样。

再理解了对象和引用的关系后,再来看参数传递。Java只有一种参数传递方式:那就是按值传递,即Java中传递任何东西都是传值。如果传入方法的是基本类型的东西,你就得到此基本类型的一份拷贝。如果是传递引用,就得到引用的拷贝。:

同样,也举个例子:

package TempFile;

public class Solution {

    //基本类型的参数传递
    public static void fun1(int m){
        m = 100;
    }

    //参数为对象,不改变引用的值
    public static void fun2(StringBuffer s){
        s.append("fun2");
    }

    //参数为对象,改变引用的值
    public static void fun3(StringBuffer s){
        s = new StringBuffer("fun3");
    }

    public static void main(String[] args) {

        int i = 1;
        Solution s1 = new Solution(); 
        System.out.println(i);//i = 1
        StringBuffer ss = new StringBuffer("main");

        System.out.println(ss.toString());//main

        fun2(ss);

        System.out.println(ss.toString());//mainfun2

        fun3(ss);

        System.out.println(ss.toString());//mainfun2
    }
}

以上结果中,fun1方法的参数是基本类型,尽管在fun1中参数m的值发生了改变,但是并不影响m。

fun2方法的参数是一个对象,当把ss传给参数s时,s得到的是ss的拷贝,所以s和ss指向的是同一个对象,因此,使用s操作对象,ss也会受影响。

fun3方法的参数虽然也是一个对象,当ss传给参数s时,s得到的是ss的拷贝,但是,在fun3中改变了s指向的对象,给s重新赋值后,s与ss已经没有关系,它和ss指向了不同的对象,所以不管对s做什么操作,ss都不会受影响。

评论 14 您还未登录,请先 登录 后发表或查看评论

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

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页

打赏作者

yz930618

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值