面試官:對象可能會遲到,但它永遠不會缺席
- 2020 年 8 月 17 日
- 筆記
- Java Grammar, 面試
問題一:簡單聊一下關於你對Object
的理解
在 Java 中,只有基本數據類型不是對象,比如,數值,布爾和字元類型的值都不是對象。而其餘的數據類型都是繼承自一個名為Object
的類,這個類是所有類的始祖,每個類都是由Object
類擴展而來。
如果一個類繼承自Object
類,我們可以將extends Object
給省略掉,如果在一個類的定義中沒有明確的指出哪個是它的父類,那麼Object
類就認為是這個類的父類。

問題二:Object
類中有一個registerNatives
方法,對此你了解多少?
從方法的命名上我們就可以看出,該方法是用於註冊本地(native)方法,主要是為了服務於JNI的,它主要是提供了 java 類中的方法與對應 C++ 程式碼中的方法的映射,方便jvm去查找調用 C++ 中的方法。

問題三:Object
類中有clone
方法,聊聊你對這個方法的認識
clone
方法是Object
類的一個protected
的方法,我們可以這樣去應用這個方法
-
實現
Cloneable
介面 -
重寫
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是由對象導出的一個整型值,以下是幾個常見哈希值的演算法:
-
Object
類的hashCode()
。返回對象的記憶體地址經過處理後的結構,由於每個對象的記憶體地址都不一樣,所以哈希碼也不一樣。 -
String
類的hashCode()
。根據String
類包含的字元串的內容,根據一種特殊演算法返回哈希碼,只要字元串所在的堆空間相同,返回的哈希碼也相同。 -
Integer
類,返回的哈希碼就是Integer
對象里所包含的那個整數的數值,例如Integer i1=new Integer(100
),i1.hashCode
的值就是100 。由此可見,2個一樣大小的Integer
對象,返回的哈希碼也一樣。
問題九:說說Equals
和 Hashcode
的關係
這兩個其實確切意義上並沒有什麼聯繫,前提是我們不會在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值的相關資訊,否則會導致記憶體泄露問題。