Java中对象和引用的理解
偶然想起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中对象和引用的理解的更多相关文章
- Java中对象与引用
初学Java 时.在非常长一段时间里,总认为基本概念非常模糊. 后来才知道.在很多Java 书中.把对象和对象的引用混为一谈. 假设分不清对象与对象引用,那实在没法非常好地理解以下的面向对象技术.把自 ...
- 理解Java中的弱引用(Weak Reference)
本篇文章尝试从What.Why.How这三个角度来探索Java中的弱引用,理解Java中弱引用的定义.基本使用场景和使用方法.由于个人水平有限,叙述中难免存在不准确或是不清晰的地方,希望大家可以指出, ...
- 详解Java中对象的软、弱和虚引用的区别
对于大部分的对象而言,程序里会有一个引用变量来引用该对象,这是最常见的引用方法.除此之外,java.lang.ref包下还提供了3个类:SoftReference.WeakReference和Phan ...
- Java中对象、对象引用、堆、栈、值传递以及引用传递的详解
Java中对象.对象引用.堆.栈.值传递以及引用传递的详解 1.对象和对象引用的差别: (1).对象: 万物皆对象.对象是类的实例. 在Java中new是用来在堆上创建对象用的. 一个对象能够被多个引 ...
- Java中四种引用:强、软、弱、虚引用
这篇文章非常棒:http://alinazh.blog.51cto.com/5459270/1276173 Java中四种引用:强.软.弱.虚引用 1.1.强引用当我们使用new 这个关键字创建对象时 ...
- 浅谈对java中传参问题的理解
之前用的c/c++比较多,在c/c++中对于传参类型,无外乎就是传值.传引用.传指针这几种.但在java中,由于没有指针类型,其传参的方式也发生了相应的变化.在网上找了找,按我之前的理解,java中传 ...
- java中容器的学习与理解
以前一直对于java中容器的概念不理解,虽然学习过,但始终没有认真理解过,这几天老师提出了这样一个问题,你怎么理解java中的容器.瞬间就蒙了.于是各种搜资料学习了一下,下面是我学习后整理出来的的一些 ...
- 你真的了解JAVA中对象和类、this、super和static关键字吗
作者:小牛呼噜噜 | https://xiaoniuhululu.com 计算机内功.JAVA底层.面试相关资料等更多精彩文章在公众号「小牛呼噜噜 」 目录 Java对象究竟是什么? 创建对象的过程 ...
- Java中对象的深复制和浅复制详解
1.浅复制与深复制概念 ⑴浅复制(浅克隆) 被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象.换言之,浅复制仅仅复制所考虑的对象,而不复制它所引用的对象. ⑵ ...
随机推荐
- POJ - 3162 Walking Race 树形dp 单调队列
POJ - 3162Walking Race 题目大意:有n个训练点,第i天就选择第i个训练点为起点跑到最远距离的点,然后连续的几天里如果最远距离的最大值和最小值的差距不超过m就可以作为观测区间,问这 ...
- Codevs 1200 同余方程 2012年NOIP全国联赛提高组
1200 同余方程 2012年NOIP全国联赛提高组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description 求关于 x 同余方程 a ...
- 7.9T2EASY(easy)
EASY(easy) sol:非常经典的题,取了一次之后,把线段树上这一段变成相反数 然后再贪心取和最大的. 重复以上操作,发现最后一定有对应的解,且根据贪心过程一定 是最大的 线段树上维护区间和最大 ...
- 关于MapReduce的测试
题目:数据清洗以及结果展示 要求: Result文件数据说明: Ip:106.39.41.166,(城市) Date:10/Nov/2016:00:01:02 +0800,(日期) Day:10,(天 ...
- Laydate 使用注意事项
1.laydate 切记不能放在laytpl 模板语法中使用,否则可能会导致无法触发的情况 不在laytpl中使用 <div class="layui-form-item"& ...
- Jmeter -- 脚本录制
步骤如下: 1. 添加http代理服务器(Add -> Non-TestElement -> HTTP(S)Test Script Recorder) 2. 对http代理进行配置,如下图 ...
- [CSP-S模拟测试]:慢无止境的八月(乱搞)
题目传送门(内部题102) 输入格式 第一行三个正整数$n,k,q$,分别表示数列长度,操作长度和修改个数. 第二行$n$个数,表示给出的终止数列. 接下来$q$行,每行两个数$pos,dx$,表示将 ...
- Caused by: java.lang.IllegalStateException: Unable to complete the scan for annotations for web application [/Cppcc] due to a StackOverflowError. Possible root causes include a too low setting for -Xs
解决办法:(1)修改D:\Java\apache-tomcat-7.0.88\conf\catalina.properties (122line) (2)如org.apache.catalina.st ...
- State Threads之Co-routine的调度
1. 相关结构体 1.1 _st_epoll_data static struct _st_epolldata { _epoll_fd_data_t *fd_data; /* 调用 epoll_wai ...
- 使用redis时遇到的问题及解决方法
最近在向redis中写入数据的时候,报了下面的错误: failed opening the rdb file crontab (in server root dir /etc) for saving ...