史上最全的Java专有名词:对象引用堆栈解读,导师都说我总结的好!
Posted Java老猿
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了史上最全的Java专有名词:对象引用堆栈解读,导师都说我总结的好!相关的知识,希望对你有一定的参考价值。
前言
对象、引用、堆、栈,这些是啥呀,为什么又有堆栈和栈,讲实话这些Java名词不仅仅新手看了头疼,一些老一辈的程序员可能也还没有搞清楚这些专有名词,所以接下来我们就说一下, Java中哪些吃人的 名词:对象、引用、堆、栈是啥,有什么区别和作用
刚好最近,和Java高级架构群(点这里进群)的群友们交流后,Java 中那四五个会吃人的名词:对象、引用、堆、栈、堆栈,似乎在脑海中也清晰了起来,尽管疑惑有时候仍然会在阴云密布时跑出来——正鉴于此,这篇文章恰好做一下归纳。
一、对象和引用
在 Java 中,尽管一切都可以看做是对象,但计算机操作的并非对象本身,而是对象的引用。 这话乍眼一看,似懂非懂。究竟什么是对象,什么又是引用呢?
先来看对象的定义:按照通俗的说法,每个对象都是某个类(class)的一个实例(instance)。那么,实例化的过程怎么描述呢?来看代码(类是 String):
new String("我是对象张三");
new String("我是对象李四");
在 Java 中,实例化指的就是通过关键字“new”来创建对象的过程。以上代码在运行时就会创建两个对象——“我是对象张三"和"我是对象李四”;现在,该怎么操作他们呢?
去过公园的同学应该会见过几个大爷,他们很有一番本领——个个都能把风筝飞得老高老高,徒留我们眼馋的份!风筝飞那么高,没办法直接用手拽着飞啊,全要靠一根长长的看不见的结实的绳子来牵引!操作 Java 对象也是这个理,得有一根绳——也就是接下来要介绍的“引用”(我们肉眼也常常看不见它)。
String zhangsan, lisi;
zhangsan = new String("我是对象张三");
lisi = new String("我是对象李四");
这三行代码该怎么理解呢?
先来看第一行代码:String zhangsan, lisi;
——声明了两个变量 zhangsan 和 lisi,他们的类型为 String。
①、歧义:zhangsan 和 lisi 此时被称为引用。
你也许听过这样一句古文:“神之于形,犹利之于刀;未闻刀没而利存,岂容形亡而神在?”这是无神论者范缜(zhen)的名言,大致的意思就是:灵魂对于肉体来说,就像刀刃对于刀身;从没听说过刀身都没了刀刃还存在,那么怎么可能允许肉体死亡了而灵魂还在呢?
“引用”之于对象,就好比刀刃之于刀身,对象还没有创建,又怎么存在对象的“引用”呢?
如果 zhangsan 和 lisi 此时不能被称为“引用”,那么他们是什么呢?答案很简单,就是变量啊!(鄙人理解)
②、误解:zhangsan 和 lisi 此时的默认值为 null
。
应该说 zhangsan 和 lisi 此时的值为 undefined
——借用 javascript 的关键字;也就是未定义;或者应该是一个新的关键字 uninitialized
——未初始化。但不管是 undefined
还是 uninitialized
,都与 null
不同。
既然没有初始化,zhangsan 和 lisi 此时就不能被使用。假如强行使用的话,编译器就会报错,提醒 zhangsan 和 lisi 还没有出生(初始化);见下图。
如果把 zhangsan 和 lisi 初始化为 null
,编译器是认可的(见下图);由此可见,zhangsan 和 lisi 此时的默认值不为 null
。
再来看第二行代码:zhangsan = new String("我是对象张三");
——创建“我是对象张三"的 String 类对象,并将其赋值给 zhangsan 这个变量。
此时,zhangsan 就是"我是对象张三"的引用;“=”操作符赋予了 zhangsan 这样神圣的权利。
第三行代码 lisi = new String("我是对象李四");
和第二行代码 zhangsan = new String("我是对象张三");
同理。
现在,我可以下这样一个结论了——对象是通过 new
关键字创建的;引用是依赖于对象的;=
操作符把对象赋值给了引用。
我们再来看这样一段代码:
String zhangsan, lisi;
zhangsan = new String("我是对象张三");
lisi = new String("我是对象李四");
zhangsan = lisi;
当 zhangsan = lisi;
执行过后,zhangsan 就不再是"我是对象张三"的引用了;zhangsan 和 lisi 指向了同一个对象(“我是对象李四”);因此,你知道 System.out.println(zhangsan == lisi);
打印的是 false
还是 true
了吗?
二、堆、栈、堆栈
谁来告诉我,为什么有很多地方(书、博客等等)把栈叫做堆栈,把堆栈叫做栈?搞得我都头晕目眩了——绕着门柱估计转了 80 圈,不晕才怪!
我查了一下金山词霸,结果如下:
我的天呐,更晕了,有没有!怎么才能不晕呢?我这里有几招武功秘籍,你们尽管拿去一睹为快:
1)以后再看到堆、栈、堆栈三个在一起打牌的时候,直接把“堆栈”踢出去;这仨人不适合在一起玩,因为堆和栈才是老相好;你“堆栈”来这插一脚算怎么回事;这世界上只存在“堆、栈”或者“堆栈”(标点符号很重要哦)。
2)堆是在程序运行时在内存中申请的空间(可理解为动态的过程);切记,不是在编译时;因此,Java 中的对象就放在这里,这样做的好处就是:
当需要一个对象时,只需要通过 new 关键字写一行代码即可,当执行这行代码时,会自动在内存的“堆”区分配空间——这样就很灵活。
另外,需要记住,堆遵循“先进后出”的规则(此处有雷)。就好像,一个和尚去挑了一担水,然后把一担水装缸里面,等到他口渴的时候他再用瓢舀出来喝。请放肆地打开你的脑洞脑补一下这个流程:缸底的水是先进去的,但后出来的。所以,我建议这位和尚在缸上贴个标签——保质期 90 天,过期饮用,后果自负!
还是记不住,看下图:
(不好意思,这是鼎,不是缸,将就一下哈)
3)栈,又名堆栈(简直了,完全不符合程序员的思维啊,我们程序员习惯说一就是一,说二就是二嘛),能够和处理器(CPU,也就是脑子)直接关联,因此访问速度更快;举个十分不恰当的例子哈——眼睛相对嘴巴是离脑子近的一方,因此,你可以一目十行,但绝对做不到一开口就读十行字,哪怕十个字也做不到。
既然访问速度快,要好好利用啊!Java 就把对象的引用放在栈里。为什么呢?因为引用的使用频率高吗?
不是的,因为 Java 在编译程序时,必须明确的知道存储在栈里的东西的生命周期,否则就没法释放旧的内存来开辟新的内存空间存放引用——空间就那么大,前浪要把后浪拍死在沙滩上啊。
现在清楚堆、栈和堆栈了吧?
三、基本数据类型
先来看《Java 编程思想》中的一段话:
在程序设计中经常用到一系列类型,他们需要特殊对待。之所以特殊对待,是因为 new 将对象存储于“堆”中,故用 new 创建一个对象──特别小、简单的变量,往往不是很有效。因此,不用new来创建这类变量,而是创建一个并非是引用的变量,这个变量直接存储值,并置于栈中,因此更加高效。
在 Java 中,这些基本类型有:boolean、char、byte、short、int、long、float、double 和 void;还有与之对应的包装器:Boolean、Character、Byte、Short、Integer、Long、Float、Double 和 Void;它们之间涉及到装箱和拆箱。
看两行简单的代码:
int a = 3;
int b = 3;
<p>这两行代码在编译的时候是什么样子呢?</p>
<p>编译器当然是先处理 <code>int a = 3;</code>,不然还能跳过吗?编译器在处理 <code>int a = 3;</code> 时在栈中创建了一个变量为 a 的内存空间,然后查找有没有字面值为 3 的地址,没找到,就开辟一个存放 3 这个字面值的地址,然后将 a 指向 3 的地址。</p>
<p>编译器忙完了 <code>int a = 3;</code>,就来接着处理 <code>int b = 3;</code>;在创建完 b 的变量后,由于栈中已经有 3 这个字面值,就将 b 直接指向 3 的地址;就不需要再开辟新的空间了。</p>
<p>依据上面的概述,我们假设在定义完 a 与 b 的值后,再令 a=4,此时 b 是等于 3 呢,还是 4 呢?</p>
<p>思考一下,再看答案哈。</p>
<p>答案揭晓:当编译器遇到 <code>a = 4;</code>时,它会重新搜索栈中是否有 4 的字面值,如果没有,重新开辟地址存放 4 的值;如果已经有了,则直接将 a 指向 4 这个地址;因此 a 值的改变不会影响到 b 的值哦。</p>
<p>最后,留个作业吧,下面这段代码在运行时会输出什么呢?</p>
```cpp
public class Test1 {
public static void main(String args[]) {
int a = 1;
int b = 1;
a = 2;
System.out.println(a);
System.out.println(b);
TT t = new TT("T");
TT t1 = t;
t.setName("TT");
System.out.println(t.getName());
System.out.println(t1.getName());
}
}
class TT{
private String name;
public TT (String name) {
this.name = name;
}
public String getName() {
return this.name;
}
public void setName(String name1) {
this.name = name1;
}
}
最后
小伙伴们,帮忙一键三连呀
题外话,我在一线互联网企业工作十余年里,指导过不少同行后辈。帮助很多人得到了学习和成长。
我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在Java学习中的很多困惑,所以在工作繁忙的情况下还是坚持各种整理和分享。但苦于知识传播途径有限,很多程序员朋友无法获得正确的资料得到学习提升
故此将并将重要的Java进阶资料包括并发编程、JVM调优、SSM、设计模式、spring等知识技术、阿里面试题精编汇总、常见源码分析等录播视频免费分享出来,需要领取的麻烦点这里自行下载或者是添加QQ1404119194,备注csdn
Java进阶视频资料
Java面试题精编汇总
JAVA核心知识点整理
获取方式: 只需你一键三连后,扫描👇二维码自行免费下载或者添加QQ1404119194,备注csdn
以上是关于史上最全的Java专有名词:对象引用堆栈解读,导师都说我总结的好!的主要内容,如果未能解决你的问题,请参考以下文章