Object類
toString方法
Java對象都是Object類的執行個體,都可直接調用該類中定義的方法,這些方法提供了處理Java對象的通用方法。
class Person
{
private String name;
public Person(String name)
{
this.name = name;
}
}
public class PrintObject
{
public static void main(String[] args){
Person p = new Person("hello");
System.out.println(p); // 輸出:Person@15db9742
System.out.println(p.toString()); // 輸出:Person@15db9742
}
}
System.out.println(類對象的引用)實際上是調用該類對象繼承的Object類的toString方法。并且Java對象和字元串連接配接時,系統自動調用toString方法和字元串進行連接配接運算。
String pStr = p + "";
String pStr = p.toString() + "";
Object類的toString方法總是傳回該對象實作類的“類名+@+hashCode”值,這個傳回值并不能真正實作自我描述功能,如果使用者需要自定義實作自我描述功能,就需要重寫Object類的toString方法。
equals方法
equals方法是Object類提供的一個執行個體方法,所有引用變量都可以調用該方法來判斷是否與其他引用變量相等。但使用這個方法判斷兩個對象相等的标準與使用==運算符沒有差別,同樣要求兩個引用變量指向同一對象才會傳回true。是以Object類提供的equals方法沒有太大意義,一般需要重寫該方法。比如String已經重寫Object的equals方法,String的equals方法判斷兩個字元串相等的标準:隻要兩個字元串所包含的字元序列相同,通過equals比較将傳回true,否則将傳回false。
class Person
{
private String name;
private String idStr;
public Person() {}
public Person(String name, String idStr){
this.name = name;
this.idStr = idStr;
}
public boolean equals(Object obj){
//如果兩個對象為同一對象
if(this == obj)
return true;
//隻有當obj是Person對象
if(obj!=null && obj.getClass() == Person.class)
{
Person personobj = (Person)obj;
//并且目前對象的idStr與obj對象的idStr相等時才可判斷兩個對象相等
if(this.getIdStr().equals(personobj.getIdStr()))
return true;
}
return false;
}
}
public class OverrideEqualsRight
{
public static void main(String[] args)
{
Person p1 = new Person("孫悟空", "1234343433433");
Person p2 = new Person("孫行者", "1234343433433");
Person p2 = new Person("孫悟飯", "99933433");
System.out.println("p1和p2是否相等:"+p1.equals(p2)); // true
System.out.println("p2和p3是否相等:"+p2.equals(p3)); // false
}
}
判斷obj是否為Person類的執行個體可以使用instanceof嘛?
對于instanceof運算符,前面對象是後面類的執行個體或其子類的執行個體都将傳回true,是以重寫equals方法判斷兩個對象是否為同一個類的執行個體時使用Instanceof是有問題的。比如Teacher類型變量t,如果t instanceof Person,這也将傳回true。但對于重寫equals方法而言,通常要求兩個對象是同一個類的執行個體,是以使用instanceof運算符不太合适。
finalize方法
在垃圾回收機制回收某個對象所占用的記憶體之前,通常要求程式調用适當的方法來清理資源,在沒有明确指定清理資源的情況下,Java提供了預設機制來清理該對象的資源,這個機制就是finalize方法。該方法是定義在Object類裡的執行個體方法,方法原型:
protected void finalize() throws Throwable
當finalize方法傳回後,對象消失,垃圾回收機制開始執行。方法原型中的throws Throwable表示它可以抛出任何類型的異常。
任何Java類都可以重寫Object類的finalize方法,在該方法中清理該對象占用的資源。如果程式終止之前始終沒有進行垃圾回收,則不會調用失去引用對象的finalize方法來清理資源。垃圾回收機制何時調用對象的finalize方法是完全透明的,隻有當程式認為需要更多的額外記憶體時,垃圾回收機制才會進行垃圾回收。是以,完全有可能出現這樣一種情形:某個失去引用的對象隻占用了少量記憶體,而且系統沒有産生嚴重的記憶體需求,是以垃圾回收機制并沒有試圖回收該對象所占用的資源,是以該對象的finalize方法也不會得到調用。
finalize方法具有如下特點:
- 永遠不要主動調用某個對象的finalize方法,該方法應交給垃圾回收機制調用
- finalize方法何時被調用,是否被調用具有不确定性,不要把finalize方法當成一定會被執行的方法
- 當JVM執行可恢複對象的finalize方法時,可能使該對象或系統中其他對象重新變成可達狀态。
- 當JVM執行finalize方法時出現異常時,垃圾回收機制不會報告異常,程式繼續執行。
getClass方法
hashCode方法
在預設情況下,Object類的hashCode()方法根據該對象的位址來計算(即與System.identityHashCode(Object x)方法的計算結果相同)。但很多類都重寫了Object類的hashCode()方法,不再根據位址來計算其hashCode()方法值。
clone方法
Java提供了一個protected修飾的clone方法,該方法用于幫助其他對象來實作“自我克隆”,就是得到一個目前對象的副本,而且二者之間完全隔離。由于Object類提供的clone方法使用了protected修飾,是以該方法隻能被子類重寫或調用。
自定義實作克隆的步驟:
- 自定義類實作Cloneable接口。這是一個标記性的接口,實作該接口的對象可以實作自我克隆,接口裡沒有定義任何方法。
- 自定義類實作自己的clone方法
-
實作clone方法通過super.clone();調用Object實作的clone方法來得到該對象的副本,并傳回該副本。
Object類提供的Clone機制隻對對象裡各執行個體變量進行簡單複制,如果執行個體變量的類型是引用類型,Object的Clone機制也隻是簡單地複制這個引用變量,這樣原有對象的引用類型的執行個體變量與克隆對象的引用類型的執行個體變量與克隆對象的引用類型的執行個體變量依然指向記憶體中的同一個執行個體。這和C++中的淺拷貝類似。
淺克隆-隻克隆該對象的所有成員變量值,不會對引用類型的成員變量值所引用的對象進行克隆。
深克隆-需要開發者自己進行遞歸克隆,保證所有引用類型的成員變量值所引用的對象都被複制了。
class Address{
String detail;
public Address(String detail){ this.detail = detail; }
}
//實作Cloneable接口
class User implements Cloneable
{
int age;
Address address;
public User(int age)
{
this.age = age;
address = new Address("上海");
}
//調用super.clone()來實作clone方法
public User clone() throws CloneNotSupportedException
{
return (User)super.clone();
}
}
public class CloneTest {
public static void main(String[] args) throws CloneNotSupportedException {
User u1 = new User(29);
//clone得到u1對象的副本
User u2 = u1.clone();
//判斷u1和u2是否相同
System.out.println(u1 == u2);
//判斷u1和u2的address是否相同
System.out.println(u1.address == u2.address);
}
}
Java 7新增的Objects類
public class ObjectsTest{
//定義一個obj變量,預設值是null
static ObjectsTest obj;
public static void main(String[] args){
//輸出一個null對象的hashCode值,輸出0
System.out.println(Objects.hasnCode(obj));
//輸出一個null對象的toString,輸出null
System.out.println(Objects.toString(obj));
//要求obj不能null,如果obj為null則引發異常
System.out.println(Objects.requireNonNull(obj, "obj參數不能是null!"));
}
}