朝花夕拾——finally/final/finalize撥雲霧見青天
阿新 • • 發佈:2017-05-28
sim span 出現 能夠 eth font cte 影響 ont
在看finalize
最後細斟finally
樣例1代碼例如以下: 執行結果:
樣例2代碼例如以下:
再給出出現異常情況,代碼例如以下:
樣例3代碼例如以下:
樣例4代碼例如以下:
如有很多其它興趣深入了解。可進一步認識JVM工作機制!
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操作影響
樣例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撥雲霧見青天