Java中对象的生与灭- 核心篇

前言
大家好啊,我是汤圆,今天给大家带来的是《Java中对象的生与灭- 核心篇》,希望对大家有帮助,谢谢
文章纯属原创,个人总结难免有差错,如果有,麻烦在评论区回复或后台私信,谢啦

简介
前面我们了解了Java的三大特性,其中介绍了类的继承、重载等,这里我们就基于这些知识点,把对象的创建和回收进行一个简单的介绍
这篇不是很长,只是介绍核心的几个知识点,相信大家很快就可以看完,真的
目录
- 堆和栈
- 构造函数(生)
- 对象的回收(灭)
正文
堆(heap)和栈(stack)
堆是一块内存,用来存放对象
栈是另一块内存,用来执行方法并存储局部变量,遵循后进先出的原则;
PS:栈并不存储方法,只是执行方法,执行完方法后,会将方法弹出栈(方法存在方法区)
下面我们用实际代码,来看下堆和栈的区别
代码如下:
public class LiveAndDeathDemo {
// 基本类型属性
private int a;
public static void main(String[] args) {
LiveAndDeathDemo live = new LiveAndDeathDemo(1);
live.fun();
}
public void fun(){
int temp = 10;
System.out.println(temp);
}
public LiveAndDeathDemo(int a) {
this.a = a;
}
public int getA() {
return a;
}
public void setA(int a) {
this.a = a;
}
}
可以看到,有一个实例变量a(堆), 两个方法main和fun,其中fun有一个局部变量temp(栈)
它们的区别如下所示:

这里简单介绍一下上面的流程
- main方法压入栈中,创建局部变量live(对象的引用)
- 创建对象live,在堆中开辟内存,将live放入堆中
- live调用fun方法,将fun压入栈中(此时fun在栈顶)
- fun执行完成,出栈,继续执行main方法
- 最后main方法执行完成,也出栈,程序结束
这里可能有朋友要问了,那如果属性是一个引用呢?它要存放在哪里?
堆
引用存放在堆里,引用指向的对象也存放在堆里,只不过是堆的另一个地方
如下图所示:堆中 live对象的属性 liveRef 指向了另一个对象(live对象2)

为啥要先介绍堆和栈呢?
因为堆和栈跟对象的生活息息相关
如果用人来比作对象的话,那堆就是人的家,栈就是外面的世界
我们出生在家里,跟外面的世界打交道,最后在家里。。。
对象的创建(生)
生存还是毁灭,这是一个问题。
-- 莎士比亚《哈姆莱特》
在Java的花花世界中,这也是个问题,不过是个有答案的问题;
答案就在下面。。。

这里我们先把问题简化
因为我们最常见的创建对象是通过new创建,而new对象的核心就是通过构造函数来实现,所以我们这里简单起见,着重介绍构造函数,其他的后面等到虚拟机部分再介绍
构造函数的分类:
无参构造函数
有参构造函数
构造函数和普通方法的区别:
构造函数没有返回类型
构造函数名与类名一致
关于编译器的默认操作:
- 如果没有定义构造函数,编译器会默认创建一个无参构造函数
- 如果子类定义了有参构造函数,且没有显示调用父类的构造函数,则编译器默认调用父类的无参构造函数
当你自己有创建构造函数(无参或有参)时,编译器都不会再去创建构造函数
构造函数的重载:
很常用,一般用来设置属性的默认值
具体做法就是多个构造函数层层调用(又来套娃了)
下面举个例子:
public class LiveAndDeathDemo {
private int a;
private String name;
public LiveAndDeathDemo(){
this(1);
}
public LiveAndDeathDemo(int a) {
this(a, "JavaLover");
}
public LiveAndDeathDemo(int a, String name) {
this.a = a;
this.name = name;
}
// 省略getter,setter
}
用图表示的话,就是下面这个样子

构造函数的私有化
如果构造函数私有化,那么它要怎么用呢?
私有化说明只有类本身可以调用,这种主要用在工厂方法中
比如Java中的LocalDate,源码如下:
public final class LocalDate
implements Temporal, TemporalAdjuster, ChronoLocalDate, Serializable {
// 构造函数私有化
private LocalDate(int year, int month, int dayOfMonth) {
this.year = year;
this.month = (short) month;
this.day = (short) dayOfMonth;
}
// 对外提供一个静态方法,用来创建对象实例
public static LocalDate of(int year, int month, int dayOfMonth) {
YEAR.checkValidValue(year);
MONTH_OF_YEAR.checkValidValue(month);
DAY_OF_MONTH.checkValidValue(dayOfMonth);
return create(year, month, dayOfMonth);
}
}
这种用法在LocalDate这种工具类中用的比较多,还有就是单例模式(后面设计模式时再介绍)
上面介绍的构造函数没有介绍到父类,下面开始介绍
如果有父类,构造函数的有哪些不一样的地方
this和super:
在介绍父类的构造函数之前,有必要介绍下这个super
this指向当前类super指向父类
super用来显式调用父类相关属性和方法(包括构造函数)
比如super.filedA, super.fun()等
这里有个特例,如果是在子类的构造函数中或者覆写方法中,则直接调用super()即可调用父类对应的构造函数或方法(下面代码有演示)
构造函数的执行顺序
如果子类
Dog继承父类Animal,那么会先调用父类的构造函数,再调用子类的构造函数;如果父类Animal上面还有父类,会继续往上调用;
上面这个过程就叫做“构造函数链”
这个关系有点像是:子女和父母的关系,子女要想出生,必须先让爷爷奶奶把父母生出来,然后父母才能生子女
所以这里如果我们要构造子类,必须先构造父类;如果父类还有父类,则继续延伸,一直到Object超类为止
下面用代码演示下这个层层调用的过程:
public class SuperDemo extends Father{
public SuperDemo() {
// 1.1 这里显示调用父类的构造函数
// 1.2 Super必须放在构造函数的第一行
super();
System.out.println("sub construct");
}
public static void main(String[] args) {
SuperDemo demo = new SuperDemo();
}
}
class Father{
public Father() {
// 2. 这里没有显示调用父类(Object)的构造函数,编译器会自己去调用
System.out.println("father construct");
}
}
/** 假设下面这个Object就是我们的超类
class Object{
public Object(){
// 3. 最终的构造函数,会调到这里为止
}
}
**/
输出如下:
father construct
sub construct
可以看到,先调用父类Father的构造函数,再调用子类的构造函数
他们之间的继承关系如下:

图示说明:
左边的虚线表示层层往上调用,直到超类Object
右边的实现表示上面的构造完成会回到下面那一层,继续构造,直到当前类
好了,构造的过程大致就是这个样子了,还有很多其他方面的细节(比如类的初始化等)这里先不介绍了,太多了,放到后面介绍
对象的回收(灭)
对象的回收是在程序内存不够用时,将没用的对象(可回收)进行释放的一种操作,这个操作是由垃圾收集器GC来完成的
什么是没用的对象?
没用的对象就是可回收的对象
说人话:当指向对象A的最后一个引用ref消失时,这个对象A就会变成没用的对象,等待着垃圾收集器的回收
那怎么才算引用消失呢?
基本分为两种情况:
如果引用是局部变量,那当引用所在的方法执行完毕时,引用就会被释放,那么该对象随即也就会被标记为没用的对象,等待回收
当引用指向其他对象或者null时,该对象会被标记为没用的对象,等待回收
上面都是假设引用是指向对象的最后一个引用的情况,如果有多个引用指向同一个对象,那么要等到引用都消失,对象才会被标记为可回收,即没用的东西
总结
- 堆和栈
堆存放对象,栈用来执行方法并存放局部变量
- 对象的创建
主要通过构造函数来创建,比如new对象
如果是反序列化来创建对象,则不会构造,因为构造后,对象的属性会被重新初始化,那么序列化的属性值就被抹掉了(前面的Java中的IO流有涉及)
如果子类有父类,则先调用父类的构造函数,如果父类还有父类,则依次类推,直到Object超类
- 对象的回收
当指向对象的最后一个引用消失时,这个对象就会变成没用的对象,等待着垃圾收集器的回收
后记
最后,感谢大家的观看,谢谢
Java中对象的生与灭- 核心篇的更多相关文章
- Java多线程编程实战指南(核心篇)读书笔记(五)
(尊重劳动成果,转载请注明出处:http://blog.csdn.net/qq_25827845/article/details/76730459冷血之心的博客) 博主准备恶补一番Java高并发编程相 ...
- Java多线程编程实战指南(核心篇)读书笔记(三)
(尊重劳动成果,转载请注明出处:http://blog.csdn.net/qq_25827845/article/details/76686044冷血之心的博客) 博主准备恶补一番Java高并发编程相 ...
- Java多线程编程实战指南(核心篇)读书笔记(二)
(尊重劳动成果,转载请注明出处:http://blog.csdn.net/qq_25827845/article/details/76651408冷血之心的博客) 博主准备恶补一番Java高并发编程相 ...
- Java多线程编程实战指南(核心篇)读书笔记(一)
(尊重劳动成果,转载请注明出处:http://blog.csdn.net/qq_25827845/article/details/76422930冷血之心的博客) 博主准备恶补一番Java高并发编程相 ...
- 《Java多线程编程实战指南(核心篇)》阅读笔记
<Java多线程编程实战指南(核心篇)>阅读笔记 */--> <Java多线程编程实战指南(核心篇)>阅读笔记 Table of Contents 1. 线程概念 1.1 ...
- Java多线程编程实战指南(核心篇)读书笔记(四)
(尊重劳动成果,转载请注明出处:http://blog.csdn.net/qq_25827845/article/details/76690961冷血之心的博客) 博主准备恶补一番Java高并发编程相 ...
- Java中的三大特性 - 超详细篇
前言 大家好啊,我是汤圆,今天给大家带来的是<Java中的三大特性 - 超详细篇>,希望对大家有帮助,谢谢 这一节的内容可能有点多,大家可以选择性的来看 简介 Java的三大特性:封装.继 ...
- Java中对象的深复制和浅复制详解
1.浅复制与深复制概念 ⑴浅复制(浅克隆) 被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象.换言之,浅复制仅仅复制所考虑的对象,而不复制它所引用的对象. ⑵ ...
- java 中对象比较大小
java 中对象比较大小 java 中对象比较大小有两种方法 1:实现Comparable 接口 的 public int compareTo(T o) 方法: 2:实现Comparator 接口 的 ...
随机推荐
- HTTP/1.1 & HTTP/2 & webpack
HTTP/1.1 & HTTP/2 & webpack Bundling your application is especially powerful for HTTP/1.1 cl ...
- PAUL ADAMS ARCHITECT:薪资追不上房价美一半家庭难买房
尽管上一年度美国经济遭受重创,但美国房价依旧持续蹿扬,据最新调查显示,美国大部分地区的房价已经到了一般家庭无法负担的水准. 美国房价上涨持续强劲,主要受益美国人居家办公需求(受大环境影响,目前美国有7 ...
- NGK全球行伦敦站,SPC推动全球数字金融创新
近日,NGK全球巡回路演在英国的首都伦敦盛大落幕,此次路演有幸邀请到了西欧区块链业界弗洛伊德大咖,NGK方面代表鲍利斯以及英国及其组周边国家社群意见代表马丁内斯等人,总计参与人数达到了数十人. 路演一 ...
- 微信小程序(六)-项目实例(原生框架 MINA基配搭建)==01-头搜索框tabbar
项目实例(原生框架 MINA) 1.新建小程序项目 1.用自已的小程序APPID 2.清除整理项目中初建默认无关的代码 1.app.json 中删除logs,同时删除pages下的losgs文件夹 2 ...
- 为什么ConcurrentHashMap,HashTable不支持key,value为null?
ConcurrentHashmap.HashMap和Hashtable都是key-value存储结构,但他们有一个不同点是 ConcurrentHashmap.Hashtable不支持key或者val ...
- Elasticsearch 7.x配置用户名密码访问 开启x-pack验证
一.修改elasticsearch 配置文件 1.在配置文件中开启x-pack验证 #进入es安装目录下的config目录 vim elasticsearch.yml # 配置X-Pack http. ...
- Docker的架构
一.Docker引擎 docker引擎是一个c/s结构的应用,主要组件见下图: Server是一个常驻进程 REST API 实现了client和server间的交互协议 CLI 实现容器和镜像的管理 ...
- Pyqt5——变色的表格
需求:鼠标左键点击表格后,对应的单元格背景颜色发生变化. 实现:(1)使用Qt的model-view模式生成表格视图. (2)重写表格的点击事件. (3)设置表格的背景颜色. 正常情况下,当用户选中单 ...
- Magicodes.IE Excel合并行数据导入教程
说明 Magicodes.IE.Excel目前已支持合并行单元格导入,如本篇教程所示. 安装包Magicodes.IE.Excel Install-Package Magicodes.IE.Excel ...
- 几大BSD 区别
OpenBSD 侧重于安全,软件包较少,较陈旧,比如 KDE 才 3.5,为了安全舍弃了 sudo 和 linux 兼容层: FreeBSD 是开发者最多用户最多软件包最多的,有 ZFS 和 Linu ...