Java中final、finally、finalize的区别与用法

1.简单区别:
final用于声明属性,方法和类,分别表示属性不可交变,方法不可覆盖,类不可继承。
finally是异常处理语句结构的一部分,表示总是执行。
finalize是Object类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法,供垃圾收集时的其他资源回收,例如关闭文件等。
2.中等区别:
虽然这个单词在Java中都存在,但是并没太多关联:
final:java中的关键字,修饰符。
A).如果一个类被声明为final,就意味着它不能再派生出新的子类,不能作为父类被继承。因此,一个类不能同时被声明为abstract抽象类的和final的类。
B).如果将变量或者方法声明为final,可以保证它们在使用中不被改变.
  1)被声明为final的变量必须在声明时给定初值,而在以后的引用中只能读取,不可修改。
  2)被声明final的方法只能使用,不能重载。
finally:java的一种异常处理机制。
  finally是对Java异常处理模型的最佳补充。finally结构使代码总会执行,而不管无异常发生。使用finally可以维护对象的内部状态,并可以清理非内存资源。特别是在关闭数据库连接这方面,如果程序员把数据库连接的close()方法放到finally中,就会大大降低程序出错的几率。
finalize:Java中的一个方法名。
Java技术使用finalize()方法在垃圾收集器将对象从内存中清除出去前,做必要的清理工作。这个方法是由垃圾收集器在确定这个对象没被引用时对这个对象调用的。它是在Object类中定义的,因此所的类都继承了它。子类覆盖finalize()方法以整理系统资源或者执行其他清理工作。finalize()方法是在垃圾收集器删除对象之前对这个对象调用的。
3.详细区别:
这是一道再经典不过的面试题了,我们在各个公司的面试题中几乎都能看到它的身影。final、finally和finalize虽然长得像孪生兄弟一样,但是它们的含义和用法却是大相径庭。
final关键字我们首先来说说final。它可以用于以下四个地方:
1).定义变量,包括静态的和非静态的。
2).定义方法的参数。
3).定义方法。
4).定义类。
定义变量,包括静态的和非静态的。定义方法的参数
第一种情况:
  如果final修饰的是一个基本类型,就表示这个变量被赋予的值是不可变的,即它是个常量;
  如果final修饰的是一个对象,就表示这个变量被赋予的引用是不可变的
这里需要提醒大家注意的是,不可改变的只是这个变量所保存的引用,并不是这个引用所指向的对象。
第二种情况:final的含义与第一种情况相同。
实际上对于前两种情况,一种更贴切的表述final的含义的描述,那就是,如果一个变量或方法参数被final修饰,就表示它只能被赋值一次,但是JAVA虚拟机为变量设定的默认值不记作一次赋值。被final修饰的变量必须被初始化。初始化的方式以下几种:    
1.在定义的时候初始化。    
2.final变量可以在初始化块中初始化,不可以在静态初始化块中初始化。
3.静态final变量可以在定义时初始化,也可以在静态初始化块中初始化,不可以在初始化块中初始化。    
4.final变量还可以在类的构造器中初始化,但是静态final变量不可以。
通过下面的代码可以验证以上的观点:

public class FinalTest{public final int A=10; //在定义时初始化public final int B;{B=20;} //在初始化块中初始化//非静态final变量不能在静态初始化块中初始化    //public final int C;static{//C=30; }//静态常量,在定义时初始化public static final int STATIC_D=40;//静态常量,在静态初始化块中初始化public static final int STATIC_E;static{STATIC_E = 50;}//静态变量不能在初始化块中初始化    //public static final int  STATIC_F;{STATIC_F=60;}public final int G;//静态final变量不可以在构造器中初始化    //public static final int STATIC_H;//在构造器中初始化         public finalTest(){G=70;//静态final变量不可以在构造器中初始化//STATIC_H=80;//给final的变量第二次赋值时,编译会报错//A=99;//STATIC_D=99;}//final变量未被初始化,编译时就会报错//public final int L;//静态final变量未被初始化,编译时就会报错//public static final int STATIC_J;
}

我们运行上面的代码之后出了可以发现final变量(常量和静态final变量(静态常量被初始化时,编译会报错。
用final修饰的变量(常量比非final的变量(普通变量拥更高的效率,因此我们在际编程中应该尽可能多的用常量来代替普通变量。
定义方法
当final用来定义一个方法时,它表示这个方法不可以被子类重写,但是并不影响它被子类继承。我们写段代码来验证一下:

public class ParentClass{public final void TestFinal(){System.out.println("父类--这是一个final方法");}
}
public class SubClass extends ParentClass{//子类无法重写(override父类的final方法,否则编译时会报错/* public void TestFinal(){System.out.println("子类--重写final方法");} */   public static void main(String[]args){SubClass sc = new SubClass();sc.TestFinal();}
}    

这里需要特殊说明的是,具有private访问权限的方法也可以增加final修饰,但是由于子类无法继承private方法,因此也无法重写它。编译器在处理private方法时,是照final方来对待的,这样可以提高该方法被调用时的效率。不过子类仍然可以定义同父类中private方法具同样结构的方法,但是这并不会产生重写的效果,而且它们之间也不存在必然联系。
定义类
最后我们再来回顾一下final用于类的情况。这个大家应该也很熟悉了,因为我们最常用的String类就是final的。由于final类不允许被继承,编译器在处理时把它的所方法都当作final的,因此final类比普通类拥更高的效率。而由关键字abstract定义的抽象类含必须由继承自它的子类重载实现的抽象方法,因此无法同时用final和abstract来修饰同一个类。同样的道理,
final也不能用来修饰接口。 final的类的所方法都不能被重写,但这并不表示final的类的属性(变量值也是不可改变的,要想做到final类的属性值不可改变,必须给它增加final修饰,请看下面的例子:

public final class FinalTest{int i =20;final int j=50;public static void main(String[] args){FinalTest ft = new FinalTest();ft.i = 99;/*final类FinalTest的属性值 i是可以改变的,因为属性值i前面没final修饰*///ft.j=49;//报错....因为j属性是final的不可以改变。
          System.out.println(ft.i);}
}        

运行上面的代码试试看,结果是99,而不是初始化时的10。
finally语句
接下来我们一起回顾一下finally的用法。finally只能用在try/catch语句中并且附带着一个语句块,表示这段语句最终总是被执行。请看下面的代码:

public final class FinallyTest{public static void main(String[] args){try{throw new NullPointerException();}catch(NullPointerException e){System.out.println("程序抛出了异常");}finally{//这里总会被执行,不受break,return影响另如数据库连接的close()一般写在这里,可以降低程序的出错几率System.out.println("执行了finally语句块");}}
}

运行结果说明了finally的作用:

1.程序抛出了异常

2.执行了finally语句块请大家注意,捕获程序抛出的异常之后,既不加处理,也不继续向上抛出异常,并不是良好的编程习惯,它掩盖了程序执行中发生的错误,这里只是方便演示,请不要学习。
那么,没一种情况使finally语句块得不到执行呢?
return、continue、break这个可以打乱代码顺序执行语句的规律。那我们就来试试看,这个语句是否能影响finally语句块的执行:

public final class FinallyTest {//测试return语句//结果显示:编译器在编译return new ReturnClass();时,//将它分成了两个步骤,new ReturnClass()和return,前一个创建对象的语句是在finally语句块之前被执行的,//而后一个return语句是在finally语句块之后执行的,也就是说finally语句块是在程序退出方法之前被执行的public ReturnClass testReturn() {try {return new ReturnClass();} catch (Exception e) {e.printStackTrace();} finally {System.out.println("执行了finally语句");}return null;}//测试continue语句public void testContinue(){for(int i=0; i<3; i++){try {System.out.println(i);if(i == 1){System.out.println("con");}} catch(Exception e) {e.printStackTrace();} finally {System.out.println("执行了finally语句");}}}//测试break语句public void testBreak() {for (int i=0; i<3; i++) {try {System.out.println(i);if (i == 1) {break;}} catch (Exception e) {e.printStackTrace();} finally {System.out.println("执行了finally语句");}}}public static void main(String[] args) {FinallyTest ft = new FinallyTest();// 测试return语句
        ft.testReturn();System.out.println();// 测试continue语句
        ft.testContinue();System.out.println();// 测试break语句
        ft.testBreak();}
}class ReturnClass {public ReturnClass() {System.out.println("执行了return语句");}
}

上面这段代码的运行结果如下:
执行了return语句
执行了finally语句0
执行了finally语句
1
con
执行了finally语句
2
执行了finally语句0
执行了finally语句
1
执行了finally语句

很明显,return、continue和break都没能阻止finally语句块的执行。从输出的结果来看,return语句似乎在finally语句块之前执行了,事实真的如此吗?我们来想想看,return语句的作用是什么呢?是退出当前的方法,并将值或对象返回。如果 finally语句块是在return语句之后执行的,那么return语句被执行后就已经退出当前方法了,finally语句块又如何能被执行呢?因此,正确的执行顺序应该是这样的:编译器在编译return new ReturnClass();时,将它分成了两个步骤,new ReturnClass()和return,前一个创建对象的语句是在finally语句块之前被执行的,而后一个return语句是在finally语句块之后执行的,也就是说finally语句块是在程序退出方法之前被执行的。同样,finally语句块是在循环被跳过(continue和中断(break之前被执行的
finalize方法
最后,我们再来看看finalize,它是一个方法,属于java.lang.Object类,它的定义如下:protected void finalize()throws Throwable{}众所周知,finalize()方法是GC(garbagecollector运行机制的一部分,在此我们只说说finalize()方法的作用是什么呢?finalize()方法是在GC清理它所从属的对象时被调用的,如果执行它的过程中抛出了无法捕获的异常(uncaughtexception,GC将终止对改对象的清理,并且该异常会被忽略;直到下一次GC开始清理这个对象时,它的finalize()会被再次调用。请看下面的示例:

public final class FinallyTest{//重写finalize()方法protected void finalize() throws Throwable{System.out.println("执行了finalize()方法");}public static void main(String[] args){FinallyTest ft = new FinallyTest();ft = null;System.gc();}
}

运行结果如下:• 执行了finalize()方法
程序调用了java.lang.System类的gc()方法,引起GC的执行,GC在清理ft对象时调用了它的finalize()方法,因此才了上面的输出结果。调用System.gc()等同于调用下面这行代码:Runtime.getRuntime().gc();调用它们的作用只是建议垃圾收集器(GC启动,清理无用的对象释放内存空间,但是GC的启动并不是一定的,这由JAVA虚拟机来决定。直到 JAVA虚拟机停止运行,些对象的finalize()可能都没被运行过,那么怎样保证所对象的这个方法在JAVA虚拟机停止运行之前一定被调用呢?答案是我们可以调用System类的另一个方法:

public static void FunFinalizersOnExit(boolean value){//othercode
}  

给这个方法传入true就可以保证对象的finalize()方法在JAVA虚拟机停止运行前一定被运行了,不过遗憾的是这个方法是不安全的,它会导致有用的对象finalize()被误调用,因此已不被赞成使用了。由于finalize()属于Object类,因此所类都这个方法,Object的任意子类都可以重写(override该方法,在其中释放系统资源或者做其它的清理工作,如关闭输入输出流。通过以上知识的回顾,我想大家对于final、finally、finalize的用法区别已经很清楚了。

转载于:https://www.cnblogs.com/mytzq/p/11125888.html

转 Java中final、finally、finalize的区别与用法相关推荐

  1. [转载] java中final,finally,finalize三者的作用和区别

    参考链接: Java中final,finally和finalize Final是一个修饰符: 当final修饰一个变量的时候,变量变成一个常量,它不能被二次赋值 当final修饰的变量为静态变量(即由 ...

  2. java final 变量 回收_java入门教程-Java中final,finally,finalize三个关键字的区别

    final 当这个关键字修饰一个类时,意味着他不能派生出新的子类,也就是说不能被继承,因此一个类不能被同时声明为abstract和final.当final修饰变量或者方法时,可以保证他们在使用中不会被 ...

  3. java中throws和throw的区别和用法

    1.throws关键字通常被应用在声明方法时,用来指定可能抛出的异常.多个异常可以使用逗号隔开.当在主函数中调用该方法时,如果发生异常,就会将异常抛给指定异常对象.如下面例子所示: public cl ...

  4. Java中print()\println()\printf()的区别及用法

    print()\println()\printf()的区别: print将它的参数显示在命令窗口,并将输出光标定位在所显示的最后一个字符之后. println 将它的参数显示在命令窗口,并在结尾加上换 ...

  5. 【面试常问】Java中final和finally以及finalize区别?

    说一下final和finally以及finalize区别? 在面试中如果问到这个问题,我们应该咋么回答呢?我就写一下我的看法如有错误还请个位指正! 文章目录 说一下final和finally以及fin ...

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

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

  7. final, finally, finalize 的区别

    本文转自 一.总体区别 final 用于申明属性,方法和类,表示属性不可变,方法不可以被覆盖,类不可以被继承. finally 是异常处理语句结构中,表示总是执行的部分. finallize 表示是o ...

  8. java中final是什么意思_java中final、finali、finally三者之间的区别是什么

    java中final.finali.finally三者之间的区别是什么 发布时间:2020-06-22 11:03:25 来源:亿速云 阅读:152 作者:Leah java中final.finali ...

  9. JAVA中Final的用法

    JAVA中Final的用法 1. 修饰基础数据成员的final 这是final的主要用途,其含义相当于C/C++的const,即该成员被修饰为常量,意味着不可修改.如java.lang.Math类中的 ...

最新文章

  1. 技术图文:集合技术在求解算法题中的应用
  2. 第28篇 js中let和var
  3. 菜鸟学习笔记3——jQuery 选择器
  4. 通信电子线路期末复习第三章正弦波振荡器
  5. Visual Studio registry capture utility 已停止工作的解决办法
  6. SM13: 分析SAP事务提交时的FM调用
  7. SpringBoot快速入门——helloworld(来自官网)
  8. Linux初学时的一些常用命令(4)
  9. c语言分配多一个字符空间,关于C语言动态给字符串分配内存空间问题
  10. CentOS6.4系统启动失败故障排查
  11. 【Matplotlib】【Python】如何使用matplotlib绘制散点图
  12. openfire User Service 和删除分组的方法
  13. side-by-side
  14. 杀破狼java_终于把《杀破狼》看完了
  15. 暑假计划(7月23日-8月21日)
  16. network 节点label以及相关字体设置
  17. 手机会员积分 html,会员积分系统主要有什么作用和功能?
  18. 执教《送给盲婆婆的蝈蝈》有感
  19. 海思软件开发入门篇 (一)
  20. uni-app ios 苹果真机或安卓机运行

热门文章

  1. Flask对请求的处理
  2. 信息安全系统设计基础_exp1
  3. js中document.write()使用方法
  4. Android按两次返回键退出应用
  5. /usr/bin/ld: cannot find -lfontconfig解决方法
  6. 天气预报中的风向到底有啥用?
  7. Java spark中的各种范型接口Function的区别(持续更新中)
  8. subprocess installed post-installation script returned error exit status 127
  9. Tez UI界面一直处于loading
  10. gulp加速hexo的yelee主题