Java Object類方法解析

Java Object類方法解析

在Java中Object是全部類的父類,任何類都默認繼承Object,其提供的方法主要有如下幾種:java

  • registerNatives()算法

  • hashCode和equale函數用來判斷對象是否相同,數組

  • wait(),wait(long),wait(long,int),notify(),notifyAll()函數

  • toString()和getClass性能

  • clone()this

  • finalize()用於在垃圾回收編碼

下面介紹下各個方法:操作系統

registerNatives()

registerNatives函數前面有native關鍵字修飾,Java中,用native關鍵字修飾的函數代表該方法的實現並非在Java中去完成,而是由C/C++ 去完成,並被編譯成了.dll,由Java去調用。方法的具體實現體在dll文件中,對於不一樣平臺,其具體實現應該有所不一樣。用native修飾,即表示操做系統,須要提供此方法,Java自己須要使用。具體到registerNatives()方法自己,其主要做用是將C/C++中的方法映射到Java中的native方法,實現方法命名的解耦。
在Java源碼中,此方法在靜態代碼塊中被調用:線程

private static native void registerNatives ();
  static {
     registerNatives();
 }

equales

equales常常跟「= =」作比較,二者區別是:
「= =」表示的是變量值徹底相同(對於基礎類型,地址中存儲的是值,引用類型則存儲指向實際對象的地址,因此基本數據類型:「= =」比較的是他們的值。引用類型(類、接口、數組) :用 「= =」 進行比較的時候,比較的是他們在內存中的存放地址,除非是同一個new出來的對象,他們的比較後的結果爲true,不然比較後結果爲false。)
咱們知道對象在JVM中是存放放在Java堆中的,Java虛擬機棧中存放的是對象的引用(地址)。因而可知 「= =」 是對Java虛擬機棧中的值進行比較的。若是要比較Java堆中對象的內容是否相同,那麼就須要使用equals方法了。
equals表示的是對象的內容徹底相同,此處的內容多指對象的特徵/屬性。 Object類中關於equals()方法的定義以下:翻譯

public boolean equals(Object var1) {
        return this == var1;
    }

Object原生的equals()方法內部調用的正是= =,與= =具備相同的含義。既然如此,爲何還要定義此equals()方法?
equlas()方法的正確理解應該是:判斷兩個對象是否相等。那麼判斷對象相等的標尺又是什麼?
如上,在object類中,此標尺即爲==。固然,這個標尺不是固定的,其餘類中能夠按照實際的須要對此標尺含義進行重定義。如String類中則是依據字符串內容是否相等來重定義了此標尺含義。如此能夠增長類的功能性和實際編碼的靈活性。固然了,若是自定義的類沒有重寫equals()方法來從新定義此標尺,那麼默認的將是其父類的equals(),直到object基類。
String 類的equals方法:

public boolean equals(Object var1) {
        if (this == var1) {
            return true;
        } else {
            if (var1 instanceof String) {
                String var2 = (String)var1;
                int var3 = this.value.length;
                if (var3 == var2.value.length) {
                    char[] var4 = this.value;
                    char[] var5 = var2.value;

                    for(int var6 = 0; var3-- != 0; ++var6) {
                        if (var4[var6] != var5[var6]) {
                            return false;
                        }
                    }

                    return true;
                }
            }

            return false;
        }
    }

String中equals方法判斷相等的步驟是:
1).若A==B 便是同一個String對象 返回true
2).若對比對象是String類型則繼續,不然返回false
3).判斷A、B長度是否同樣,不同的話返回false
4).逐個字符比較,如有不相等字符,返回false
注:Java中約定重寫equals()方法必須重寫hasCode()方法。

最後總結下:

==比較的是「值」(引用數據類型是比較其內存地址值,基本數據類型是比較變量值)

equals比較的是對象的內容,對內容比較的標尺能夠由子類本身定義。

hashCode

hashCode()方法返回一個整形數值,表示該對象的哈希碼值。
hashCode()具備以下約定:
1).在Java應用程序程序執行期間,對於同一對象屢次調用hashCode()方法時,其返回的哈希碼是相同的,前提是將對象進行equals比較時所用的標尺信息未作修改。在Java應用程序的一次執行到另一次執行,同一對象的hashCode()返回的哈希碼無須保持一致;
2).若是兩個對象相等(依據:調用equals()方法),那麼這兩個對象調用hashCode()返回的哈希碼也必須相等;
3).反之,兩個對象調用hasCode()返回的哈希碼相等,這兩個對象不必定相等。
即嚴格的數學邏輯表示爲: 兩個對象相等 <=> equals()相等 => hashCode()相等。所以,重寫equlas()方法必須重寫hashCode()方法,以保證此邏輯嚴格成立,同時能夠推理出:hasCode()不相等 => equals()不相等 <=> 兩個對象不相等。
可能有人在此產生疑問:既然比較兩個對象是否相等的惟一條件(也是充要條件)是equals,那麼爲何還要弄出一個hashCode(),而且進行如此約定,弄得這麼麻煩?
其實,這主要體如今hashCode()方法的做用上,其主要用於加強哈希表的性能。
以集合類中的Set爲例,當新加一個對象時,須要判斷現有集合中是否已經存在與此對象相等的對象,若是沒有hashCode()方法,須要將Set進行一次遍歷,並逐一用equals()方法判斷兩個對象是否相等,此種算法時間複雜度爲o(n)。經過藉助於hasCode方法,先計算出即將新加入對象的哈希碼,而後根據哈希算法計算出此對象的位置,直接判斷此位置上是否已有對象便可。(注:Set的底層用的是Map的原理實現)
在此須要糾正一個理解上的誤區:對象的hashCode()返回的不必定是對象所在的物理內存地址。甚至也不必定是對象的邏輯地址,hashCode()相同的兩個對象,不必定相等,換言之,不相等的兩個對象,hashCode()返回的哈希碼可能相同。
小結:
1).若是兩個對象equals,Java運行時環境會認爲他們的hashcode必定相等。
2).若是兩個對象不equals,他們的hashcode有可能相等。
3).若是兩個對象hashcode相等,他們不必定equals。
4).若是兩個對象hashcode不相等,他們必定不equals。
爲了比較兩個對象時更高效,判斷兩個對象是否相等能夠採用如下規則:
第一步,若是hashCode()相等,則查看第二步,不然不相等;
第二步,查看equals()是否相等,若是相等,則兩obj相等,不然仍是不相等。

wait(),wait(long),wait(long,int),notify(),notifyAll()

一說到wait(…) / notify() /notifyAll()這幾個方法,首先想到的是線程。確實,這幾個方法主要用於java線程之間的通訊協做。先具體看下這幾個方法的主要含義:
一、wait(…)方法調用後當前線程將當即阻塞,且釋放其所持有的同步代碼塊中的鎖,直到被喚醒或超時或打斷後且從新獲取到鎖後才能繼續執行;
二、notify()/notifyAll()方法調用後,其所在線程不會當即釋放所持有的鎖,直到其所在同步代碼塊中的代碼執行完畢,此時釋放鎖,所以,若是其同步代碼塊後還有代碼,其執行則依賴於JVM的線程調度。

注:wait(…) / notify() / notifyAll()通常狀況下都是配套使用。且wait(…)/notify()|notifyAll()方法只能在同步代碼塊中才能使用。

爲何Object這個基類會提供這類方法?由於定義在Object中就能夠實現將任何對象視爲線程同步中的監聽器。

對於wait和notify方法咱們在Java線程部分還會再次分析。

toString()

toString()方法返回該對象的字符串表示。先看一下Object中的具體方法體:

public String toString() {
        return this.getClass().getName() + "@" + Integer.toHexString(this.hashCode());
    }

toString()方法相信你們都常常用到,即便沒有顯式調用,但當咱們使用System.out.println(obj)時,其內部也是經過toString()來實現的。

Object類的toString()方法返回的是對象的類型和其哈希碼,子類能夠重寫該方法以打印本身想要打印的內容。

getClass

getClass()是一個native方法,返回的是此Object對象的類對象/運行時類對象Class<?>。
首先解釋下」類對象」的概念:在Java中,類是是對具備一組相同特徵或行爲的實例的抽象描述,對象則是此類所描述的特徵或行爲的具體實例。做爲概念層次的類,其自己也具備某些共同的特性,如都具備類名稱、由類加載器去加載,都具備包,具備父類,屬性和方法等。因而,Java中有專門定義了一個類,Class類,去描述其餘類所具備的這些特性,今後角度去看,類自己是屬於Class類的對象,咱們稱之爲」類對象」。

clone()

clone()方法一樣是native方法,所以,咱們知道了clone()方法並非Java的原生方法,具體的實現是有C/C++完成的。clone英文翻譯爲」克隆」,其目的是建立並返回此對象的一個副本。Java術語表述爲:clone函數返回的是一個引用,該引用指向的是新的clone出來的對象,此對象與原對象分別佔用不一樣的堆空間。
同時Java中的語法規定:
clone()的正確調用是須要實現Cloneable接口,若是沒有實現Cloneable接口,而且子類直接調用Object類的clone()方法,會拋出CloneNotSupportedException異常。
Cloneable接口僅是一個表示接口,接口自己不包含任何方法,用來指示Object.clone()能夠合法的被子類引用所調用。

finalize()

finalize方法主要與Java垃圾回收機制有關。首先咱們看一下finalized方法在Object中的具體定義:

protected void finalize() throws Throwable {
    }

咱們發現Object類中finalize方法被定義成一個空方法,爲何要如此定義呢?finalize方法的調用時機是怎麼樣的呢? 首先,Object中定義finalize方法代表Java中每個對象都將具備finalize這種行爲,其具體調用時機在:JVM準備對此對象所佔用的內存空間進行垃圾回收前,將會調用其finalize。由此能夠看出,此方法並非由咱們主動去調用的。

相關文章
相關標籤/搜索