[短文速讀 -6] final?finally?finalize?
這篇速讀文章來自面試的常客final、finally、finalize。說實話不大很理解為啥把這三者放在一起。這完全不相干啊!不過既來之則安之吧。
今天讓我們聊一聊final、finally、finalize各自的場景。
正題
引子
小A:MDove,我最近發現很多文章會把final、finally、finalize放在一起比較。恕我愚鈍,我實在不知道它們有什麼關係。
MDove:它們的關係你竟然看不出來?這不就是:這三者就是卡巴斯基、巴基斯坦和小丑巴基的關係,有個基巴關係!
小A:啊?......
MDove:它們三者的確沒有什麼關係,估計大家是看它們長得像,所以弄到一起去比較吧。今天咱們也別談三者的關係了,咱們就一個個聊一聊它們的特點。先從最常用的final開始:
final
MDove:對於我們來說final是很基礎的關鍵字。final可以用來修飾類、方法、變數 。
- 1、final修飾的class,代表不可以繼承擴充套件。
- 2、final的方法也是不可以重寫的。
- 3、final修飾的變數是不可以修改的。
MDove:咱們重點提一提第3點,這裡所謂的不可修改對於基本型別來來,的確是不可以修改。而對於引用型別來說,只能說不能重新賦值。也就是不能改變引用地址。但是作為引用型別,它內部所包含的內容如果不是final則可以隨意修改咯,就像:
final List<String> arryList = new ArrayList<>(); arryList.add("AAA"); arryList.add("BBB"); List<String> unmodifiableArrayList = List.of("AAA", "BBB"); unmodifiableArrayList.add("CCC"); 複製程式碼
MDove:final只能約束arryList這個引用不可以被重新賦值,但是arryList物件行為不被final影響,也就是說add是沒問題的。如果我們希望物件行為不可變,我們就需要使用List.of(),這個方法建立的物件本身就是不可變的,因此最後那句add是會在執行時丟擲異常的。
MDove:我們都知道final宣告的變數需要顯示的給它賦初始值的。這裡考考你,如果不想直接給它賦值,那應該怎麼做?
小A:我猜...需要在構造方法裡邊吧?
MDove:沒錯的確是這樣:
fianl int num; final int num2 = 666; public Test(){ num = 666; } 複製程式碼
MDove:前面的文章,我們有提到其實這倆種寫法,對於編譯的class檔案是等價的。
MDove:關於final,還有個有趣的地方。在很多文章中,會提到在特定場景下final能夠提高效能。比如:利用final可能有助於JVM將方法進行內聯,可以改善編譯器進行條件編譯的能力等等。說實話這種假設完全沒有考慮的必要。
finally
MDove:接下來讓我們來聊一聊finally。提到finally,那麼try-catch就逃不掉了。finally 則是Java保證重點程式碼一定要被執行的一種機制。最常用的地方:通過try-catch-finally來進行類似資源釋放、保證解鎖等動作。比如:
FileInputStream inputStream = null; try { inputStream = new FileInputStream(new File("test")); System.out.println(inputStream.read()); } catch (IOException e) { throw new RuntimeException(e.getMessage(), e); } finally { if (inputStream != null) { try { inputStream.close(); } catch (IOException e) { throw new RuntimeException(e.getMessage(), e); } } } 複製程式碼
MDove:這裡提一點,try-finally也是可以的。不過這裡個人不建議省略掉catch。因為前一段時間我們就踩到了這個坑。我們專案裡捕獲的異常,一般都會在catch裡通過Error的CallBack傳出去,打Log。那次我們在追一個Bug的時候,發現竟然什麼Log都沒有。後來才發現,出Bug的地方,try異常後沒有做任何處理直接finally,導致沒有辦法看到Log日誌,浪費了很多時間。
MDove:當然關於finally中釋放資源的操作,更推薦使用Java7中新增的try-with-resources語句。簡單,高效~比如:
try (FileInputStream inputStream = new FileInputStream(new File("test"))) { System.out.println(inputStream.read()); } catch (IOException e) { throw new RuntimeException(e.getMessage(), e); } 複製程式碼
這二者的寫法是等價的。當然這只是一種語法糖~
MDove:當然有些喪心病狂的題目,會問你什麼情況下finally不執行。這種情況就不執行了:
try { System.exit(1); } finally{ System.out.println(“程式都死了,我還執行個毛線~”); } 複製程式碼
MDove:可以看出,能導致程式停止的操作,finally都沒辦法執行了。說實話這真的沒有啥意義...
MDove:最後我們來聊一聊finalize。
finalize
MDove:說實話,我們日常開發中finalize用的並不多,而且也不被推薦使用。甚至在Java9中,明確將Object.finalize()標記為deprecated!
MDove:關於finalize說白了,它設計之初的作用就是:在CG要回收某個物件時,讓這個物件有底氣的大喊一聲:“報告,我還能再搶救一下!”。但是也正是因為如此,JVM要對它進行額外處理。finalize也就成為了CG回收的阻礙者,也就會導致這個物件經過多個垃圾收集週期才能被回收。
MDove:因為我自己對finalize瞭解也不是很深,所以關於finalize的內容就暫時讓我們止步於此。如果你還是感興趣,可以搜一搜相關的分析文章。
MDove:不知道一路捋到這,你是不是多少對這三者有了一些瞭解。實話實說,他們三者瞭解瞭解就完OJBK了,知道它們設計的初衷,瞭解它們的用法。可以靈活多變的應用到業務中就哦了。過分的追求一些“奇技淫巧”,反而失去了設計本身的意義。
小A:真是學無止境,我覺得我好想選錯了行業。