“横看成岭侧成峰,远近高低各不同。不识庐山真面目,只缘身在此山中。”

这首诗来自于宋朝苏轼《题西林壁》,它的意思是,庐山从正面看,它是一道道连绵起伏的山岭;从侧面看,它是一座巍然耸立的险峰,而从远处、近处、高处、低处看,庐山又呈现各种不同的样子。

我们之所以认不清庐山真正的面目,是因为人身处在庐山之中。诗的意思是指同一个事物在不同的角度和不同的时间看是不一样的,指出我们在看待或者观察问题时应当客观全面,如果主观片面的看问题,就会得出不正确的结论。

final、finally、finalize这三个关键字长得很像,对于Android初学者或者Java初学者来说容易混淆,有时分不清楚该怎样正确的使用它们,并且它们也经常是某些公司面试基础知识中的重点,所以我们有必要来专项学习一下它。今天我就来总结一下它们的定义,使用场景,区别等,争取把它们所有相关的知识点都一次性讲明白,使大家都能够很好的掌握它们。

1、关于final

final是Java中的一个修饰关键字,它可以用来修改类,方法和变量。

(1)、如果用它来修饰类,即类被声明为final,意味着这个类不能再派生出新的子类,不能作为父类被继承。例如,String、StringBuilder、StringBuffer、Math等类。它和abstract(抽象)是互斥的,用abstract修饰的类是必须要继承才能实例化对象的,因此一个类不能既被声明为 abstract,又被声明为final。

(2)、而用final修饰变量或方法时,可以保证变量或方法在使用中不被改变。

被final修饰的变量必须在声明时给定初值,而在以后的使用中只能读取,不可修改,场景包括形参,局部变量,成员变量等情况。如果修饰的是基本数据类型,则初始化之后变量的值不能被改变;如果修饰的变量是引用类型,那么它只能指向初始化时指向的那个对象,不能再指向别的对象,但是对象当中的内容是允许改变的。

(3)、被final修饰的方法也同样只能使用,不能被重载,但是子类可以使用或调用父类中final修饰的方法。

(4)、final有一个特殊的使用场景。

当方法内部声明的类或者方法内定义的匿名内部类,访问该方法内定义的局部变量时,该变量必须要用final修饰。因为当内部类或内部匿名类访问方法的局部变量时,相当于扩大了局部变量的作用域,如果局部变量不用 final 修饰,我们就可以在内部类中随意修改该局部变量值,而在该局部变量的作用域范围之外是可以看到这些修改后的值,这样将会出现安全问题,所以必须用final修饰,不允许内部类或内部匿名类修改变量的值。而方法内部类或内部匿名类在访问该方法所在的类的成员变量时,却可以不用final修饰。

如下所示,

public class TestFinal {
String str1 = "no need final";
//匿名内部类
public void testAnonyClass() {
final String str2 = "need final"; new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
} System.out.println(str1);
System.out.println(str2); }
}).start();
} public void testInnerClass(){
final String str3 = "also need final";
//方法内部定义的内部类
class innerClass{
public void method1(){
System.out.println(str1);
System.out.println(str3);
}
}
}
}

如上所示str2在方法testAnonyClass中的匿名类中访问,它需要声明为final类型才可以,str3在方法testInnerClass中的内部类innerClass中访问,也同样需要声明为final。这两个方法中的内部类或内部匿名类在访问方法所在的类中的成员变量str1时,str1不需要声明为final。

2、关于finally

finally也是Java中的一个保留字,用在异常处理时,提供 finally代码块来执行最后的清除操作。

我们在写一段可能抛出异常的代码段时,如果我们希望捕获这个代码段中抛出的异常,那我们一般这样来写,

try {
//调用方法,期间可能抛出异常
//....
} catch (Exception e) {
e.printStackTrace();
} finally {
//可以进行一些清理
//....
}

如果抛出一个异常,那么相匹配的 catch 子句就会执行,然后最终控制会进入 finally代码块。

finally语句不会被执行的唯一情况是:先执行了用于终止程序的System.exit()方法,这个时候不会走到finally语句中,或者如果在执行过程中突然断电了,这时所有进程都会终止,也不会执行finally语句。

大家看一下如下demo,猜一猜打印的结果是什么?

public class TestFinally{
public int testFinally(){
try{
System.out.println("-----try-----");
return 1;
}finally{
System.out.println("-----finally-----");
return 2 ;
}
}
public static void main(String[]args){
TestFinally te= new TestFinally();
int t = te.testFinally();
System.out.println(t);
}
}

这里有两个return,按正常逻辑在try中调用return后,方法就返回了,但是因为下面有finally语句,并且其中也有一个return,所以最终应该返回finally语句中return对应的结果。

以上程序运行结果如下所示,

-----try-----

-----finally-----

2

如果注释掉finally语句中return,返回结果如下所示,

-----try-----

-----finally-----

1

可见finally中的语句永远都是要执行的。

3、关于finalize

finalize是Java中的一个方法名,它在Object类中定义,因此所有的类都继承了它。finalize() 方法的作用是在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。垃圾收集器在确定这个对象没有被引用时将调用此对象的finalize()方法,或者说finalize() 方法是在垃圾收集器删除对象之前对这个对象调用的。子类可以覆盖finalize() 方法从而整理自己定义的各类资源,或者执行资源清理工作。

使用场景,当销毁一个对象时,需要执行一些额外操作。例如,如果一个对象创建了一些非Java 资源,如文件句柄,window 字符字体或者数据库cursor等,这时你在这个对象被销毁前,要保证这些资源被安全释放。那如何保证呢?Java提供了一种收尾(finalization)机制,可以通过重写finalize() 方法来实现这种机制,在这种机制或者finalize() 方法中,可以将对象在进行垃圾回收前释放之前创建的其它资源。

在finalize ( )方法中,你要指定这个对象被撤消前必须执行的操作。系统的垃圾回收会周期性地运行,将由JVM的垃圾回收机制来控制,它会检查此对象是不是不再被运行状态引用或间接地引用。如果没有被引用,将会释放此对象,对应的inalize( ) 方法就会执行。

finalize()方法定义如下所示:

protected void finalize( )
{
// finalization code here
}

但是,finalize( )并不确保一个对象超出了它的作用域时就会执行,也就是说你不可能知道何时,甚至是否finalize( ) 被调用,因为这完全取决于系统的垃圾回收机制。所以,释放对象所创建的资源最好使用其它方法来实现,而不能仅仅依靠finalize( ) 来完成程序的资源释放工作。

finalize()在什么场景使用呢?

有三种情况

(1)、对象没有了直接和间接引用,垃圾回收器(garbage colector)决定回收某对象时,比如运行System.gc()的时候。

(2)、程序退出时为对象调用一次finalize方法。

(3)、显式的调用finalize方法。`

4、总结

由以上介绍,我们应该对final、finally、finalize有所了解了。对于它们的使用,还需要我们在工作中多摸索和多实践,这样才会理解的更加深刻,运用起来才会得心应手,才不会对它们产生混淆。



本公众号将以推送Android各种技术干货或碎片化知识,以及整理老司机日常工作中踩过的坑涉及到的经验知识为主,也会不定期将正在学习使用的新技术总结出来进行分享。每天一点干货小知识把你的碎片时间充分利用起来。

知识点干货--讲一讲final、finally、finalize的区别的更多相关文章

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

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

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

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

  3. 一、基础篇--1.1Java基础-final, finally, finalize 的区别

    final, finally, finalize 首先,这三个关键字没什么关联,只是放在一起比较像,用法用处完全不同. final: final关键字可以用来修饰类.方法.变量(成员变量和局部变量), ...

  4. final, finally, finalize的区别

    1.final 用于声明属性,方法和类,分别表示属性不可变,方法不可覆盖,类不可继承. 内部类要访问局部变量,局部变量必须定义成final类型 2.finally是异常处理语句结构的一部分,表示总是执 ...

  5. java中的final, finally, finalize的区别

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

  6. final, finally, finalize 的区别

    1.final 用于声明属性, 方法和类, 分别表示属性不可变, 方法不可覆盖, 类不可继承.内部类要访问局部变量, 局部变量必须定义成 final 类型, 例如, 一段代码…… 2.finally ...

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

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

  8. 2018.5.7每天一题面试题----final, finally, finalize 的区别

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

  9. 请解释final finally finalize的区别

    final  关键字 ,可以定义不能被继承的父类.定义不能被重写的方法,常量 finally   关键字, 异常处理的统一出口 不管是否有异常都执行 finalize   方法(protected   ...

  10. final, finally, finalize的区别?

    final 用于声明属性,方法和类,分别表示属性不可变,方法不可覆盖,类不可继承.内部类要访问局部变量,局部变量必须定义成final类型.finally是异常处理语句结构的一部分,表示总是执行.fin ...

随机推荐

  1. Number()和new Number()的区别以及一种简单实现

    看MDN Beginners文档的时候注意到了这种用法 var n1 = Number(123); , 冒出的第一个疑问就是和 var n2 = new Number(123); 有什么区别呢? 首先 ...

  2. mybatis-枚举类型的typeHandler&自定义枚举类型typeHandler

    MyBatis内部提供了两个转化枚举类型的typeHandler给我们使用. org.apache.ibatis.type.EnumTypeHandler 是使用枚举字符串名称作为参数传递的 org. ...

  3. java从文件中读取json

    wangxiaoer.json里面存放了json数据 需要依赖common-io.jar

  4. IE下常见的js兼容问题

    1.IE下不支持console.log() 2.IE下不支持addEventListener() 解决办法:用IE相应的attachEvent() 3.IE下请求后台接口会有缓存 解决方案,接口加版本 ...

  5. 【转】sed 学习笔记

    一  .  sed 简介 1  .  功能 sed 是一种流编辑器,所谓流编辑器是指能够对来自文件或者管道的输入流进行基本的文本转换的工具,比方说查找替换删除等. 2  .  最简单的运作机制 sed ...

  6. 10个实用的 Linux 网络和监控命令[转]

    本文列出了10个基础的每个Linux用户都应该知道的网络和监控命令.网络和监控命令类似于这些: hostname, ping, ifconfig, iwconfig, netstat, nslooku ...

  7. XML系列之--Linq操作带属性的XML(四)

    关于XML,之前解析过电文收发方面的,就是所谓的带表头.前缀(命名空间)SOAP格式.这次需求是解析一个xml的模板(xls内容),然后填充数据,最后保存.需要时可转换xls.pdf等文件.关于这种带 ...

  8. [DeeplearningAI笔记]改善深层神经网络_优化算法2.1_2.2_mini-batch梯度下降法

    觉得有用的话,欢迎一起讨论相互学习~Follow Me 2.1 mini-batch gradient descent mini-batch梯度下降法 我们将训练数据组合到一个大的矩阵中 \(X=\b ...

  9. [DeeplearningAI笔记]神经网络与深度学习2.11_2.16神经网络基础(向量化)

    觉得有用的话,欢迎一起讨论相互学习~Follow Me 2.11向量化 向量化是消除代码中显示for循环语句的艺术,在训练大数据集时,深度学习算法才变得高效,所以代码运行的非常快十分重要.所以在深度学 ...

  10. jQuery&Ajax应用

    jQuery对Ajax操作进行了封装,在jQuery中$.ajax()方法属于最底层的方法,第二层是load(),$.get()和$.post()方法,第三层是$.getScript(),$.getJ ...