Java中Object類的理解和使用
如何理解根父類
類java.lang.Object
是類層次結(jié)構(gòu)的根類,即所有其它類的父類。每個類都使用Object
作為超類。
- Object類型的變量與除Object以外的任意引用數(shù)據(jù)類型的對象都存在多態(tài)引用
method(Object obj){…} //可以接收任何類作為其參數(shù) Person o = new Person(); method(o);
- 所有對象(包括數(shù)組)都實(shí)現(xiàn)這個類的方法
- 一個類沒有特別指定父類,那么默認(rèn)則繼承自O(shè)bject類
public class Person { ... } //上面和下面是等價的 public class Person extends Object { ... }
Object類的方法
根據(jù)JDK源代碼及Object類的API文檔,Object類中包含的方法有11個,但是今天只看其中主要的5個。
equals()
所有類都繼承了Object,那么也就獲得了equals()方法,且還可以重寫方法。 equals():
- 只能比較引用類型,比較是否指向同一個對象
- 格式:
obj1.equals(obj2)
- 特例:當(dāng)用equals()方法進(jìn)行比較時,對類File、String、Date及包裝類來說,是比較類型及內(nèi)容而不考慮引用的是否是同一個對象,因?yàn)樵谶@些類中重寫了Object類的equals()方法
- 當(dāng)自定義equals()方法時,可以重寫方法,用來比較兩個對象的內(nèi)容是否一樣
重寫equals()方法的原則:
- 對稱性:如果x.equals(y)返回是true,那么y.equals(x)也應(yīng)該返回是true
- 自反性:x.equals(x)必須返回是true
- 傳遞性:如果x.equals(y)返回是true,且y.equals(z)返回是true,那么z.equals(x)也應(yīng)該返回true
- 一致性:如果x.equals(y)返回是true,只要x和y內(nèi)容不變,無論重復(fù)x.equals(y)多少次,都是返回true
- 任何情況下,x.equals(null)都是返回false,x.equals(和x是不同類型的對象)都是返回false
重寫舉例:
class User{ private String host; private String username; private String password; public User(String host, String username, String password) { super(); this.host = host; this.username = username; this.password = password; } public User() { super(); } public String getHost() { return host; } public void setHost(String host) { this.host = host; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Override public String toString() { return "User [host=" + host + ", username=" + username + ", password=" + password + "]"; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; User other = (User) obj; if (host == null) { if (other.host != null) return false; } else if (!host.equals(other.host)) return false; if (password == null) { if (other.password != null) return false; } else if (!password.equals(other.password)) return false; if (username == null) { if (other.username != null) return false; } else if (!username.equals(other.username)) return false; return true; } }
= =:
- 基本類型比較的是值:只要兩個變量的值相等,即為true
- 引用類型比較引用(是否指向同一個對象):只有指向同一個對象時,才返回true
注意: 用來進(jìn)行比較時,符號兩邊的數(shù)據(jù)類型必須兼容(可自動轉(zhuǎn)換的基本數(shù)據(jù)類型除外),否則編譯報錯。
= =和equals的區(qū)別:
- = =即可以比較基本數(shù)據(jù)類型也可以比較引用類型,對于基本類型就是比較數(shù)值,對于引用類型就是比較內(nèi)存地址
- equals是屬于java.lang.Object類里面的方法,如果該方法沒有被重寫,默認(rèn)也是= =,String等類的equals方法是被重寫過的,而且String類在日常開發(fā)中用的較多,形成了equals是比較值的錯誤觀點(diǎn),這點(diǎn)要注意
- 具體要看自定義類型里有沒有重寫Object的equals方法來判斷
- 通常情況下,重寫equals方法,會比較類中的相應(yīng)屬性是否都相等
toString()
public String toString()
:默認(rèn)情況下toString()返回的是對象的運(yùn)行時類型@對象的hashCode值的十六進(jìn)制形式。
在進(jìn)行String與其他類型數(shù)據(jù)的連接操作時,自動調(diào)用toString方法,比如:
Date now=new Date(); System.out.println("now="+now); //相當(dāng)于"now="+now.toString()
如果直接打印對象,默認(rèn)會調(diào)用該對象的toString()方法(Java的引用數(shù)據(jù)類型的變量中存儲的實(shí)際上是對象的內(nèi)存地址,但是Java對外隱藏了內(nèi)存地址信息,所以不能直接將內(nèi)存地址顯示出來,所以當(dāng)打印對象時,JVM會調(diào)用對象的toString()方法)。
可以根據(jù)需要在用戶自定義類型中重寫toString()方法。
getClass()
public final Class<?> getClass()
:獲取對象的運(yùn)行時類型。
由于Java有多態(tài)現(xiàn)象,所以一個引用數(shù)據(jù)類型的變量編譯時類型與運(yùn)行時類型可能不一致,因此如果需要查看這個變量實(shí)際指向的對象的類型,就需要用getClass()
方法。
public static void main(String[] args) { Object obj = new Person(); System.out.println(obj.getClass()); //獲取運(yùn)行時類型 }
hashCode()
public int hashCode()
:返回每個對象的hash值。
如果重寫equals,那么通常會一起重寫hashCode()方法,hashCode()方法主要是為了當(dāng)對象存儲到哈希表等容器中時提高存儲和查詢性能用的,這是因?yàn)殛P(guān)于hashCode()有兩個常規(guī)協(xié)定:
- 如果兩個對象的hash值不同,那么這兩個對象一定不相等
- 如果兩個對象的hash值是相同的,那么這兩個對象不一定相等
重寫equals()和hashCode()方法時,要保證滿足如下要求:
- 如果兩個對象調(diào)用equals返回true,那么要求這兩個對象的hashCode值一定是相等的
- 如果兩個對象的hashCode值不同,那么要求這兩個對象調(diào)用equals方法一定是false
- 如果兩個對象的hashCode值相同,那么這兩個對象調(diào)用equals可能是true,也可能是false
public static void main(String[] args) { System.out.println("Aa".hashCode()); //2112 System.out.println("BB".hashCode()); //2112 }
clone()
clone()方法將對象復(fù)制了一份并返回給調(diào)用者,clone()的作用在于復(fù)制對象,在復(fù)制對象的過程中,首先要分配一個和源對象同樣大小的空間,在這個空間中創(chuàng)建一個新的對象。
示例:
public class CloneTest { public static void main(String[] args) { Animal a1 = new Animal("小黑"); try { Animal a2 = (Animal) a1.clone(); System.out.println("原始對象:" + a1); a2.setName("小黃"); System.out.println("clone的對象:" + a2); } catch (CloneNotSupportedException e) { e.printStackTrace(); } } } class Animal implements Cloneable{ private String name; public Animal() { super(); } public Animal(String name) { super(); this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Animal [name=" + name + "]"; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } }
finalize()
當(dāng)對象被回收時,系統(tǒng)自動調(diào)用該對象的finalize()方法,子類可以重寫該方法,做一些釋放資源的操作。如果重寫該方法,讓一個新的引用變量重新引用該對象,則會重新激活對象。
永遠(yuǎn)不要主動調(diào)用某個對象的finalize方法,應(yīng)該交給垃圾回收機(jī)制調(diào)用。
什么時候被回收:
當(dāng)某個對象沒有任何引用時,JVM就認(rèn)為這個對象是垃圾對象,就會在之后不確定的時間使用垃圾回收機(jī)制來銷毀該對象,在銷毀該對象前,會先調(diào)用finalize()方法(垃圾回收發(fā)生具有不可預(yù)知性,程序無法精確控制垃圾回收機(jī)制的執(zhí)行)。
垃圾回收機(jī)制的調(diào)用是由系統(tǒng)來決定的,也可以通過System.gc()或者Runtime.getRuntime().gc()來通知系統(tǒng)進(jìn)行垃圾回收,會有一些效果,但是系統(tǒng)是否進(jìn)行垃圾回收依然是不確定的。
public class FinalizeTest { public static void main(String[] args) { Person p = new Person("Peter", 12); System.out.println(p); p = null; //此時對象實(shí)體就是垃圾對象,等待被回收,但時間不確定 System.gc();//強(qiáng)制性釋放空間 } } class Person{ private String name; private int age; public Person(String name, int age) { super(); 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; } //子類重寫此方法,可在釋放對象前進(jìn)行某些操作 @Override protected void finalize() throws Throwable { System.out.println("對象被釋放--->" + this); } @Override public String toString() { return "Person [name=" + name + ", age=" + age + "]"; } }
native關(guān)鍵字的理解
使用native關(guān)鍵字說明這個方法是原生函數(shù),也就是這個方法是用c/c++等非Java語言實(shí)現(xiàn)的,并且被編譯成了dll,由Java去調(diào)用,在定義一個native方法時,并不提供實(shí)現(xiàn)體。
為什么要用native方法
雖然Java使用起來非常方便,然而有些層次的任務(wù)用Java實(shí)現(xiàn)起來不易,或?qū)Τ绦虻男屎茉谝鈺r就會考慮native方法。
例如:有時Java應(yīng)用需要與Java外面的環(huán)境交互,這是本地方法存在的主要原因,當(dāng)Java需要與一些底層系統(tǒng)如操作系統(tǒng)或某些硬件交換信息時的情況,本地方法正是這樣的一種交流機(jī)制,它提供了一個非常簡潔的接口,而且無需我們?nèi)チ私釰ava應(yīng)用之外的繁瑣細(xì)節(jié)。
native聲明的方法,對于調(diào)用者可以當(dāng)做其他Java方法一樣使用
一個native方法可以返回任何Java類型,包括非基本類型,而且同樣可以進(jìn)行異??刂啤?/p>
native方法的存在并不會對其他類調(diào)用這些本地方法產(chǎn)生任何的影響,實(shí)際上調(diào)用這些方法的其他類甚至不知道它調(diào)用的是一個本地方法,JVM將控制調(diào)用本地方法的所有細(xì)節(jié)。
如果一個含有本地方法的類被繼承,子類會繼承這個本地方法并且可以用Java在需要的時候重寫該方法。
以上就是Java中Object類的理解和使用的詳細(xì)內(nèi)容,更多關(guān)于Java Object類的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Java實(shí)現(xiàn)導(dǎo)出Word文檔的示例代碼
poi-tl是一個基于Apache POI的Word模板引擎,也是一個免費(fèi)開源的Java類庫,你可以非常方便的加入到你的項(xiàng)目中。本文就利用它實(shí)現(xiàn)導(dǎo)出Word文檔功能,需要的可以參考一下2023-02-02詳解java實(shí)現(xiàn)HTTP請求的三種方式
這篇文章主要介紹了java實(shí)現(xiàn)HTTP請求的三種方式,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04SpringBoot解決同名類導(dǎo)致的bean名沖突bean name conflicts問題
這篇文章主要介紹了SpringBoot解決同名類導(dǎo)致的bean名沖突bean name conflicts問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-06-06解決IDEA2020 創(chuàng)建maven項(xiàng)目沒有src/main/java目錄和webapp目錄問題
這篇文章主要介紹了IDEA2020 創(chuàng)建maven項(xiàng)目沒有src/main/java目錄和webapp目錄問題解決方法,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-10-10Spring?Boot?集成JWT實(shí)現(xiàn)前后端認(rèn)證的示例代碼
小程序、H5應(yīng)用的快速發(fā)展,使得前后端分離已經(jīng)成為了趨勢,本文主要介紹了Spring?Boot?集成JWT實(shí)現(xiàn)前后端認(rèn)證,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-04-04