一、簡述
1、Object類是所有類的父類,即直接或間接的繼承java.lang.Object類。省略了extends Object。
2、方法
(1)protected native Object clone() throws CloneNotSupportedException; //創建並返回一個對象的副本。
(2)public String toString(); //返回一個字符串,一般需要重寫。
(3)public final native Class<?> getClass(); //返回對象在運行時的類的類型
(4)public boolean equals(Object obj); //用來判斷調用equals對象與參數對象obj是否為同一個對象,一般需重寫。
(5)public native int hashCode(); //返回對象的哈希碼,可用於哈希查找,減少equals比較的次數,一般重寫equals方法后也要重寫hashcode方法。
(6)protected void finalize() throws Throwable { }; //該方法用於釋放資源,無法確定該方法什么時候被調用。
(7)public final native void wait(long timeout) throws InterruptedException; //使當前線程等待鎖,直到獲取鎖或被中斷,timeout指的是最長等待時間。
(8)public final native void notify(); //用於隨機喚醒該對象上等待的某個線程。
(9)public final native void notifyAll(); //用於喚醒該對象上等待的所有線程。
3、由於getClass()、notify()、notifyAll()、wait()等方法被final修飾,所以不能被重寫。
二、Clone()
1、clone()方法作用是返回一個Object對象的復制,且復制的對象是一個新的對象。
2、使用clone()方法時,需要實現Cloneable接口,否則會拋出異常(CloneNotSupportedException)。
3、分類:淺復制(Shallow Clone)與深復制(Deep Clone)
(1)淺復制:復制后的對象的所有變量都與原有對象的值相同,且所有對其他對象的引用仍指向原來的對象。簡單的講,對於基本類型,復制的是數據,對於引用類型,復制的是數據的地址。即淺復制復制當前對象,不復制當前對象中的引用對象。
注意一個坑:對於引用類型,復制的是數據的地址(通過地址訪問對象的真實數據)。若通過地址來修改對象,那么原有對象以及復制的對象均會修改相應的值。但若是修改了地址(比如new了一個對象,則地址發生改變,而原有的對象並未發生改變),則只有被修改的對象才會發生改變。
(2)深復制:指的是完全復制,將當前對象整體復制,並創建一個新的對象保存。即深復制復制當前對象,且復制當前對象中的引用對象。簡單的講,深復制在淺復制的基礎上,將引用類型再復制一份,其中引用類型需要實現Cloneable接口(如下例中的People類實現了Cloneable接口)。
注意一個坑:只有實現了Cloneable接口,才能調用clone()方法。
/** * 引用類型,用於測試淺復制與深復制的差別。 若只是淺復制,不用實現Clonable接口。 若是深復制,則要實現Cloneable接口以及clone方法。 */ class People implements Cloneable { private String name; private int age; public People(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "People [name=" + name + ", age=" + age + "]"; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } } /** * 淺復制 */ class ShallowCloneDemo implements Cloneable { private People people; private String sex; public ShallowCloneDemo(People people, String sex) { this.people = people; this.sex = sex; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public People getPeople() { return people; } public void setPeople(People people) { this.people = people; } @Override protected Object clone() { try { return (ShallowCloneDemo) super.clone(); } catch (CloneNotSupportedException e) { System.out.println("Shallow Clone Error"); return null; } } @Override public String toString() { return "ShallowCloneDemo [people=" + people + ", sex=" + sex + "]"; } } /** * 深復制 */ class DeepCloneDemo implements Cloneable { private People people; private String sex; public DeepCloneDemo(People people, String sex) { this.people = people; this.sex = sex; } public People getPeople() { return people; } public void setPeople(People people) { this.people = people; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } @Override protected Object clone() { DeepCloneDemo obj = null; try { obj = (DeepCloneDemo) super.clone();// 淺復制 obj.people = (People) this.getPeople().clone();// 需要克隆引用類型 } catch (CloneNotSupportedException e) { System.out.println("Deep Clone Error"); return null; } return obj; } @Override public String toString() { return "DeepCloneDemo [people=" + people + ", sex=" + sex + "]"; } } /** * 測試類,用於測試淺復制與深復制 */ public class Test { public static void main(String[] args) { System.out.println("普通實例化一個ShallowCloneDemo:"); ShallowCloneDemo shallowCloneDemo1 = new ShallowCloneDemo(new People("rick", 18), "man"); System.out.println("實例化完成"); System.out.println(); System.out.println("通過clone()方法淺復制克隆一個ShallowCloneDemo:"); System.out.println("Start Shallow Cloning"); ShallowCloneDemo shallowCloneDemo2 = (ShallowCloneDemo) shallowCloneDemo1.clone(); System.out.println("Shallow Clone End"); System.out.println(); System.out.println("輸出原有對象以及淺復制克隆對象的值:"); System.out.println(shallowCloneDemo1); System.out.println(shallowCloneDemo2); System.out.println(); System.out.println("對原有對象進行修改后,輸出原有對象以及淺復制克隆對象的值:"); shallowCloneDemo1.getPeople().setName("tom"); shallowCloneDemo2.getPeople().setAge(20); shallowCloneDemo1.setSex("woman"); System.out.println(shallowCloneDemo1); System.out.println(shallowCloneDemo2); System.out.println("結果顯示,淺復制對象會隨着原有對象一起修改。"); System.out.println("這里由於String類型相當於指向了一個新地址,所以只有被修改的對象改變值"); System.out.println(); System.out.println("普通實例化一個DeepCloneDemo:"); DeepCloneDemo deepCloneDemo1 = new DeepCloneDemo(new People("rick", 18), "man"); System.out.println("實例化完成"); System.out.println(); System.out.println("通過clone()方法深復制克隆一個DeepCloneDemo:"); System.out.println("Start Deep Cloning"); DeepCloneDemo deepCloneDemo2 = (DeepCloneDemo) deepCloneDemo1.clone(); System.out.println("Deep Clone End"); System.out.println(); System.out.println("輸出原有對象以及深復制克隆對象的值:"); System.out.println(deepCloneDemo1); System.out.println(deepCloneDemo2); System.out.println(); System.out.println("對原有對象進行修改后,輸出原有對象以及淺復制克隆對象的值:"); deepCloneDemo1.getPeople().setName("tom"); deepCloneDemo2.getPeople().setAge(20); deepCloneDemo1.setSex("woman"); System.out.println(deepCloneDemo1); System.out.println(deepCloneDemo2); System.out.println("結果顯示,深復制時對象是獨立的,互不干擾。"); System.out.println("這里由於String類型相當於指向了一個新地址,所以只有被修改的對象改變值"); } } /* 測試結果: 普通實例化一個ShallowCloneDemo: 實例化完成 通過clone()方法淺復制克隆一個ShallowCloneDemo: Start Shallow Cloning Shallow Clone End 輸出原有對象以及淺復制克隆對象的值: ShallowCloneDemo [people=People [name=rick, age=18], sex=man] ShallowCloneDemo [people=People [name=rick, age=18], sex=man] 對原有對象進行修改后,輸出原有對象以及淺復制克隆對象的值: ShallowCloneDemo [people=People [name=tom, age=20], sex=woman] ShallowCloneDemo [people=People [name=tom, age=20], sex=man] 結果顯示,淺復制對象會隨着原有對象一起修改。 這里由於String類型相當於指向了一個新地址,所以只有被修改的對象改變值 普通實例化一個DeepCloneDemo: 實例化完成 通過clone()方法深復制克隆一個DeepCloneDemo: Start Deep Cloning Deep Clone End 輸出原有對象以及深復制克隆對象的值: DeepCloneDemo [people=People [name=rick, age=18], sex=man] DeepCloneDemo [people=People [name=rick, age=18], sex=man] 對原有對象進行修改后,輸出原有對象以及淺復制克隆對象的值: DeepCloneDemo [people=People [name=tom, age=18], sex=woman] DeepCloneDemo [people=People [name=rick, age=20], sex=man] 結果顯示,深復制時對象是獨立的,互不干擾。 這里由於String類型相當於指向了一個新地址,所以只有被修改的對象改變值 */
三、toString、getClass
1、Object 類的 toString 方法返回一個字符串,該字符串由類名、標記符“@”和此對象哈希碼的無符號十六進制表示組成。
2、Object 類的getClass()方法返回一個對象的類名。
四、equals、hashcode
1、Object中的equals方法是直接判斷this和obj本身的值是否相等,即用來判斷調用equals的對象和形參obj所引用的對象是否是同一對象(即是否占據同一個內存)。對於內容相同但內存不同的對象,返回false。需要進行重寫,並重寫比較規則,才能使其為true。
2、Object的hashcode()方法用於哈希查找,可以減少在查找中使用equals的次數,重寫了equals方法一般都要重寫hashCode方法。
五、==和equals的區別是什么?
1、==對於基本類型,比較的是值,對於引用類型,比較的引用變量的堆內存地址。
2、equals未重寫時等價於==,一般重寫后用來比較兩個對象的內容是否相等。
六、hashCode() 與 equals() 的關系?
1、hashcode()的作用用於獲取哈希碼(散列碼),其返回一個int整數,用於確定對象在哈希表中的索引位置。
2、equals相同的兩個對象的hashCode必定相同。
3、hashCode相同的兩個對象的equal不一定相同。
4、equals重寫時,hashcode一般需重寫。hashcode默認為堆中對象產生的獨特值,若未重寫hashcode,那么即使兩個對象指向同一個數據,hashcode值也不會相等。
5、hashcode與equals在HashSet中的應用,當對象加入HashSet時,先由hashcode計算對象的散列值,若相等,則比較equals,若equals比較仍相等(即為相同對象),則對象不會加入到HashSet中。若equals比較不等,則將對象重新散列到其他位置。通過減少equals比較次數,可以提高執行速度。