Java编程中。常常会使用到异常处理,而finally看似的是try/catch后对逻辑处理的完好,事实上里面却存在非常多隐晦的陷阱。final常见于变量修饰,那么你在内部类中也见过吧。finalize作为GC回收对象前的一道门,什么时候运行。运行效果又是如何。有时看看又忘了。以下是我总结网上朋友的一些博文及其帖子对三者进行总结。(重点讲下finally)

先看final

  • Final修饰变量不能被又一次赋值,其修饰实例变量时,定义时指定值则可视为“宏变量”。在非静态代码块和构造器中初始化值则不是。其修饰类变量时。仅仅有在定义时指定值才视为“宏变量”,在静态代码块中初始化则不是。

  • Final修饰的方法不能被重写
  • Final修饰的类不能被继承
  • 内部类一般使用final修饰的局部变量。

在看finalize

  • 系统调用finalize方法具有不确定性
  • finalize方法是protected方法。子类能够覆盖该方法以实现资源清理工作,GC在回收对象之前调用该方法。一般当对象在变成不可到达的时候,GC会推断是否覆盖该方法,假设没有覆盖就直接回收。假设覆盖就把该对象放进F-Queue队列并由一低优先级线程运行该对象的finalize方法,然后再次推断是否可达。
  • 尽量不要去调用finalize,假设调用。则避免对象再生,多用于关闭流。

最后细斟finally
  • Finall语句在return语句运行之后,return返回之前运行;
  • Finally块中的return语句运行结果覆盖try和catch中运行的return语句运行结果
  • Finally块中操作try/catch返回基本变量时。结果不受finally操作影响
  • Finally块中操作try/catch返回引用对象时。

    结果受finally操作影响

以下给出几个样例验证finally的4个重要观点

样例1代码例如以下:
package java_zhaohuaxishi;

public class Example1 {

	public int test(){
int i = 0;
try{
i = 10;
System.out.println("try");
return i+=10; }catch(Exception e){
i = 20;
return 200; }finally{
System.out.println("finally");
System.out.println(i);
} } /**
* @param args
*/
public static void main(String[] args) { // TODO Auto-generated method stub
System.out.println(new Example1().test()); } }

执行结果:

try
finally
20
20

这也意味着finally打印出来的是try中return已经计算了的,验证观点一。


样例2代码例如以下:
package java_zhaohuaxishi;

public class Example1 {

	public int test(){
int i = 0;
try{
i = 10;
return 100; }catch(Exception e){
i = 20;
return 200; }finally{
return i;
} } /**
* @param args
*/
public static void main(String[] args) { // TODO Auto-generated method stub
System.out.println(new Example1().test()); } }

上述时没有出现异常情况,打印例如以下:

10

再给出出现异常情况,代码例如以下:

package java_zhaohuaxishi;

public class Example2 {

	public int test(){
int i = 0;
try{
i = 10/0;
return 100; }catch(Exception e){
i = 20;
return 200; }finally{ return i;
} } /**
* @param args
*/
public static void main(String[] args) { // TODO Auto-generated method stub
System.out.println(new Example2().test()); } }

打印结果例如以下:

20

结果是:不管出现异常与否,finally的return总会覆盖try/catch中return的结果。验证观点二。


样例3代码例如以下:
package java_zhaohuaxishi;

public class Example5 {

	public int test(){
int i = 0;
try{
i = 10;
return i;
}catch(Exception e){
i = 20;
return i;
}finally{ i=30;
//return i;
}
} /**
* @param args
*/
public static void main(String[] args) { // TODO Auto-generated method stub
System.out.println(new Example5().test()); }
}

打印结果例如以下:

10

能够看到。实际上finally改动i变量是不起作用的。验证观点三。


样例4代码例如以下:
package java_zhaohuaxishi;

class Test{

	int num;

	public Test(int num){
this.num = num;
} public int getNum() {
return num;
} public void setNum(int num) {
this.num = num;
} } public class Example3 { public Test test(){
Test t = new Test(0);
try{
t.setNum(10); return t; }catch(Exception e){
t.setNum(20);
return t; }finally{ t.setNum(30);
} } /**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println(new Example3().test().getNum()); } }

打印结果例如以下:

30

从上述结果来看,finally操作的对象确实是与try上的同一个对象。那么我们比較上面观点三,操作变量的时候是不能更改的,想想有点诡异。我们看以下代码:

package java_zhaohuaxishi;

class Test{

	int num;
public Test(int num){
this.num = num;
} public int getNum() {
return num;
} public void setNum(int num) {
this.num = num;
} } public class Example3 { public int test(){ Test t = new Test(0); try{
t.setNum(10);
System.out.println(t.getNum());
return t.getNum(); }catch(Exception e){
t.setNum(20);
return t.getNum(); }finally{
System.out.println(t.getNum());
t.setNum(30);
} } /**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println(new Example3().test()); } }

这次我们不在返回对象。而是返回一个int变量。从观点一我们能够知道,返回的t.getNum()实际上是会先计算再保存起来。那么假设我们在finally中在去改变t的num,实际上t的num会被改变,然而返回的应该还是10。

打印结果例如以下:
10
30
10

果然!这与我们预先的是一模一样。假设有人认为finally中t对象可能与try中不一致。以下样例将会让你认为非常奇妙:

package java_zhaohuaxishi;

class Test4{

	int num;

	public Test4(int num){
this.num = num;
} public int getNum() {
return num;
} public void setNum(int num) {
this.num = num;
} } public class Example4 { public Test4 test(Test4 t){ System.out.println("传进去的t:"+t.hashCode()); try{
t.setNum(10); return t; }catch(Exception e){
t.setNum(20);
return t; }finally{
//t.setNum(30);
System.out.println("finally改动前:"+t.hashCode());
t = new Test4(0);
System.out.println("finally改动后:"+t.hashCode());
//return t;
} } /**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Test4 t = new Test4(0);
System.out.println("return返回对象"+new Example4().test(t).hashCode());
System.out.println("最后的t:"+t.hashCode()); } }
我们来看看打印结果:
传进去的t:2004703190
finally改动前:2004703190
finally改动后:1175576547
return返回对象2004703190
最后的t:2004703190

这结果看起来非常奇妙。我们验证观点四的时候操作对象是起作用的!然而当我们试图去改动t引用让他指向其它对象的时候居然无效......


如有很多其它兴趣深入了解。可进一步认识JVM工作机制!




























朝花夕拾——finally/final/finalize拨云雾见青天的更多相关文章

  1. 抽象类和接口 static final finalize

    抽象类 任何含有一个或多个抽象方法的类都必须声明成抽象类,用关键字abstract. 抽象类没有对象,即一个抽象类不能用new来直接实例化. 不能定义抽象构造方法或抽象静态方法.(但是可以创建父类引用 ...

  2. C# abstract virtual override new finally java final finalize

    virtual:声明虚方法.可以被其派生类所重写的.重写方法需要使用override或者new关键字. override:覆盖原方法.可对重写virtual.override.abstract进行重写 ...

  3. final/finalize/finally的区别

    一.性质不同 (1)final为关键字: (2)finalize()为方法:---垃圾回收机制中的方法(GC) (3)finally为为区块标志,用于try语句中: 二.作用 (1)final为用于标 ...

  4. final finalize finally throw throws try catch

    什么是finalize()方法 finalize()方法什么时候被调用 参见网址 析构函数(finalization)的目的是什么 final 和 finalize 的区别 final以下参见网址 f ...

  5. 关于Java异常和错误的几个问题

    1.Java中什么是Exception? 异常是Java传达给你的系统和程序错误的方式. 在java中,异常功能是通过实现比如Throwable,Exception,RuntimeException之 ...

  6. Java异常错误的面试题及答案

    1) Java中什么是Exception? 这个问题经常在第一次问有关异常的时候或者是面试菜鸟的时候问.我从来没见过面高级或者资深工程师的 时候有人问这玩意,但是对于菜鸟,是很愿意问这个的.简单来说, ...

  7. java异常面试常见题目

    在Java核心知识的面试中,你总能碰到关于 处理Exception和Error的面试题.Exception处理是Java应用开发中一个非常重要的方面,也是编写强健而稳定的Java程序的关键,这自然使它 ...

  8. java android面试题分析总结

    本文参考多处,一并感谢! http://www.blogjava.net/fanyingjie/archive/2007/06/27/126467.aspx http://baike.baidu.co ...

  9. 计算机本科/硕士找offer的总结 节选

    在这样的目标定位下,我的求职历程从2006年10月8日开始,到2007年1月10日正式结束,一共持续了3个月的时间.整个过程可以分为三个阶段:第一阶段:2006年10月份 找工作刚刚开始的阶段,什么都 ...

随机推荐

  1. Android 开源框架ViewPageIndicator 和 ViewPager 仿网易新闻客户端Tab标签

    转载请注明出处:http://blog.csdn.net/xiaanming/article/details/10766053 之前用JakeWharton的开源框架ActionBarSherlock ...

  2. 准确率99%!基于深度学习的二进制恶意样本检测——瀚思APT 沙箱恶意文件检测使用的是CNN,LSTM TODO

    所以我们的流程如图所示.将正负样本按 1:1 的比例转换为图像.将 ImageNet 中训练好的图像分类模型作为迁移学习的输入.在 GPU 集群中进行训练.我们同时训练了标准模型和压缩模型,对应不同的 ...

  3. centos7 usually use

    firewall-cmd --permanent --add-rich-rule 'rule family=ipv4 source address=192.168.22.103 port port=8 ...

  4. Microsoft Edge 首个 Chromium 内核版释出

    翻译功能释出 navigator.userAgent"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, ...

  5. function——函数声明头的提升和预解析

    函数: 即function语句的集合,就是将多个语句封装到一起: 函数的执行要会自己遍历,遇见函数 a():执行语句,就要移交控制权,函数执行完毕之后,控制权又移交回来了! 函数的参数要罗列在func ...

  6. 解决有关null闪退及json解析数据中null的问题

    程序在获取某些数据之后莫名崩溃.其实很早就发现了原因: 由于服务器的数据库中有些字段为空, 然后以Json形式返回给客户端时就会出现这样的数据: "somevalue":null ...

  7. 什么是2.5D与3D编辑模式

    ZBrush®其实就是一个带有三维特性的二维软件,它不仅具有绘制二维图像的功能,而且也具有对三维物体进行编辑的功能,就是所谓的2.5D(Pixol技术). 学习ZBrush之前有必要了解一下2.5D的 ...

  8. 第十一章 Python之异常处理

    异常 异常时程序运行时发生错误的信号(在程序错误时,则会产生一个异常,若程序没有处理,则会抛出该异常,程序的运行也随之终止) 常见的异常类型AttributeError 试图访问一个对象没有的树形,比 ...

  9. rem 自适应布局 bootstrap 移动端适配

    移动端适配用:rem 自使用布局用:bootstrap

  10. LeetCode Golang 5. 最长回文子串

    5. 最长回文子串 给定一个字符串 s,找到 s 中最长的回文子串.你可以假设 s 的最大长度为 1000. 示例 1: 输入: "babad" 输出: "bab&quo ...