• 朝花夕拾——finally/final/finalize拨云雾见青天


    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工作机制!



















  • 相关阅读:
    LAB8 android
    python3速查参考- python基础 1 -> python版本选择+第一个小程序
    selenium三种断言以及异常类型
    selenium+java:获取列表中的值
    selenium测试(Java)--元素操作(五)
    redhat网卡设置
    PYTHON TDD学习(一)-->Python 3.4版本环境安装Django及其启动
    渗透测试
    实用--功能测试方法与实际测试内容
    SQL常见面试题(学生表_课程表_总表)
  • 原文地址:https://www.cnblogs.com/blfbuaa/p/6915692.html
Copyright © 2020-2023  润新知