類Object是類層次結構的根類。每個類都直接或者間接地繼承Object類。所有對象(包括數組)都實現這個類的方法。Object類中的構造方法只有一個,並且是無參構造方法,這說明每個類中默認的無參構造方法調用的就是Object類的無參構造方法。
1、hashCode方法
hashCode方法返回給調用者此對象的哈希碼(其值由一個hash函數計算得來,一般是通過將該對象的內部地址轉換成一個整數)。這個方法通常用在基於hash的集合類中(像java.util.HashMap,java.until.HashSet和java.util.Hashtable)以提高性能。
1 @Test 2 public void testHashCode() { 3 Student student = new Student(); 4 5 for (int i = 0; i < 3; i++) { 6 System.out.println(student.hashCode()); 7 } 8 }
1 249123537 2 249123537 3 249123537
我們可以看到運行了3次,結果是一樣的,Java中對hashCode方法有如下約定:
1)在Java應用程序執行期間,在對同一對象多次調用hashCode方法時,必須一致地返回相同的整數,前提是將對象進行equals比較時所用的信息沒有被修改。從某一應用程序的一次執行到同一應用程序的另一次執行,該整數無需保持一致。
2)如果根據equals(Object)方法,兩個對象是相等的,那麼對這兩個對象中的每個對象調用hashCode方法都必須生成相同的整數結果。
3)如果根據equals(java.lang.Object)方法,兩個對象不相等,那麼對這兩個對象中的任一對象上調用hashCode方法不要求一定生成不同的整數結果。但是,程序員應該意識到,為不相等的對象生成不同整數結果可以提高哈希表的性能。
上面3句話可以理解為:
兩個對象相等 <=> equals相等 => hashCode相等。
hasCode不相等 => equals不相等 <=> 兩個對象不相等。
說來說去還是不知道這個hasCode方法是用來做什麼的,上面提到該方法通常用在基於hash的集合類中,以提高性能,以Set集合為例,當往集合中添加一個新的對象時,需要知道在當前集合中是否存在存在該對象,Java會先調用hasCode方法判斷集合中是否有對象的哈希碼值與新的對象相等,如果不相等,則添加,如果相等,則繼續用equals方法判斷2個對象是否相等,只有當哈希碼相等時,並且equals方法返回為true時,2個對象才認為是相等的。
2、equals方法
該方法可以用來檢查一個對象與調用這個equals()的這個對象是否相等。
equals字面意思相等,說到相等,我們想到==這個運算符也是用來比較相等的,那麼這兩個有什麼區別呢,當==用於基本類型時比較的是基本類型的值是否相同,用於引用類型時,比較的是引用類型的地址是否指向同一個地方,Object中的equals方法與==運算符是一樣的
1 public boolean equals(Object obj) { 2 return (this == obj); 3 }
既然有了==運算符,那還需要equals方法做什麼呢,通常情況下,比較2個兩個對象的地址值意義不大,所以需要重寫Object類中的equals方法來滿足自己的需求,例如String類中的equals方法表示的是字符串的內容是否相等。如果重寫了equals方法,則hashCode也有必要重寫。
3、getClass方法
返回此 Object 的運行時類(類對象),我們知道類是是對具有一組相同特征或行為的實例的抽象並進行描述,對象則是此類所描述的特征或行為的具體實例。作為類,其本身也具有某些共同的特性,如都具有類名稱、由類加載器去加載,都具有包,具有父類,屬性和方法等。在Java中用Class這個類來表示其他類所具有的這些特征,因此,類本身也都是屬於Class類的對象。為了與平時所說的對象區分開,通常情況稱之為類對象。
1 @Test 2 public void testGetClass() { 3 Student student = new Student(); 4 System.out.println(student.getClass()); 5 }
class com.java.test.Student
4、toString方法
返回該對象的字符串表示。通常,toString 方法會返回一個“以文本方式表示”此對象的字符串。我們看Object類中的toString方法
1 public String toString() { 2 return getClass().getName() + "@" + Integer.toHexString(hashCode()); 3 }
當我們使用System.out.println(object)時,內部也是通過調用toString()來實現的。
1 @Test 2 public void testToString() { 3 Student student = new Student(); 4 System.out.println(student); 5 System.out.println(student.toString()); 6 System.out.println(student.getClass().getName() + "@" + Integer.toHexString(student.hashCode())); 7 }
1 com.java.test.Student@cb5efc8 2 com.java.test.Student@cb5efc8 3 com.java.test.Student@cb5efc8
由於這個信息一般沒有什麼太大作用,所以建議所有子類都重寫此方法。 重寫了Student類中的toString方法後
1 Student [name=null, age=0] 2 Student [name=null, age=0]
這時候的信息我們就可以很容易的理解了。
5、clone方法
創建並返回此對象的一個副本。副本可以這麼理解,原來有一個文檔,通過Ctrl+C復制,然後Ctrl+V黏貼一個新的文檔出來,這個新的文檔就叫做文檔的副本,你在副本上面所做的操作不會影響到原來的文檔。注意在調用clone()方法時,被調用對象需要實現Cloneable接口,如果沒有實現Cloneable接口,並且子類直接調用Object類的clone()方法,則會拋出CloneNotSupportedException異常。Cloneable接口是標記接口,接口本身不包含任何方法,表示實現了這個接口,就可以實現對象的復制了。
1 @Test 2 public void testClone() throws CloneNotSupportedException { 3 Student student1 = new Student("John", 23); 4 Student student2 = (Student) student1.clone(); 5 System.out.println(student1); 6 System.out.println(student2); 7 System.out.println("改變student1的屬性值後:"); 8 student1.setName("Jack"); 9 student1.setAge(22); 10 System.out.println(student1); 11 System.out.println(student2); 12 }
1 Student [name=John, age=23] 2 Student [name=John, age=23] 3 改變student1的屬性值後: 4 Student [name=Jack, age=22] 5 Student [name=John, age=23]
從運行結果也可以看出,被調用對象student1更改了屬性值後,不會影響到副本的屬性值,也說明了兩者在堆空間中的位置不同。
6、finalize方法
1 protected void finalize() throws Throwable { }
當垃圾回收器確定不存在對該對象的更多引用時,由對象的垃圾回收器調用此方法。通常情況下,這個方法一般不會用到。
附完整代碼:
1 package com.java.test; 2 3 import org.junit.Test; 4 5 public class StudentTest { 6 7 @Test 8 public void testHashCode() { 9 Student student = new Student(); 10 11 for (int i = 0; i < 3; i++) { 12 System.out.println(student.hashCode()); 13 } 14 } 15 16 @Test 17 public void testGetClass() { 18 Student student = new Student(); 19 System.out.println(student.getClass()); 20 } 21 22 @Test 23 public void testToString() { 24 Student student = new Student(); 25 System.out.println(student); 26 System.out.println(student.toString()); 27 System.out.println(student.getClass().getName() + "@" + Integer.toHexString(student.hashCode())); 28 } 29 30 @Test 31 public void testClone() throws CloneNotSupportedException { 32 Student student1 = new Student("John", 23); 33 Student student2 = (Student) student1.clone(); 34 System.out.println(student1); 35 System.out.println(student2); 36 System.out.println("改變student1的屬性值後:"); 37 student1.setName("Jack"); 38 student1.setAge(22); 39 System.out.println(student1); 40 System.out.println(student2); 41 } 42 }
1 package com.java.test; 2 3 public class Student implements Cloneable { 4 private String name; 5 private int age; 6 7 public Student() { 8 super(); 9 } 10 11 public Student(String name, int age) { 12 super(); 13 this.name = name; 14 this.age = age; 15 } 16 17 public String getName() { 18 return name; 19 } 20 21 public void setName(String name) { 22 this.name = name; 23 } 24 25 public int getAge() { 26 return age; 27 } 28 29 public void setAge(int age) { 30 this.age = age; 31 } 32 33 @Override 34 public String toString() { 35 return "Student [name=" + name + ", age=" + age + "]"; 36 } 37 38 @Override 39 protected Object clone() throws CloneNotSupportedException { 40 return super.clone(); 41 } 42 43 }