面試官:物件可能會遲到,但它永遠不會缺席

山禾說發表於2020-08-17

問題一:簡單聊一下關於你對Object的理解

在 Java 中,只有基本資料型別不是物件,比如,數值,布林和字元型別的值都不是物件。而其餘的資料型別都是繼承自一個名為Object的類,這個類是所有類的始祖,每個類都是由Object類擴充套件而來。

如果一個類繼承自Object類,我們可以將extends Object給省略掉,如果在一個類的定義中沒有明確的指出哪個是它的父類,那麼Object類就認為是這個類的父類。

=
=

問題二:Object類中有一個registerNatives方法,對此你瞭解多少?

從方法的命名上我們就可以看出,該方法是用於註冊本地(native)方法,主要是為了服務於JNI的,它主要是提供了 java 類中的方法與對應 C++ 程式碼中的方法的對映,方便jvm去查詢呼叫 C++ 中的方法。

img
img

問題三:Object類中有clone方法,聊聊你對這個方法的認識

clone方法是Object類的一個protected的方法,我們可以這樣去應用這個方法

  1. 實現Cloneable介面

  2. 重寫clone方法,並指定public修飾符。

問題四:為什麼我們一定要去實現Cloneable介面,而不是直接去重寫這個方法呢?

我們通過原始碼可以發現這是一個空的介面,clone是從Object類繼承的。這個介面只是作為一個標記,指示類設計者瞭解克隆繼承。物件對於克隆也很"偏執",如果一個物件請求克隆,但沒有實現這個介面,就會生成一個異常。

在 Java 中,Cloneable這樣的介面叫做標記介面,標記介面不包括任何方法,它的唯一作用就是允許在型別查詢的時候使用instanceof

  • ounter(line
  • ounter(line
  • ounter(line
if (obj instanceof Cloneable){    //TODO}

問題五:說一說你對關於深克隆和淺克隆的認識

首先來說一下Object類是如何實現clone,它對這個物件一無所知,所以只能逐個域的進行拷貝。如果物件中的所有資料域都是數值或其他基本型別,拷貝這些域沒有任何問題,但是如果物件中包含子物件的引用,拷貝域就會得到相同子物件的另一個引用,這樣一來,原物件和克隆物件仍然會去共享一些資訊。這種Object類預設實現的clone方法稱為淺拷貝(Shallow Clone)。

這裡需要注意,關於淺克隆的安全性,如果原物件和淺克隆物件共享的子物件是不可變的,那麼這種共享就是安全的。如果子物件屬於一個不可變的類,如String,就是這種情況。或者在物件的生命期中,子物件一直包含不變的常量 ,沒有更改器方法會改變它,也沒有方法會生成它的引用,這種情況同樣是安全的。

不過子類物件通常是可變的,這時我們就需要定義深拷貝(Deep Clone),來克隆這個類的所有子物件。

具體實現方法如下:

  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
public Test clone() throws CloneNotSupportedException{     //拷貝該物件    Test cloned = (Test)super.clone();     //拷貝該物件中的可變域    cloned.time = (Date) time.clone();    return cloned;}

這裡需要提到的一點是:

雖然我們已經學習了clone的兩種用法,但是在實際的編碼中還是儘量少用這個方法,它具有天生的不穩定性,僅僅瞭解即可。即使是Java的標準庫中也只有5%的類實現了這個方法。

我們可以使用Java的物件序列化特性來實現克隆物件,雖然效率不高,但是很安全,而且很容易實現。

問題六: 關於equals方法,說說是什麼?

Object類中的equals方法用於檢測一個物件是否等於另一個物件。在Object類中,這個方法將判斷兩個物件是否具有相同的引用。如果兩個物件具有相同的引用,它們一定是相等的。

問題七:有沒有自己去重寫過equals方法呢?

當然,這個我有筆記~

問題八:不限於Object,聊聊hashCode

在Java中,hash code是由物件匯出的一個整型值,以下是幾個常見雜湊值的演算法:

  1. Object類的hashCode()。返回物件的記憶體地址經過處理後的結構,由於每個物件的記憶體地址都不一樣,所以雜湊碼也不一樣。

  2. String類的hashCode()。根據String類包含的字串的內容,根據一種特殊演算法返回雜湊碼,只要字串所在的堆空間相同,返回的雜湊碼也相同。

  3. Integer類,返回的雜湊碼就是Integer物件裡所包含的那個整數的數值,例如Integer i1=new Integer(100),i1.hashCode的值就是100 。由此可見,2個一樣大小的Integer物件,返回的雜湊碼也一樣。

問題九:說說EqualsHashcode的關係

這兩個其實確切意義上並沒有什麼聯絡,前提是我們不會在HashSet,HashMap這種本質是雜湊表的資料結構中使用,如果我們要在HashSet,HashMap這種本質是雜湊表的資料結構中使用,在重寫equals方法的同時也要重寫hashCode方法,以便使用者將物件插入到雜湊表中,否則會導致資料不唯一,記憶體洩漏等各種問題。

1.hashCode是為了提高在雜湊結構儲存中查詢的效率,線上性表中沒有作用。

2.equals()hashCode()需要同時覆蓋,而且定義必須一致,也就是說equals比較了哪些域,hashCode就會對哪些域進行hash值的處理。

3.若兩個物件equals()返回true,則hashCode()有必要也返回相同的值。

4.若兩個物件equals()返回false,則hashCode()不一定返回不同的值。

5.若兩個物件hashCode()返回相同的值,則equals()不一定返回true。

6.若兩個物件hashCode()返回不同值,則equals()一定返回false。

7.同一物件在執行期間若已經儲存在集合中,則不能修改影響hashCode值的相關資訊,否則會導致記憶體洩露問題。

相關文章