zoukankan      html  css  js  c++  java
  • 朝花夕拾——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工作机制!



















  • 相关阅读:
    A1052. Linked List Sorting (25)
    A1032. Sharing (25)
    A1022. Digital Library (30)
    A1071. Speech Patterns (25)
    A1054. The Dominant Color (20)
    A1060. Are They Equal (25)
    A1063. Set Similarity (25)
    电子码表
    矩阵键盘
    对象追踪、临时对象追踪、绝对坐标与相对坐标
  • 原文地址:https://www.cnblogs.com/blfbuaa/p/6915692.html
Copyright © 2011-2022 走看看