谈谈 final finally finalize 区别

声明

本篇所涉及的提问,正文的知识点,全都来自于杨晓峰的《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),如果你觉得本篇内容有帮助到你,可以转载但记得要关注,要标明原文哦,谢谢支持~

原文地址:https://www.cnblogs.com/dasusu/p/9285834.html

时间: 2024-10-16 03:03:24

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

Final,finally,finalize区别

final- 修饰符(关键字)如果一个类被声明为final,意味着它不能再派生出新的子类,不能作为父类被继承.因此一个类不能既被声明为 abstract的,又被声明为final的.将变量或方法声明为final,可以保证它们在使用中不被改变.被声明为final的变量必须在声明时给定初值,而在以后的引用中只能读取,不可修改.被声明为final的方法也同样只能使用,不能重载. finally- 在异常处理时提供 finally 块来执行任何清除操作.如果抛出一个异常,那么相匹配的 catch 子句就会

【动力节点java培训】final, finally, finalize的区别

[动力节点java培训]final, finally, finalize的区别 final 用于声明属性,方法和类,分别表示属性不可变,方法不可覆盖,类不可继承.finally是异常处理语句结构的一部分,表示总是执行.finalize是Object类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法,可以覆盖此方法提供垃圾收集时的其他资源回收,例如关闭文件等. 如果您对动力节点有兴趣,可以登录官网看看免费教学视频:http://dwz.cn/29yALNN java学习交流QQ群:425

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

Android开发的学习流程 final,finally,finalize的区别 Android的发展越来越快,Android开发人员越来越多,当两种情况碰撞,在诸多开发者中跟紧Android步伐脱颖而出就显得十分必要,虽然Android开发行业薪资高,潜力大,但人往高处走,有更大的上升空间就一定要抓住机会,Android开发行业其实很简单,高技能行业行业唯一重要的要求就是技能,所以学好Android开发直接关系到未来的职业发展,千锋Android培训机构作为行业最具权威的Android研发和人

final、finalize、finally

final.finalize.finally final:用于声明属性,方法和类,分别表示属性不可变,方法不可覆盖,类不可继承. 说明:final 声明的成员变量,必须在声明的同时赋值.final 声明的局部变量和普通的局部变量一样,可以在声明的同时不赋初值,但是在使用前必须赋值. finalize 是Object 类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法,可以覆盖此方法提供垃圾收集时的其他资源回收,例如关闭文件等. finally:return.continue和break

谈谈final、finally、finalize的区别

1.final:如果一个类被final修饰,意味着该类不能派生出新的子类,不能作为父类被继承.因此一个类不能被声明为abstract,又被声明为final.将变量或方法声明为final.可以保证他们在使用的时候不被改变.其初始化可以在两个地方:一是其定义的地方,也就是在final变量在定义的时候就对其赋值:二是在构造函数中.这两个地方只能选其中的一个,要么在定义的时候给值,要么在构造函数中给值.被声明为final的方法也只能使用,不能重写. 2.finally:在异常处理的时候,提供finall

final .....finally ...... 和Finalize ......区别

一.性质不同 (1)final为关键字: (2)finalize()为方法: (3)finally为为区块标志,用于try语句中: 二.作用 (1)final为用于标识常量的关键字,final标识的关键字存储在常量池中(在这里final常量的具体用法将在下面进行介绍): (2)finalize()方法在Object中进行了定义,用于在对象"消失"时,由JVM进行调用用于对对象进行垃圾回收,类似于C++中的析构函数:用户自定义时,用于释放对象占用的资源(比如进行I/0操作): (3)fi

Java核心技术36讲----------谈谈final、finally、finalize有什么不同

一.final 1.final修饰方法时,需要注意的点: #final修饰方法时,之前的第二个原因是效率.但是如果方法过于庞大,可能看不到内嵌调用带来的任何性能提升.在最近的Java版本中,不需要使用final方法进行这些优化了." #因此,如果只有在想明确禁止 该方法在子类中被覆盖的情况下才将方法设置为final的.即父类的final方法是不能被子类所覆盖的,也就是说子类是不能够存在和父类一模一样的方法的 #要注意的一点是:因为重写的前提是子类可以从父类中继承此方法,如果父类中final修饰的

谈谈final、finally和finalize

final: final为修饰符, 如果类被声明为final,则不能派生新子类. 如果变量被声明为final,则必须在声明时初始化,在以后的引用只能读取,不可修改. 如果方法被final声明,则只能使用,不可重载. finally: finally用于异常处理中执行catch块后执行的语句块(如果该语句块存在). finalize: finalize为方法名,用于在垃圾收集器将对象删除之前对该对象调用的.

Java中final,finally和finalize区别

Day11_SHJavaTraing_4-18-2017 1.final-修饰符(关键字) ①final修饰类,表示该类不可被继承 ②final修饰函数,表示继承这个类的子类中不能重写这个函数 ③final修饰变量,表示该变量的值不可改变,必须在声明时给定初值.如果修饰的是引用类型的变量,则变量中保存的引用(地址)不可改变,但是引用指向的堆内存中的数据可以改变2.finally-在异常处理时finally代码块一定会被执行3.finalize-Object类的一个方法 使用finalize()方