首页 技术 正文
技术 2022年11月9日
0 收藏 527 点赞 2,908 浏览 2920 个字
偶然想起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编程思想》中的一段话:

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

相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:9,492
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,907
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,740
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,495
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:8,132
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:5,295