天天看點

大廠面試官問你知道final、finally、finalize有什麼差別?

前言

Java程式員面試,基礎真的很重要。基礎這東西,各個公司都很看重,尤其是大公司,他們看中人的潛力,他們舍得花精力去培養,是以基礎是重中之重。之前很多人問我,項目經曆少怎麼辦,那就去打牢基礎,當你的基礎好的發指的時候,你的其他東西都不重要了。

Java 語言有很多看起來很相似,但是用途卻完全不同的語言要素,這些内容往往容易成為面試官考察你知識掌握程度的切入點。

今天,我要問你的是一個經典的 Java 基礎題目,談談 final、finally、 finalize 有什麼不同?

大廠面試官問你知道final、finally、finalize有什麼差別?

典型回答

final 可以用來修飾類、方法、變量,分别有不同的意義,final 修飾的 class 代表不可以繼承擴充,final 的變量是不可以修改的,而 final 的方法也是不可以重寫的(override)。

finally 則是 Java 保證重點代碼一定要被執行的一種機制。我們可以使用 try-finally 或者 try-catch-finally 來進行類似關閉 JDBC 連接配接、保證 unlock 鎖等動作。

finalize 是基礎類 java.lang.Object 的一個方法,它的設計目的是保證對象在被垃圾收集前完成特定資源的回收。finalize 機制現在已經不推薦使用,并且在 JDK 9 開始被标記為 deprecated。

考點分析

這是一個非常經典的 Java 基礎問題,我上面的回答主要是從文法和使用實踐角度出發的,其實還有很多方面可以深入探讨,面試官還可以考察你對性能、并發、對象生命周期或垃圾收集基本過程等方面的了解。

對于final

推薦使用 final 關鍵字來明确表示我們代碼的語義、邏輯意圖,這已經被證明在很多場景下是非常好的實踐,比如:

我們可以将方法或者類聲明為 final,這樣就可以明确告知别人,這些行為是不許修改的。

如果你關注過 Java 核心類庫的定義或源碼, 有沒有發現 java.lang 包下面的很多類,相當一部分都被聲明成為 final class?在第三方類庫的一些基礎類中同樣如此,這可以有效避免 API 使用者更改基礎功能,某種程度上,這是保證平台安全的必要手段。

使用 final 修飾參數或者變量,也可以清楚地避免意外指派導緻的程式設計錯誤,甚至,有人明确推薦将所有方法參數、本地變量、成員變量聲明成 final。

final 變量産生了某種程度的不可變(immutable)的效果,是以,可以用于保護隻讀資料,尤其是在并發程式設計中,因為明确地不能再指派 final 變量,有利于減少額外的同步開銷,也可以省去一些防禦性拷貝的必要。

final 也許會有性能的好處,很多文章或者書籍中都介紹了可在特定場景提高性能,比如,利用 final 可能有助于 JVM 将方法進行内聯,可以改善編譯器進行條件編譯的能力等等。

坦白說,很多類似的結論都是基于假設得出的,比如現代高性能 JVM(如 HotSpot)判斷内聯未必依賴 final 的提示,要相信 JVM 還是非常智能的。類似的,final 字段對性能的影響,大部分情況下,并沒有考慮的必要。

從開發實踐的角度,我不想過度強調這一點,這是和 JVM 的實作很相關的,未經驗證比較難以把握。我的建議是,在日常開發中,除非有特别考慮,不然最好不要指望這種小技巧帶來的所謂性能好處,程式最好是展現它的語義目的。如果你确實對這方面有興趣,可以查閱相關資料,我就不再贅述了,不過千萬别忘了驗證一下。

對于 finally

明确知道怎麼使用就足夠了。需要關閉的連接配接等資源,更推薦使用 Java 7 中添加的 try-with-resources 語句,因為通常 Java 平台能夠更好地處理異常情況,編碼量也要少很多,何樂而不為呢。

注意事項

finally代碼不會被執行的特例:

大廠面試官問你知道final、finally、finalize有什麼差別?

final修飾的List,不會影響其行為:

大廠面試官問你知道final、finally、finalize有什麼差別?

final隻能限制strList這個引用不可以被指派,但是strList對象行為不被final影響,添加元素的操作是完全正常的。如果我們真的希望對象本身是不可變的,那麼需要相應的類支援不可變的行為。

在上面的例子中,List.of方法建立的就是不可變List,最後那句add會在運作時抛出異常。

Java平台目前在逐漸使用java.lang.ref.Cleaner來替換掉原來的finalize實作。

對于 finalize

我們要明确它是不推薦使用的,業界實踐一再證明它不是個好的辦法,在 Java 9 中,甚至明确将 Object.finalize() 标記為 deprecated!如果沒有特别的原因,不要實作 finalize 方法,也不要指望利用它來進行資源回收。

為什麼呢?簡單說,你無法保證 finalize 什麼時候執行,執行的是否符合預期。使用不當會影響性能,導緻程式死鎖、挂起等。

通常來說,利用上面的提到的 try-with-resources 或者 try-finally 機制,是非常好的回收資源的辦法。如果确實需要額外處理,可以考慮 Java 提供的 Cleaner 機制或者其他替代方法。