jdk源碼每日一讀 (一) java.lang.Object 1. 類說明 Object是java繼承體系的根,是每一個類的基類,所有的類都實現了Object類的所有方法。 2.重要方法 3. 分析 1. getClass方法 getClass方法的返回值是Class對象,它返回的是對象消除靜態類型 ...
jdk源碼每日一讀 (一) java.lang.Object
1. 類說明
Object是java繼承體系的根,是每一個類的基類,所有的類都實現了Object類的所有方法。
2.重要方法
public final native Class<?> getClass()
public native int hashCode();
public boolean equals(Object obj);
protected native Object clone() throws CloneNotSupportedException;
public String toString();
public final native void notify();
public final native void notifyAll();
public final native void wait(long timeout) throws InterruptedException;
public final void wait(long timeout, int nanos) throws InterruptedException;
public final void wait() throws InterruptedException
protected void finalize() throws Throwable;
3. 分析
getClass方法
getClass方法的返回值是Class對象,它返回的是對象消除靜態類型的類型,也就是說他返回的是對象的實際類型,比如說下麵這個例子
public class Test { public static void main(String[] args) { A a=new B(); System.out.println(a.getClass()); } } class A{ } class B extends A{ }
B是A的子類,雖然a聲明的類型是A,但是getClass方法返回的類型是B
hashCode方法
該方法返回的是一個整形的hash碼,一般這個方法用於利用到散列的類,比如說hashmap等,支持這個方法是為了提高hash表的性能。源碼中強調了,如果兩個類使用equals方法比較相等,那麼hashCode的返回值一定相同,但是如果使用equals方法比較不同,不對hashCode的返回值是否相等做要求,但是不同對象的hashCode不相同能夠提高hash表的性能。
在同一個應用中,每次調用同一個對象的hashCode方法,返回的整數一定相等。
hashCode是一個本地方法,他的返回值與對象的地址有關。
equals方法
比較兩個對象是否相等,在Object的實現中,直接使用==比較兩個對象是否相等,也就是說比較的是兩個對象的地址是否相等,如果有特殊的要求,如字元串的內容相等則可以認為兩個字元串是相等的,那麼應該重寫equal方法,當然也不要忘記重寫hashCode方法。
public boolean equals(Object obj) { return (this == obj); }
重寫equal方法要滿足下列要求
- 自反性:對於任何非空引用值
x
,x.equals(x)
都應返回true
。 - 對稱性:對於任何非空引用值
x
和y
,當且僅當y.equals(x)
返回true
時,x.equals(y)
才應返回true
。 - 傳遞性:對於任何非空引用值
x
、y
和z
,如果x.equals(y)
返回true
,並且y.equals(z)
返回true
,那麼x.equals(z)
應返回true
。 - 一致性:對於任何非空引用值
x
和y
,多次調用x.equals(y)
始終返回true
或始終返回false
,前提是對象上equals
比較中所用的信息沒有被修改。 - 對於任何非空引用值
x
,x.equals(null)
都應返回false
。
- 自反性:對於任何非空引用值
clone方法
返回該對象的副本,對於一般類,必須實現Cloneable介面,該介面是一個標記介面,裡面沒有內容。
public interface Cloneable { }
toString方法
返回一個表示該類信息的字元串,需要子類去重寫toString方法,預設實現如下: 類名+@+哈希碼的16進位字元串
public String toString() { return getClass().getName() + "@" + Integer.toHexString(hashCode());
notify方法
隨機喚醒在此對象監視器上等待的其中一個線程。
notifyAll方法
喚醒在此對象監視器上等待的所有線程
wait方法
調用wait系列方法,當前線程將會等待,並放棄該對象的監視器的所有權,調用該方法之前當前線程必須擁有該對象的監視器的所有權。
finalize方法
當垃圾回收器確定不存在對該對象的更多引用時(該對象可以被回收),由對象的垃圾回收器調用此方法。子類可以重寫該方法,使得該對象避免被回收,具體的做法是讓該對象再次存在引用,但是註意該方法只能被調用一次。
4. 問題
為什麼重寫equals方法要重寫hashCode方法
個人理解:hashCode方法在被設計的時候就是為了提高與hash相關的數據結構的性能,具體是如何提高的呢?以HashMap為例,當需要查找某個元素的時候,HashMap判斷某個key是否相等的時候,為了速度,首先是判斷的hashCode是否相等,然後通過equals方法判斷是否相等。所以如果重寫了equals而沒有重寫hashCode就會造成不一致性,也就是說通過equals方法判斷兩個對象是相等的,而hashCode未重寫的時候預設返回的值與對象的地址有關,這樣hashCode勢必就不相等了。所以為了保證比較時的一致性在重寫equals方法的時候一定要重寫hashCode方法,這一點在hashCode方法的源碼註釋里也說明瞭。
clone方法在什麼情況下使用
個人理解:clone用來複制一個對象,在java中創建一個對象有很多方式,比如說使用new關鍵字,反射以及clone方法。對比一下new和clone的區別,new一個對象的時候,首先會去檢查該對象的class文件是否載入進入方法區,如果沒有則先去載入class文件,然後分配一塊空間給對象,之後再進行一系列的初始化,這樣就在堆中得到了一個對象,而clone方法則是在根據一個對象中複製另一個新的對象。在有的場景中,我們可能需要一系列相同的對象,但是這些對象通過new創建的成本卻很高,這時就可以調用clone方法,這在設計模式中的原型設計模式中得到了應用。同時有的時候我麽也有複製對象的場景,但是通過引用賦值的方式,只能複製引用,不能複製堆中的對象。
clone還有深拷貝和淺拷貝的區別。深拷貝指得是對象本身以及對象包含的引用指向的堆中對象都進行拷貝,淺拷貝則是引用進行了複製但沒有真正拷貝引用所指向的對象。