偶然想起Java中对象和引用的基本概念,为了加深下对此的理解和认识,特地整理一下相关的知识点,通过具体实例从两者的概念和区别两方面去更形象的认识理解,再去记忆。

一、对象和引用的概念: 
在Java中万物皆对象,比如我们定义一个简单的动物类:

class Animal {
String count;
String weight;
....
}

有了这个Animal类之后,我们可以来创建一个Animal对象:

Animal an = new Animal();

我们把编写这个语句的动作就称作创建一个对象,细化这个动作为: 
1. 右面的”new Animal”,是以Animal类为模板的,在堆空间里创建一个Animal对象; 
2. 末尾的”( )”代表着:在对象创建之后,立即调用Animal类的构造函数,对新生成的对象进行初始化。(如果没构造函数,Java会有一个默认的构造函数的); 
3. 左面的”Animal an” 创建了一个Animal类引用变量。即以后可以用来指向Animal对象的对象引用; 
4. “=” 操作符使对象引用指向刚才创建的那个Animal对象。 
拆分开也就是:等同于

Animal an;
an = new Animal();

有两个实体:一个是对象引用变量;一个是对象本身。 
在java中,都是通过引用来操纵对象的,这也是两者的区别。

二、对象和引用的区别: 
1、关联性: 
1). 当对象的引用变量指向对象时,两者就互相联系起来,改变引用的属性,就会改变对象的属性; 
2). 如果同一个对象被多个引用变量引用的话,则这些引用变量将共同影响这个对象本身; 
3). 在java中,都是通过引用来操纵对象的。

2、差异性: 
1). 一个对象可以被不同的引用变量来操纵,同时一个引用变量也可以指向不同的对象,但是同一时刻下只能指向一个对象。 
2). 从存储空间上来看,对象和引用也是相互独立的,对象一般存储在堆中,而引用存储在堆栈中(存储速度而更快)。

对于引用变量的深层含义,未必在初学的时候就能深刻理解, 
所以理解好下面这两句话的真正含义非常重要

Case cc=new Case();

Case cc;
cc=new Case();

1.先搞清楚什么是堆,什么是栈。 
Java开辟了两类存储区域,对比二者的特点

存储区域 存储内容 优点 缺点 回收
基本类型的变量和对象的引用变量 存取速度比堆要快,仅次于寄存器,栈数据可以共享 存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。栈中主要存放一些基本类型的变量 当超过变量的作用域后,Java会自动释放掉该变量,内存空间可以立即被另作他用
由new等指令创建的对象和数组 可以动态地分配内存大小,生存期也不必事先告诉编译器 由于要在运行时动态分配内存,存取速度较慢 由Java虚拟机的自动垃圾回收器来回收不再使用的数据

堆栈的存储特点决定了其中存储的数据类型。

注意,栈内存储的除了基本类型的变量(String, int 这种类型的变量)还会存储对象的引用变量。java中,引用变量实际上是一个指针,它指向的是堆内存中对象实例。

引用变量就相当于是为数组或对象起的一个名称,以后就可以在程序中使用栈中的引用变量来访问堆中的数组或对象。

2.给引用变量赋值

回过头再来看代码

实际上里面分解成了四个步骤。

Case cc; '''在栈内存里面开辟了空间给引用变量cc,这时cc=null'''
cc=new Case();
'''
1. new Case()在堆内存里面开辟了空间给Case类的对象,这个对象没有名字
2. Case()随即调用了Case类的构造函数
3. 把对象的地址在堆内存的地址给引用变量cc
'''

这样我们就明确了:

  • Java中,这里的“=”并不是赋值的意思,而是把对象的地址传递给变量;
  • 对象创建出来,其实连名字都没有,因此必须通过引用变量来对其进行操作。

为了形象地说明对象、引用及它们之间的关系,可以做一个或许不很妥当的比喻。对象好比是一只很大的气球,大到我们抓不住它。引用变量是一根绳, 可以用来系汽球

紧接着就会问,引用变量是怎么传递的呢? 
这就涉及到Java唯一的参数传递方式——按值传递

看下面一段代码:

public class ObjectRef {

    '''基本类型的参数传递'''
public static void testBasicType(int m) {
System.out.println("m=" + m);//m=50
m = 100;
System.out.println("m=" + m);//m=100
}
'''参数为对象,不改变引用的值'''
'''s即sMain指向的对象执行了append方法,在原来的字符串上加了段“_add”''' public static void add(StringBuffer s) {
s.append("_add");
} '''参数为对象,改变引用的值 '''
'''引用变量指向了一个新的对象,已经不是sMain指向的对象了'''
public static void changeRef(StringBuffer s) {
s = new StringBuffer("Java");
} public static void main(String[] args) {
int i = 50;
testBasicType(i);
System.out.println(i);'''i=50'''
StringBuffer sMain = new StringBuffer("init");
System.out.println("sMain=" + sMain.toString());'''sMain=init'''
add(sMain);
System.out.println("sMain=" + sMain.toString());'''sMain=init_add'''
changeRef(sMain);
System.out.println("sMain=" + sMain.toString());'''sMain=Java'''
}
}

看这里,给人的感觉是传递过来的明明是对象的引用,为什么就是值得传递呢? 
因为传递之前,被传的就是个引用啊,我们所谓的“传地址”,在传之前,那可是一个实例,传过来的是实例的地址。这里传递的值,从始至终就是个地址,sMain就是个地址,传给s还是个地址。你们感受下:

'''参数为对象,不改变引用的值'''
'''s即sMain,指向的对象执行了append方法,在原来的字符串上加了段“_add”'''
public static void add(StringBuffer s) {
s.append("_add");
}

以上输出的结果会是“init_add”

而这里,s引用了一个新的对象,根本没有进行参数的传递,它和之前的sMain没有关系了。

'''参数为对象,改变引用的值 '''
'''引用变量指向了一个新的对象,已经不是sMain指向的对象了'''
public static void changeRef(StringBuffer s) {
s = new StringBuffer("Java");
}

以上输出的结果会是“Java”

引用《Java编程思想》中的一段话:

倘若“将一个对象赋值给另一个对象”,实际是将“引用”从一个地方复制到另一个地方.

Java中对象和引用的理解的更多相关文章

  1. Java中对象与引用

    初学Java 时.在非常长一段时间里,总认为基本概念非常模糊. 后来才知道.在很多Java 书中.把对象和对象的引用混为一谈. 假设分不清对象与对象引用,那实在没法非常好地理解以下的面向对象技术.把自 ...

  2. 理解Java中的弱引用(Weak Reference)

    本篇文章尝试从What.Why.How这三个角度来探索Java中的弱引用,理解Java中弱引用的定义.基本使用场景和使用方法.由于个人水平有限,叙述中难免存在不准确或是不清晰的地方,希望大家可以指出, ...

  3. 详解Java中对象的软、弱和虚引用的区别

    对于大部分的对象而言,程序里会有一个引用变量来引用该对象,这是最常见的引用方法.除此之外,java.lang.ref包下还提供了3个类:SoftReference.WeakReference和Phan ...

  4. Java中对象、对象引用、堆、栈、值传递以及引用传递的详解

    Java中对象.对象引用.堆.栈.值传递以及引用传递的详解 1.对象和对象引用的差别: (1).对象: 万物皆对象.对象是类的实例. 在Java中new是用来在堆上创建对象用的. 一个对象能够被多个引 ...

  5. Java中四种引用:强、软、弱、虚引用

    这篇文章非常棒:http://alinazh.blog.51cto.com/5459270/1276173 Java中四种引用:强.软.弱.虚引用 1.1.强引用当我们使用new 这个关键字创建对象时 ...

  6. 浅谈对java中传参问题的理解

    之前用的c/c++比较多,在c/c++中对于传参类型,无外乎就是传值.传引用.传指针这几种.但在java中,由于没有指针类型,其传参的方式也发生了相应的变化.在网上找了找,按我之前的理解,java中传 ...

  7. java中容器的学习与理解

    以前一直对于java中容器的概念不理解,虽然学习过,但始终没有认真理解过,这几天老师提出了这样一个问题,你怎么理解java中的容器.瞬间就蒙了.于是各种搜资料学习了一下,下面是我学习后整理出来的的一些 ...

  8. 你真的了解JAVA中对象和类、this、super和static关键字吗

    作者:小牛呼噜噜 | https://xiaoniuhululu.com 计算机内功.JAVA底层.面试相关资料等更多精彩文章在公众号「小牛呼噜噜 」 目录 Java对象究竟是什么? 创建对象的过程 ...

  9. Java中对象的深复制和浅复制详解

    1.浅复制与深复制概念 ⑴浅复制(浅克隆) 被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象.换言之,浅复制仅仅复制所考虑的对象,而不复制它所引用的对象. ⑵ ...

随机推荐

  1. Codevs 1851 越狱 2008年湖南省队选拔赛

    1851 越狱 2008年湖南省队选拔赛 时间限制: 10 s 空间限制: 128000 KB 题目等级 : 大师 Master 题目描述 Description 监狱有连续编号为1-N的N个房间,每 ...

  2. C#重绘TabControl

    C#重绘TabControl的Tabpage标签,添加图片及关闭按钮 Code highlighting produced by Actipro CodeHighlighter (freeware)h ...

  3. 推荐系统系列(五):Deep Crossing理论与实践

    背景 特征工程是绕不开的话题,巧妙的特征组合也许能够为模型带来质的提升.但同时,特征工程耗费的资源也是相当可观的,对于后期模型特征的维护.模型线上部署不太友好.2016年,微软提出Deep Cross ...

  4. Hbase底层解析

    hfile+compaction 原理 ​ 用户数据写入先写WAL,再写缓存,满足一定条件后缓存数据会执行flush操作真正落盘,形成一个数据文件HFile.太多数据文件会导致数据查询IO次数增多,因 ...

  5. svn 同步hook

    hook 目录下 cp pre-revprop-change.tmpl pre-revprop-change chmod a+x pre-revprop-change 同步代码初始化 sudo svn ...

  6. DAY 6考试

    题解: 这题太水辣 注意开 long long 但我不是没开long long 的锅 我是 输出 long long 要用 lld 啊 大梦身先醒,80可海星 PS:百度了一下 long (ld) 和 ...

  7. ambari部署Hadoop集群(1)

    本例使用hortonworks 提供了 ambari 的安装方法,而且还很详细.以下是在 centos7 上的安装步骤. 基础配置: 1. 修改电脑的主机名 hostnamectl set-hostn ...

  8. linux系统交互通道

    默认有6个命令交互通道和一个图形界面交互通道,默认进入到的是图形界面通道     命令交互模式切换:ctrl+alt+f1---f6     图形交互界面 ctrl+alt+f7 1.图形界面交互模式 ...

  9. ButterKnifer使用

    ButterKnifer使用 1.集成 github地址: https://github.com/JakeWharton/butterknife 1.1在主Moduel中的使用 在主moduel中的b ...

  10. ubuntu下wps的安装

    (一)安装 1)下载:WPS For Linux http://community.wps.cn/download/ 下载wps-office_10.1.0.5672~a21_amd64.deb 2) ...