1. 程式人生 > >朝花夕拾——finally/final/finalize撥雲霧見青天

朝花夕拾——finally/final/finalize撥雲霧見青天

sim span 出現 能夠 eth font cte 影響 ont

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撥雲霧見青天