【Java八股|第9篇】final、finally、finalize 区别详解
前言上一篇我们学习了 Java 异常体系其中提到了finally。这一篇继续学习一个名字非常相似、但含义完全不同的高频面试题final、finally、finalize有什么区别这三个单词长得很像但它们分别属于不同的知识点final是关键字finally是异常处理中的代码块finalize是Object类中的方法面试时如果只回答一句“一个是关键字一个是代码块一个是方法”显然不够。更完整的回答还要讲它们的使用场景、注意事项以及为什么现在不推荐使用finalize。这一篇我们就把它们一次讲清楚。一、先给结论可以先看这张表名称类型作用final关键字修饰类、方法、变量finally异常处理代码块通常用于释放资源finalizeObject 类方法对象被垃圾回收前可能调用已不推荐使用一句话总结final用来表示“不可变、不可继承、不可重写”等限制finally用在try-catch后面一般用于释放资源finalize是对象回收前可能执行的方法但不可靠实际开发中不推荐使用。二、final 是什么final是 Java 中的关键字。它可以修饰类方法变量不同位置含义不一样。三、final 修饰类当final修饰类时表示这个类不能被继承。比如publicfinalclassMyClass{}下面这种写法是错误的publicclassChildextendsMyClass{}因为MyClass是final类不能被继承。Java 中典型的final类有StringIntegerLongDouble比如String就是final类。这样做的一个重要原因是防止子类破坏原有设计。四、final 修饰方法当final修饰方法时表示这个方法不能被子类重写。父类publicclassParent{publicfinalvoidshow(){System.out.println(父类 show 方法);}}子类publicclassChildextendsParent{Overridepublicvoidshow(){System.out.println(子类 show 方法);}}这段代码会编译报错。因为父类的show方法被final修饰子类不能重写它。适合使用final方法的场景不希望核心逻辑被子类修改模板方法中某些步骤固定安全性要求较高的方法五、final 修饰变量final修饰变量时表示这个变量只能被赋值一次。1. 修饰基本数据类型finalintnum10;num20;第二次赋值会报错。因为num被final修饰后值不能再改变。2. 修饰引用数据类型finalListStringlistnewArrayList();list.add(Java);list.add(MySQL);这段代码是可以的。但是下面这样不行listnewArrayList();原因是final修饰引用类型时限制的是引用地址不能改变不代表对象内部内容不能改变。也就是说list不能再指向新的集合对象但原集合中的内容仍然可以修改。这是面试中非常容易问到的点。六、final 修饰常量final经常和static一起使用表示常量。publicclassConstants{publicstaticfinalStringSUCCESSsuccess;publicstaticfinalIntegerPAGE_SIZE10;}这里publicstaticfinal表示全局常量。命名习惯一般是全部大写单词之间用下划线比如publicstaticfinalStringDEFAULT_PASSWORD123456;在项目中常量可以避免魔法值散落在代码中。不推荐if(success.equals(result)){}更推荐if(Constants.SUCCESS.equals(result)){}七、final 参数方法参数也可以用final修饰。publicvoidprint(finalStringname){System.out.println(name);// name 李四; // 不能重新赋值}这里表示方法内部不能修改参数变量的引用。不过现在实际开发中方法参数加final并不是必须更多是编码风格选择。八、finally 是什么finally是异常处理中的代码块。它通常和try-catch一起使用。基本格式try{// 可能出现异常的代码}catch(Exceptione){// 异常处理}finally{// 最后执行的代码}示例publicclassTest{publicstaticvoidmain(String[]args){try{intresult10/0;System.out.println(result);}catch(Exceptione){System.out.println(出现异常);}finally{System.out.println(finally 执行);}}}输出出现异常 finally 执行finally的作用一般是释放资源比如关闭文件流、数据库连接、网络连接等。九、finally 一定会执行吗大多数情况下finally都会执行。比如即使方法中有returnfinally也会执行。publicstaticinttest(){try{return1;}finally{System.out.println(finally 执行);}}调用System.out.println(test());输出finally 执行 1但是有些极端情况下finally不会执行。比如try{System.exit(0);}finally{System.out.println(finally 执行);}System.exit(0)会直接退出 JVM所以finally不会执行。所以更准确的说法是finally通常会执行但不是绝对一定执行。十、finally 中不要随便 return看下面这个例子publicstaticinttest(){try{return1;}finally{return2;}}调用System.out.println(test());输出2因为finally中的return覆盖了try中的return。这会让代码变得很难理解。所以实际开发中不建议在finally中写return。同样也不建议在finally中随便抛出新的异常覆盖原异常。十一、try-with-resources 替代 finally 关闭资源以前关闭流可能这样写FileInputStreamfisnull;try{fisnewFileInputStream(a.txt);intdatafis.read();System.out.println(data);}catch(IOExceptione){e.printStackTrace();}finally{if(fis!null){try{fis.close();}catch(IOExceptione){e.printStackTrace();}}}代码比较繁琐。现在更推荐使用try-with-resourcestry(FileInputStreamfisnewFileInputStream(a.txt)){intdatafis.read();System.out.println(data);}catch(IOExceptione){e.printStackTrace();}只要资源实现了AutoCloseable接口就可以自动关闭。这也是现代 Java 中更推荐的资源释放方式。十二、finalize 是什么finalize是Object类中的一个方法。以前它的作用是在对象被垃圾回收之前可能会被 JVM 调用。示例publicclassUser{Overrideprotectedvoidfinalize()throwsThrowable{System.out.println(对象即将被回收);}}但是现在实际开发中不推荐使用finalize。原因有几个它什么时候执行不确定它不一定会执行会影响垃圾回收效率容易导致资源释放不及时新版本 Java 中已经逐渐废弃所以面试时可以明确说finalize现在已经不推荐使用资源释放应该使用try-with-resources或显式关闭。十三、为什么 finalize 不可靠假设我们写了Overrideprotectedvoidfinalize()throwsThrowable{System.out.println(释放资源);}这并不能保证资源一定会及时释放。因为垃圾回收什么时候发生不由程序精确控制。即使对象变成垃圾也不代表马上会被回收。而且 JVM 也不保证finalize一定会被执行。所以如果把文件关闭、数据库连接释放等重要逻辑放到finalize中就很危险。正确做法应该是try-with-resources或者手动调用close()十四、final、finally、finalize 面试回答如果面试官问final、finally、finalize有什么区别可以这样回答final是 Java 关键字可以修饰类、方法和变量。修饰类表示不能被继承修饰方法表示不能被重写修饰变量表示只能赋值一次。如果修饰引用类型表示引用地址不能改变但对象内部内容仍然可能改变。finally是异常处理中的代码块一般和try-catch一起使用通常用于释放资源。大多数情况下finally都会执行但如果 JVM 退出比如调用System.exit()它就不会执行。实际开发中不建议在finally中写return。finalize是Object类中的方法对象被垃圾回收前可能会调用。但它执行时机不确定也不保证一定执行已经不推荐使用。资源释放应该使用try-with-resources或显式关闭资源。十五、常见问题总结1. final 修饰对象对象内容还能改吗可以。比如finalListStringlistnewArrayList();list.add(Java);这是允许的。final限制的是list不能再指向新对象。2. final 类能不能被继承不能。比如String就是final类。3. final 方法能不能重写不能。子类不能重写父类的final方法。4. finally 一定执行吗大多数情况下会执行但不是绝对。如果 JVM 直接退出比如System.exit(0)finally不会执行。5. finalize 推荐使用吗不推荐。它不可靠执行时机不确定也不保证一定执行。十六、实际开发建议实际开发中可以记住下面几点常量使用public static final不希望被继承的类可以用final不希望被重写的方法可以用finalfinal修饰引用类型时对象内部内容仍可能改变finally常用于释放资源不要在finally中写return关闭资源优先使用try-with-resources不要依赖finalize释放资源十七、总结这一篇主要学习了final、finally、finalize的区别。final是关键字用来修饰类、方法、变量finally是异常处理中的代码块通常用于释放资源finalize是Object类中的方法对象被垃圾回收前可能调用但现在已经不推荐使用。这三个名字很像但属于完全不同的知识点。面试回答时要先说明它们的类型再分别说明作用和注意事项。下一篇我们继续学习 Java 中的包装类和自动拆装箱。