简单谈谈java里的引用类型

  在java学习中,大家往往会发现,虽然在c里已经见识过结构体的威力,但在java这样的面向对象的语言中却有着种类更加丰富,更加更加强大,甚至还支持自定义的新型数据类型。这就是引用类型,今天来和大家简单谈一谈java里出现的引用类型。


 

1.名词定义

  首先,c中的基本类型也能在java中找到,它们分别是:

boolean
char
byte
short
int
long
float
double

而引用类型,就是那些可以通过 new 来创建对象的类型,引用类型指向一个对象,不是原始值,而指向对象的变量就叫做引用变量。其实,引用类型的变量的内核概念非常类似于 C/C++ 的指针。为了形象起见,也为了打字方便,本文后面的内容,都把“引用类型的变量”称为【指针】。

2.存储方式

  • 引用类型的存储

当你在函数中创建一个引用类型的对象时,比如:

StringBuffer str = new StringBuffer();

该 StringBuffer 【对象】的内容是存储在堆(Heap)上的,需要申请堆内存。而变量 str 只不过是针对该 StringBuffer 对象的一个引用(或者叫地址)。变量 str 的【值】(也就是 StringBuffer 对象的地址)是存储在【栈】上的。

  • 对比基本类型的存储

当你在【函数中】创建一个基本类型的变量时,比如:

int n = 123;

这个变量 n 的【值】也是存储在栈(Stack)上的,但是这个语句不需要再从堆中申请内存了。

简图如下:

 

 3.创建引用

假设咱们在【函数中】写了如下这个简单的语句:

StringBuffer str = new StringBuffer("Hello world");

别看这个语句简单,其实包含了如下三个步骤:

首先,new 操作符会在【堆】(Heap)里申请一块内存,把创建好的 StringBuffer 对象放进去。

其次,StringBuffer str 声明了一个指针。这个指针本身是存储在【栈】(Stack)上的(此语句写在【函数中】),用来指向某个 StringBuffer 类型的对象。或者换一种说法,这个指针可以用来保存某个 StringBuffer 对象的地址。

最后,当中这个 等于号(赋值符号)把两者关联起来,也就是把刚申请的那一块内存的地址保存成 str 的值。

4.引用对象之间的赋值与相等判断

对于以下语句:

StringBuffer str2 = str;

实际上就是把 str 的地址复制给 str2;记住,是地址的复制,StringBuffer 对象本身并【没有】复制。所以两个指针指向的是同一个东西。示意图如下:

明白了赋值,判断相等的问题(就是==操作符)也就简单了。当我们写如下语句时,只是判断两个指针的【值】(也就是对象的地址)是否相等,并【不是】判断“被指向的对象”是否内容相同。

if(str2 == str)

实际上两个指针的值相同,则肯定是指向同一个对象(所以对象内容必定相同)。但是两个内容相同的对象,它们的地址可能不一样(比如克隆出来的多个对象之间,地址就不同),所以此时要调用equals方法来判断引用类型的内容是否相同。

5.关于final常量

针对引用类型变量的 final 修饰符是很多人混淆的地方。实际上 final 只是修饰指针的值(也就是限定指针保存的地址不能变)。至于该指针指向的对象,内容是否能变,那就无所谓了。

所以,对于如下语句:

final StringBuffer strConst = new StringBuffer();

你可以修改它指向的对象的【内容】,比如:

strConst.append("hello world");

但是【不能】修改它的【值】,比如:

strConst = null;

6.关于传参

引用类型(在函数调用中)的传参问题,是一个相当有争议的问题。有些书上说是传值,有些书上说是传引用。所以,我们最后来谈一下“引用类型参数传递”的问题。

还是拿刚才的例子,假设现在要把刚才创建的那一坨字符串打印出来,我们会使用如下语句:

System.out.println(str);

这个语句又是什么意思?这时候就有两种说法。

第一种理解:

可以认为传进函数的是 str 这个指针,指针说白了就是一个地址的值,说得再白一点,就是个整数。按照这种理解,就是传值的方式。也就是说,参数传递的是指针本身,所以是传值的。

第二种理解:

可以认为传进去的是 StringBuffer 对象,按照这种理解,就是传引用方式了。因为我们确实是把对象的地址(也就是引用)给传了进去。

其实不论是“传引用”还是“传值”,都可以讲得通,关键取决于你是【如何看待】参数所传递的【东西】。这就好比量子力学中“光的波粒二象性”,如果你以粒子的方式去测量它,它看起来像粒子;如果你以波动的方式去观测它,它看起来像波动。


 

总之,Java中的引用类型奥妙无穷,值得好好研究,最重要的是从中理解java中面向对象的思想。

posted @ 2022-05-12 17:29  WildMice  阅读(323)  评论(0编辑  收藏  举报