谈谈你对 finalize 方法的理解,该怎样回答才能体现出高水平?浮于表面的答案永远不行!

本文主要是介绍谈谈你对 finalize 方法的理解,该怎样回答才能体现出高水平?浮于表面的答案永远不行!,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

1. finalize 方法是什么?

2. finalize 方法的作用?

3. 为什么强烈不建议在 finalize 方法中进行资源的释放和清理工作


1. finalize 方法是什么?

首先要知道,finalize 方法是 Object 类中的一个方法,从源码中叶可儿一看到,所以所有的对象都会具有这个方法,该方法修饰符为 protected ,子类可以进行 @Override 重写,但实际开发过程中一般不会去理会它。

在 JDK9 之后,该方法已经被官方不推荐使用了,但面试的时候还是有可能会被问到的,所以我们就来聊聊该方法的一些作用。

2. finalize 方法的作用?

finalize 方法是在对象被垃圾回收器回收之前执行的,当我们将一个对象设置为 null 之后,它就变成了垃圾,等待着垃圾回收器回收,finalize 方法主要就是做一些清理善后的工作,如果一个对象重写了 finalize 方法,那么它在被垃圾回收器回收之前,就会先执行 finalize 方法。

由此也带来了它的另一个作用,通常一个对象都是具有很多的功能属性的,所以我们就可以将一些资源的释放;例如文件关闭操作,网络连接断开操作放到 finalize 方法中去完成。

如下代码所示

public class Test {// 重写 Test 类中的 finalize() 方法@Overridepublic void finalize() throws Throwable{// 打印一句话作为标记,证明该方法被调用过System.out.println("finalize方法执行");}public static void main(String[] args) throws Exception {// 创建类对象 tTest t = new Test();
// 获取该对象System.out.println(t+"第一次获取对象");
// 将对象t赋值为 null,此时堆中的对象就会变成垃圾t = null;// 手动开启垃圾回收GC,将垃圾回收,验证 finalize方法是否执行System.gc();// 因为GC垃圾回收是另外的垃圾回收线程,所以我们让主线程先睡两秒,避免造成误差Thread.sleep(2000);// 经过GC之后再次获取t对象System.out.println(t+"第二次获取对象");}
}

这里还有一点需要提醒注意,Java虚拟机的GC是单独的GC垃圾回收线程,并且该线程是 main 线程的守护线程,只要 main 线程运行结束,GC垃圾回收线程就会停止,所以在代码中我才让 main 线程调用 sleep 方法。

然后我们运行上述方法,在控制台中得到如下所示结果

可以看到,将对象 t 赋值为 null 之后,finalize 方法就执行了。

3. 为什么强烈不建议在 finalize 方法中进行资源的释放和清理工作

经过了上面的演示,现在已经得知,finalize 方法会在对象被垃圾回收器回收之前执行此方法,但是!!!强烈不建议在 finalize 方法中进行资源的释放和清理工作。

原因我总结了以下三点

(1)资源释放实际成谜。

如果我们重写了 finalize 方法,那么对象在变成垃圾被垃圾回收器回收之前,需要先执行 finalize 方法,而 finalize 方法并不是由垃圾回收器来调用的,是有一个专门的线程叫 finalizer 来调用的,finalizer 线程内部有一个引用队列,垃圾回收器识别到垃圾对象之后,会把该对象添加到引用队列中去,finalizer 线程会依次调用每个对象的 finalize 方法然后进行清理。如果说一个对象不再被任何一个变量引用,我们就希望它能够马上被回收释放占用的系统资源,但是垃圾回收算法的运行时机是不确定的,而且缺少对该垃圾对象的监控,所以我们无从得知盖拉几何时会被清理掉,资源的释放时机就成了谜。

(2)资源释放异常,对象变成"僵尸"。

finalize 既然是一个方法,那么它就有可能抛出异常,如果抛出异常,垃圾清理到一半又没有清理完,此时这个对象就不能被清除掉,就变成半死不活的"僵尸"了,一直占用系统资源无法被释放。

(3)很容易导致OOM(内存溢出)

GC垃圾回收线程和主程序的线程不是同一个线程。也就是说,我们的主线程,也可以说是业务一直都在持续地进行着,那么业务就很有可能会在内存中继续创建出新的对象进行其他的业务操作。而此时先前创建的对象被回收需要调用 finalize 方法,如果我们将一些资源的释放工作和内存清理工作全部放到 finalize 方法中的话,是非常耗时的,特别是网络断开连接操作,需要等待对方的响应才能断开连接,但现在内存中的垃圾对象又需要等待 finalize 方法执行完毕后才能清除,由于业务的不断进行,还有不断新的对象被创建,垃圾对象的清理速度慢,新对象的创建速度快,清理的速度没有创建的速度快,一定会造成内存溢出。

这篇关于谈谈你对 finalize 方法的理解,该怎样回答才能体现出高水平?浮于表面的答案永远不行!的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/162106

相关文章

Maven 配置中的 <mirror>绕过 HTTP 阻断机制的方法

《Maven配置中的<mirror>绕过HTTP阻断机制的方法》:本文主要介绍Maven配置中的<mirror>绕过HTTP阻断机制的方法,本文给大家分享问题原因及解决方案,感兴趣的朋友一... 目录一、问题场景:升级 Maven 后构建失败二、解决方案:通过 <mirror> 配置覆盖默认行为1. 配置示

SpringBoot排查和解决JSON解析错误(400 Bad Request)的方法

《SpringBoot排查和解决JSON解析错误(400BadRequest)的方法》在开发SpringBootRESTfulAPI时,客户端与服务端的数据交互通常使用JSON格式,然而,JSON... 目录问题背景1. 问题描述2. 错误分析解决方案1. 手动重新输入jsON2. 使用工具清理JSON3.

使用jenv工具管理多个JDK版本的方法步骤

《使用jenv工具管理多个JDK版本的方法步骤》jenv是一个开源的Java环境管理工具,旨在帮助开发者在同一台机器上轻松管理和切换多个Java版本,:本文主要介绍使用jenv工具管理多个JD... 目录一、jenv到底是干啥的?二、jenv的核心功能(一)管理多个Java版本(二)支持插件扩展(三)环境隔

Java中Map.Entry()含义及方法使用代码

《Java中Map.Entry()含义及方法使用代码》:本文主要介绍Java中Map.Entry()含义及方法使用的相关资料,Map.Entry是Java中Map的静态内部接口,用于表示键值对,其... 目录前言 Map.Entry作用核心方法常见使用场景1. 遍历 Map 的所有键值对2. 直接修改 Ma

Mybatis Plus Join使用方法示例详解

《MybatisPlusJoin使用方法示例详解》:本文主要介绍MybatisPlusJoin使用方法示例详解,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,... 目录1、pom文件2、yaml配置文件3、分页插件4、示例代码:5、测试代码6、和PageHelper结合6

Java中实现线程的创建和启动的方法

《Java中实现线程的创建和启动的方法》在Java中,实现线程的创建和启动是两个不同但紧密相关的概念,理解为什么要启动线程(调用start()方法)而非直接调用run()方法,是掌握多线程编程的关键,... 目录1. 线程的生命周期2. start() vs run() 的本质区别3. 为什么必须通过 st

C#之List集合去重复对象的实现方法

《C#之List集合去重复对象的实现方法》:本文主要介绍C#之List集合去重复对象的实现方法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录C# List集合去重复对象方法1、测试数据2、测试数据3、知识点补充总结C# List集合去重复对象方法1、测试数据

SpringBoot读取ZooKeeper(ZK)属性的方法实现

《SpringBoot读取ZooKeeper(ZK)属性的方法实现》本文主要介绍了SpringBoot读取ZooKeeper(ZK)属性的方法实现,强调使用@ConfigurationProperti... 目录1. 在配置文件中定义 ZK 属性application.propertiesapplicati

MyBatis设计SQL返回布尔值(Boolean)的常见方法

《MyBatis设计SQL返回布尔值(Boolean)的常见方法》这篇文章主要为大家详细介绍了MyBatis设计SQL返回布尔值(Boolean)的几种常见方法,文中的示例代码讲解详细,感兴趣的小伙伴... 目录方案一:使用COUNT查询存在性(推荐)方案二:条件表达式直接返回布尔方案三:存在性检查(EXI

Java调用C#动态库的三种方法详解

《Java调用C#动态库的三种方法详解》在这个多语言编程的时代,Java和C#就像两位才华横溢的舞者,各自在不同的舞台上展现着独特的魅力,然而,当它们携手合作时,又会碰撞出怎样绚丽的火花呢?今天,我们... 目录方法1:C++/CLI搭建桥梁——Java ↔ C# 的“翻译官”步骤1:创建C#类库(.NET