声明

本篇所涉及的提问,正文的知识点,全都来自于杨晓峰的《Java核心技术36讲》,当然,我并不会全文照搬过来,毕竟这是付费的课程,应该会涉及到侵权之类的问题。

所以,本篇正文中的知识点,是我从课程中将知识点消耗后,用个人的理解、观念所表达出来的文字,参考了原文,但由于是个人理解,因此不保证观点完全正确,也不代表错误的观点是课程所表达的。如果这样仍旧还是侵权了,请告知,会将发表的文章删掉。

当然,如果你对此课程有兴趣,建议你自己也购买一下,新用户立减 30,微信扫码订阅时还可以返现 6 元,相当于 32 元购买 36 讲的文章,每篇文章还不到 1 元,蛮划算的了。

提问

  • 谈谈 final、finally、finalize 有什么不同?
  • 为什么局部内部类和匿名内部类只能访问局部final变量?

正文

emmm,说实话,感觉这一讲好像没什么实质性内容。而且,就像评论区里有人提到的,搞不懂为啥总有人喜欢拿这三者来比较,它们有个毛的关系?仅仅就是因为单词相近就拿来比较?

但课程小结还是要做下,梳理梳理下相关面试知识点也好,那也不说废话了,结合原文和评论区,以及一些扩展,尽量多总结一些知识点吧。

final

final 是 java 中的关键字,可用于修饰类,方法,变量。

当修饰类时,表明这个类不可被继承。Java 中有一些核心类都被 final 修饰了,比如 String,System。当考虑到安全性原因时,可以将该类设计成 final。

当修饰方法时,表明该方法不可被重写。一般是某些流程控制不希望被修改掉时,可以将这些方法声明成 final,比如 View 中的 measure()requestFocus()findViewById()

当修饰变量时,表明该变量为常量,不允许被重新赋值,因此声明成 final 的变量都需要显示的进行赋值,否则编译会报错。

finally

finally 是确保 try-catch 方式最后执行的一种机制,通常的用法都是在 finally 里进行一些资源的关闭,回收。比如 IO 流的关闭等等。

建议最好不要利用 finally 来控制流程,也不要在 finally 中有返回值,否则很容易影响正常流程,导致流程结构特别杂乱。

另外,有些特殊情况下,finally 中的代码并不会被执行到,比如:

//1.try-catch异常退出
try {
System.exit(1)
} catch {
....
} finally {
//不会执行到这里
Log.d("finally", "finally");
} //2.无限循环
try {
while(true) {
...
}
} finally {
//不会执行到这里
Log.d("finally", "finally");
} //3. 线程被杀死
//当执行 try-catch 时,线程被杀死了,那么 finally 里的代码也无法被执行到

总之,finally 通常情况下都会最后被执行到,所以最好不要在这里有 return 之类的语句来影响正常流程。但在某些特殊的场景下,finally 并不会被执行到,了解一下即可。

finalize

这个是 Object 中的一个方法,方法注释说了很多,大概就是讲这个方法是由垃圾收集器即将要回收该对象时会调用该方法,用户可在这里做一些最后的资源释放工作。

以上是概念定义,但说实话,没用过该方法,而且作者也说了,不推荐使用 finalize 机制来做资源回收,并且在 JDK 9,这个方法已经被标志为 deprecated 废弃的方法了。

作者有提到说,因为我们无法保证 finalize 什么时候执行,执行是否符合预期,使用不当还会影响性能,导致程序死锁、挂起等问题。

那么,有其他方案来替代 finalize 处理回收资源的工作么?有,Cleaner 机制,这个我没接触过,作者提了这个替代方案。另外,作者也说了,回收资源最好就是资源用完后就随手清除,或者结合 try-catch-finally 机制回收。不管是 finalize 或者 Cleaner 机制,最好都只将它看成是最后一道防线,一旦将主要的回收工作依赖于这两个机制的话,很容易出现各种问题。

扩展

为什么局部内部类和匿名内部类只能访问局部final变量?

先来看这么段代码:

//参数 msg 必须声明为 final 类型
public void notifyChange(final String msg) {
mTextView.post(new Runnable() {
@Override
public void run() {
mTextView.setText(msg);
}
})
}

在这里,post() 方法的参数是一个匿名内部类,在内部类中如果要使用外部 notifyChange() 方法的参数 msg,那么必须将 msg 类型声明成 final,否则编译器会保错。

这种场景非常常见的吧,不管是类似上述的 Ui 场景,还有网络访问时也经常需要通过回调通知上层,此时也就经常出现这种场景了。

那么,有考虑过,为什么内部类只能访问局部 final 变量么?

如果懂得反编译 class 文件的,那么应该就很清楚了。我也不懂,理解这点是通过阅读其他大神分析的文章,以下是我的理解:

首先,变量都是有生命周期的,成员变量的生命周期就跟随着对象的整个生命周期,而局部变量的生命周期则是非常有限。

比如方法内部的局部变量,它的生命周期就是在这个方法执行结束就终止。同样,方法的参数也是局部变量,它是生命周期也同样是到该方法执行结束。

另外,内部类的执行时机有时是会在外部方法执行结束之后。就拿上述例子来说,post() 中 Runnable 的执行时机,肯定是在外部 notifyChange() 方法执行完之后的。

那么,问题来了。内部类 Runnable 的执行需要使用到外部方法 notifyChange() 的参数,但当它执行的时候,这个参数的生命周期早已结束,已经被回收掉了。既然已经被回收了,内部类又是怎么使用外部的这个局部变量呢?

有大神反编译了 class 文件后,给出了结论,原来内部类使用外部的局部变量时,是通过 copy 一份过来。也就是说,其实内部类此时使用的是自己内部定义的局部变量了,只是这个变量的值是复制外部那个局部变量的而已。

这也就解释了,为什么外部的局部变量明明已经被回收了,内部类仍旧可以使用,因为内部类此时使用的并不是外部类的局部变量引用了。

但到这里,新的问题就来了:既然内部类使用的局部变量本质上跟外部的局部变量是相互独立的两个变量,那如果在内部类中修改了这个局部变量的值会出现什么情况?是吧,数据的不一致性。

基于此,java 编译器就直接限定死,内部类使用外部的局部变量时,必须将其限制为 final 类型,确保该变量不允许进行更改。

这样一来,其实也就顺便理解了,为什么成员变量可以直接在内部类中使用,因为成员变量的声明周期很长,不存在局部变量的问题。

以上内容,是在大神的文章里被醍醐灌顶了,感谢大神,原文链接放出来:

Java内部类详解


大家好,我是 dasu,欢迎关注我的公众号(dasuAndroidTv),如果你觉得本篇内容有帮助到你,可以转载但记得要关注,要标明原文哦,谢谢支持~

谈谈 final finally finalize 区别的更多相关文章

  1. Reader和Writer区别final.finally.finalize区别

    Reader和Writer是字符操作流,Writer是输出的,而Reader是输入的. 首先找到一个文件,比如:File file=new File("."+File.separa ...

  2. 谈谈final, finally, finalize的区别

    final 修饰符(关键字)如果一个类被声明为final,意味着它不能再派生出新的子类,不能作为父类被继承.因此一个类不能既被声明为 abstract的,又被声明为final的.将变量或方法声明为fi ...

  3. final finally finalize 区别及用法

    final 1,final修饰的class,代表不可以继承扩展. 2.final的方法也是不可以重写的. 3.final修饰的变量是不可以修改的.这里所谓的不可修改对于基本类型来来,的确是不可以修改. ...

  4. final finally finalize 区别

    public class Demo { public static void main(String[] args) { long start = System.currentTimeMillis() ...

  5. Final,finally,finalize区别

    final— 修饰符(关键字)如果一个类被声明为final,意味着它不能再派生出新的子类,不能作为父类被继承.因此一个类不能既被声明为 abstract的,又被声明为final的.将变量或方法声明为f ...

  6. final,finally,finalize有什么区别?String, StringBuffer, StringBuilder有什么区别?Exception和Error有什么区别?

    继上篇JVM学习之后,后面将分三期深入介绍剩余JAVA基础面试题,每期3题. 题目一.final,finally,finalize有什么区别? /*请尊重作者劳动成果,转载请标明原文链接:*/ /* ...

  7. Android源码中final关键字的用法及final,finally,finalize的区别

    Android开发的学习流程 final,finally,finalize的区别 Android的发展越来越快,Android开发人员越来越多,当两种情况碰撞,在诸多开发者中跟紧Android步伐脱颖 ...

  8. 【Java面试题系列】:Java中final finally finalize的区别

    本篇为[Java面试题系列]第三篇,文中如有错误,欢迎指正. 第一篇链接:[Java面试题系列]:Java基础知识常见面试题汇总 第一篇 第二篇链接:[Java面试题系列]:Java基础知识常见面试题 ...

  9. java面试题(杨晓峰)---第三讲谈谈final、finally、finalize有什么不同?

    java语言有很多看起来相似,但用途却完全不相同的语言要素,这些内容往往容易成为面试官考察你知识掌握程度的切入点. 今天我要问你一个基础的java经典题目,谈谈final.finally.finali ...

随机推荐

  1. 于bugku中游荡意外得到关于CBC翻转攻击思路

    个人简介:渣渣一枚,萌新一个,会划水,会喊六六今天在bugku遇到关于CBC翻转攻击的题目,总结了一下关于CBC翻转攻击的原理,以及关于这道题目的解题思路个人博客:https://www.cnblog ...

  2. Java 判断两个对象是否相等

    一.使用 == 与 equals == : 它的作用是判断两个对象的地址是不是相等.即,判断两个对象是不是同一个对象.(基本数据类型==比较的是值,引用数据类型==比较的是内存地址) equals() ...

  3. Testing - 自动化测试的几个基础概念

    自动化测试框架与模型 一个自动化测试框架就是一个集成体系,在这一体系中包含测试功能的函数库.测试数据源.测试对象识别标准,以及种可重用的模块. 自动化测试框架在发展的过程中经历了几个阶段,模块驱动测试 ...

  4. SpringBoot集成netty实现客户端服务端交互和做一个简单的IM

    看了好几天的netty实战,慢慢摸索,虽然还没有摸着很多门道,但今天还是把之前想加入到项目里的 一些想法实现了,算是有点信心了吧(讲真netty对初学者还真的不是很友好......) 首先,当然是在S ...

  5. 基于python的OpenCV图像1

    目录 1. 读入图片并显示 import cv2 img = cv2.imread("longmao.jpg") cv2.imshow("longmao", i ...

  6. 剑指offer例题分享--6

    前言:继续整理例题,快速做完这部分,然后继续用C++去刷数据结构和算法的题. 面试题28: 代码如下: #include<iostream> #include<stdio.h> ...

  7. 发福利了!!超过100本的linux免费书籍

    New Books Kindle Fire App Development Essentials iPhone iOS 6 Development Essentials CentOS 6 Essent ...

  8. SpringCloud实战10-Sleuth

    Spring-Cloud-Sleuth是Spring Cloud的组成部分之一,为SpringCloud应用实现了一种分布式追踪解决方案,其兼容了Zipkin, HTrace和log-based追踪, ...

  9. RabbitMQ系列(六)你不知道的RabbitMQ集群架构全解

    前言 本文将系统的介绍一下RabbitMQ集群架构的特点.异常处理.搭建和使用中要注意的一些细节. 知识点 一.为什么使用集群? 二.集群的特点 三.集群异常处理 四.集群节点类型 五.集群搭建方法 ...

  10. 在Object-C中学习数据结构与算法之排序算法

    笔者在学习数据结构与算法时,尝试着将排序算法以动画的形式呈现出来更加方便理解记忆,本文配合Demo 在Object-C中学习数据结构与算法之排序算法阅读更佳. 目录 选择排序 冒泡排序 插入排序 快速 ...