JavaRush /Java Blog /Random-TW /訪談中有關連載的 13 個常見問題
Dmitry Vasilyev
等級 26
Саратов

訪談中有關連載的 13 個常見問題

在 Random-TW 群組發布
文章翻譯https://javarevisited.blogspot.com/2011/04/top-10-java-serialization-interview.html Java中的序列化是什麼?序列化是重要的概念之一,很少用作保存程式狀態的解決方案,因此該 API 經常被開發人員忽略。然而,根據我的經驗,序列化在任何基礎 Java 面試中都是一個非常重要的主題。我遇到的幾乎每次面試都會涉及一兩個有關連載的問題,而且我發現應徵者在問了幾個有關該主題的問題後,會因為自己缺乏這方面的經驗而感到不舒服。他們不知道如何在Java中序列化一個對象,他們不熟悉任何序列化的例子,無法解釋其工作機制,瞬態變數和易失性變數之間的區別,他們不知道Serialized介面有多少方法有。什麼是標記介面?它的目的是什麼?Java 中的外部化和序列化實作有什麼不同?為什麼java引入註解後不把Serialized替換成@Serialized呢?在本文中,我們將涵蓋針對初學者和高級開發人員的問題,這些問題對每個人(從初級開發人員到高級開發人員)同樣有用。大多數商業專案使用資料庫、記憶體映射檔案或只是普通的平面檔案來提供更高的穩健性,但很少有專案依賴 Java 的序列化過程。無論如何,這篇文章不是教程 - 它是關於在參加任何 Java 面試之前值得自己澄清的問題,並對自己不熟悉的術語感到驚訝。對於那些完全不熟悉 Java 序列化的人:「Java 中的序列化是一個透過將物件的狀態儲存在副檔名為 .ser 的檔案中並重新建立物件的狀態來序列化Java中的物件的過程。從這個文件。這個相反的過程稱為反序列化。 塞普卡 Java Serialization API 為開發人員提供了使用 Serialized 和Externalized 介面序列化物件的標準機制。順便說一句,這篇文章是我(不是我,譯者,而是英文原文作者)之前文章的延續:設計模式的20道面試題Java中單例模式的10道面試題。那麼,我們走吧! Java中的序列化是什麼? Java 中的物件序列化是用於將物件轉換為二進位格式的過程,該二進位格式可以儲存到磁碟或透過網路傳送到任何其他正在執行的 Java 虛擬機器;從二進位流創建物件的逆過程稱為反序列化。Java提供了API,其中包括java.io.Serialized、java.io.Externalizable、ObjectInputStream和ObjectOutputStream等。程式設計師可以自由使用Java基於類別結構使用的預設序列化機制,但他們也可以使用自己的自訂二進位格式,這通常被推薦為序列化最佳實踐,因為序列化二進位格式成為類別匯出API的一部分並且可能會破壞Java 中私有和包私有欄位提供的封裝。一般來說,這些資訊足以開始使用。 如何使 Java 類別可序列化? 這很容易。您的類別只需要實作 java.io.Serialized 接口,JVM 將負責以預設格式序列化物件。應該簡短地做出創建可序列化類別的決定,因為雖然創建可序列化類別的短期成本很低,但長期成本卻很高,並且可能會限制您對實現進行進一步修改的能力。發生這種情況的原因是,與任何公共API 一樣,物件的序列化形式成為公共API 的一部分,並且當您透過實作新增介面來變更類別的結構時,新增或刪除任何欄位都可能會破壞預設序列化。不過,可以透過使用自訂二進位格式來最大程度地減少這種情況,但仍需要付出很大的努力來確保向後相容性。SerialVersionUID 欄位是序列化如何限制您修改類別的能力的一個範例。如果您沒有明確聲明 SerialVersionUID,那麼虛擬機會根據類別結構產生它,這取決於類別實現的介面以及其他幾個可以更改的因素。假設您實作了與 JVM 不同的接口,它將為新版本的類別檔案產生不同的 SerialVersionUID,並且當您嘗試載入由舊版本程式序列化的舊物件時,您將得到一個無效類別異常。 問題1)Java中Serialized介面和Externalized介面有什麼差別? 這是最常見的 Java 序列化面試問題。Externalized介面為我們提供了writeExternal()和readExternal()方法,這使我們能夠靈活地控制序列化,而不是依賴預設的機制。正確實作Externalized介面可以顯著提高應用程式效能。 問題2)Serialized有多少個方法?如果沒有方法,那麼Serialized介面的用途是什麼? 可序列化介面存在於java.io套件中,構成了Java序列化引擎的核心。它沒有任何方法,在Java中也稱為標記介面。當您的類別實作 java.io.Serialized 介面時,它就會變得可序列化。這很簡單。 問題3)什麼是serialVersionUID?如果不定義會發生什麼事? 我最喜歡的 Java 序列化面試問題之一。SerialVersionUID是物件序列化時附加的標識符,通常是物件的雜湊碼。可以使用serialver工具取得序列化物件的serialVersionUID。SerialVersionUID 用於物件版本控制。您也可以在類別文件中手動指定serialVersionUID。不指定serialVersionUID的後果是,如果新增或變更類別中的任何字段,已經序列化的類別將無法恢復,因為為新類別產生的serialVersionUID將與舊序列化物件相同的字段。Java 序列化過程依賴正確的serialVersionUID 來恢復序列化物件的狀態,如果不匹配,則會拋出java.io.InvalidClassException。要了解有關serialversionuid 的更多信息,請參閱此處問題4)序列化時,是否希望某些成員不被序列化?如何實現這項目標? 另一個常見的連載面試問題。有時人們也會問如何使用瞬態變量,瞬態變數和靜態變數是否序列化等等,因此,如果您不希望任何欄位成為物件狀態的一部分,請將其聲明為靜態或瞬態,具體取決於根據您的需要,它不會包含在Java 序列化過程中。 問題 5)如果類別成員之一沒有實作 Serialized 接口,會發生什麼情況? 關於Java中序列化過程的簡單問題之一。如果您嘗試序列化實現了 Serialized 的類別的對象,但該物件包含對不可 Serialized 的類別的引用,則在運行時將拋出 NotSerializedException ,這就是為什麼我總是在我的程式),最好的程式碼註解技術之一是指導開發人員在向 Serialized 類別新增欄位時記住這一事實。 問題6)如果一個類別是可序列化的,但它的超類別不是可序列化的,那麼從超類別繼承的實例變數在反序列化後會是什麼狀態? 只要類別實作了 Serialized 接口,Java 序列化過程只會在物件層次結構中繼續,並且從超類別繼承的變數的值將在反序列化過程中透過呼叫不可序列化超類別的建構函式來初始化。一旦建構函數鏈啟動,就無法停止它,因此即使層次結構中較高的類別(不)實作 Serialized 接口建構函式也會被執行。這個連載面試題看起來可能很難,但是如果你熟悉了關鍵概念,那就不難了。 問題 7) 可以自訂序列化過程或覆寫 Java 中的預設序列化過程嗎? 答案是肯定的,可以。我們都知道,要序列化一個對象,需要調用ObjectOutputStream.writeObject(saveThisObject) ,要讀取一個對象,需要調用ObjectInputStream.readObject() ,但是Java 虛擬機還為您提供了一項功能- 定義這兩個方法在你的班級。如果您在類別中定義它們,JVM 將呼叫這兩個方法,而不是使用預設的序列化機制。您可以在此處透過執行任何預處理或後處理任務來配置物件的序列化和反序列化行為。需要注意的是,這些方法必須是私有的,以避免繼承、覆蓋或重載。由於只有 Java 虛擬機器可以呼叫私有方法,因此類別的完整性將被保留,並且序列化將照常工作。在我看來,這是在 Java 序列化面試中可以提出的最佳問題之一。一個很好的後續問題是:為什麼需要為物件提供自訂序列化形式? 問題8)假設一個新類別的超類別實作了Serialized接口,我們如何避免新類別被序列化? 關於 Java 序列化的面試難題之一。如果一個類別的超類別已經實作了 Java 中的 Serialized 接口,那麼其後代類別也是可序列化的,因為你不能不實作父類別的接口,並且實際上不可能將其設為不可序列化類別。但是,有一種方法可以避免這個新類別的序列化。為此,您需要實作 writeObject() 和 readObject() 方法,並從這些方法中拋出 NotSerializedException。隨著面試的進行,這個問題通常會被被問到作為附加問題。 問題9)Java中序列化和反序列化過程中使用了哪些方法? 這是序列化中非常常見的問題。在這個案例中,面試官想了解什麼?無論您是否熟悉 readObject()、writeObject()、readExternal() 和 writeExternal() 的使用。Java 序列化是由 java.io.ObjectOutputStream 類別完成的。此類是一個過濾流,包裹在較低層級的位元組流中以處理序列化引擎。要使用序列化機制保存任何對象,我們呼叫 ObjectOutputStream.writeObject(saveThisObject) 並反序列化該對象,我們呼叫 ObjectInputStream.readObject() 方法。呼叫 writeObject() 方法啟動序列化過程。關於 readObject() 方法需要注意的一件重要事情是,它用於讀取位元組並從這些位元組創建和返回一個對象,而該對象必須轉換為正確的類型。 問題 10) 假設您有一個已序列化並保存的類,然後您修改該類以新增欄位。如果反序列化一個已經序列化的物件會發生什麼事? 這取決於該類別是否有自己的serialVersionUID。從上面的問題我們知道,如果我們在程式碼中不提供serialVersionUID,java編譯器將自行產生它,並且通常它等於該物件的雜湊碼。新增任何新欄位後,為該版本的類別產生的新serialVersionUID有可能與已序列化的物件不匹配,在這種情況下,API將拋出java.io.InvalidClassException。因此,建議在程式碼中擁有自己的serialVersionUID,對於同一個類別來說始終是相同的。 問題11)Java序列化機制中相容與不相容的變化有哪些? 真正的問題是透過添加任何欄位、方法或刪除具有已序列化物件的任何欄位或方法來更改類別的結構。根據 Java 序列化規範,新增任何欄位或方法都屬於相容更改和​​更改類別層次結構或未實現可序列化介面(某些屬於不相容更改)。有關兼容和不相容更改的完整列表,我建議閱讀 Java 序列化規範。 問題 12)我們可以透過網路傳輸序列化物件嗎? 是的,您可以透過網路傳遞序列化對象,因為 Java 序列化物件是可以以任何方式傳遞的位元組集合。您也可以將序列化物件儲存在磁碟上或作為 Blob 儲存在資料庫中。 問題13)Java序列化時哪些類型的變數不被序列化? 有時會以不同的方式提出這個問題,但目標是相同的:了解 Java 開發人員是否了解序列化靜態變數和瞬態變數的細節。由於靜態變數屬於類別而不是對象,因此它們不是對象狀態的一部分,因此它們在 Java 序列化過程中不會被持久化。由於Java序列化僅儲存物件的狀態而不儲存物件本身,因此瞬態變數也不包含在序列化過程中,並且不是物件序列化狀態的一部分。提出這個問題後,或許面試官會問:如果不儲存這些變數的值,那麼反序列化並重新建立這個物件後,這些變數的值會是什麼呢?而這一點,各位同事,你們自己想一想:)原文在這裡
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION