Object物件你真理解了嗎?

Java3y發表於2018-05-03

前言

五一回家又斷更了一個放假時間了~~~

只有光頭才能變強

回顧前面:

之前花了點之間時間去搞多執行緒的基礎知識了,難呀難呀難呀....打算寫一篇執行緒池的就暫時將多執行緒系列停止了...

今天中午在逛簡書的時候發現一些大廠也會問Object物件裡面有什麼方法(也算是一個知識點吧),Object我還沒去認真複習過,於是這篇主要看看Object物件有什麼要注意的地方~

那麼接下來就開始吧,如果文章有錯誤的地方請大家多多包涵,不吝在評論區指正哦~

一、Object物件簡介

宣告:本文都是使用JDK1.8

我們學Java的知道,Java是一門物件導向的語言。無論在Java中出現什麼,都可以認為它是物件(除了八大基本資料型別。當然了,八大基本資料型別也能裝箱成為物件):

  • 而Object就是這些物件的最高階別的,所有的Java物件都隱式地繼承了Object物件(不用顯示寫extends繼承)
  • 所有的Java物件都擁有Object預設的方法

那麼我們看看Object有什麼方法:

Object物件你真理解了嗎?

其實就可以歸納成幾個:

  • registerNatives()【底層實現、不研究】
  • hashCode()
  • equals(Object obj)
  • clone()
  • toString()
  • notify()
  • notifyAll()
  • wait(long timeout)【還有過載了兩個】
  • finalize()

Object一共有11個方法,其中一個為底層的實現registerNatives(),其中兩個wait()wait(long timeout, int nanos)過載方法。

  • 所以我們真正需要看的就是8個方法

還有一個屬性


 public final native Class<?> getClass();

複製程式碼

Object物件你真理解了嗎?

二、equals和hashCode方法

equals和hashCode方法可以說是面試的重點題了,配合著String可以說在面試題中哪都有它們的存在

首先,我們來看看equals和hashCode在Object中原生的實現吧:

hashCode:


public native int hashCode();

複製程式碼

equals:


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

複製程式碼

看上去都非常簡單:

  • hashCode()由native方法底層實現了。
  • equals()就直接==判斷是否相等了。

想要更加清晰它們究竟是做什麼的,我們來讀讀它的註釋:

Object物件你真理解了嗎?

Object物件你真理解了嗎?

根據註釋我們可以總結以下的要點

  • 重寫equals()方法,就必須重寫hashCode()的方法
  • equals()方法預設是比較物件的地址,使用的是==等值運算子
  • hashCode()方法對底層是雜湊表的物件有提升效能的功能
  • 同一個物件(如果該物件沒有被修改):那麼重複呼叫hashCode()那麼返回的int是相同的!
  • hashCode()方法預設是由物件的地址轉換而來的
  • equals()方法還有5個預設的原則:
    • 自反性--->呼叫equals()返回的是true,無論這兩個物件誰呼叫equals()都好,返回的都是true
    • 一致性--->只要物件沒有被修改,那麼多次呼叫還是返回對應的結果!
    • 傳遞性--->x.equals(y)y.equals(z)都返回true,那麼可以得出:x.equals(z)返回true
    • 對稱性--->x.equals(y)y.equals(x)結果應該是相等的。
    • 傳入的引數為null,返回的是false

為啥說hashCode()以雜湊表為底層帶來效能的提升是很容易理解的。我們再來回顧一下HashMap的插入:

Object物件你真理解了嗎?

如果hash值都不相等,那麼可以直接判斷該key是不相等的了!

2.1equals和hashCode方法重寫

equals()方法預設是比較物件的地址,使用的是==等值運算子。但是按我們正常開發來說,比較的是物件地址是沒有意義的

  • 一般地,如果我們有兩個Address物件,只要這兩個物件的省號、城市號、街道號相等,我們就認為這兩個物件相等了!

Object物件你真理解了嗎?

2.2String實現的equals和hashCode方法

我們在初學的時候可能就聽過了:String已經實現了equals和hashCode方法了。

  • 這也就是為什麼,我們可以直接使用String.equals()來判斷兩個字串是否相等!

下面我們就來看看它的實現吧:

Object物件你真理解了嗎?

Object物件你真理解了嗎?

三、toString方法

接下來我們看看toString方法,也十分簡單:

Object物件你真理解了嗎?

toString方法主要是用來標識該物件的:

Object物件你真理解了嗎?

從上面的結果我們都可以看出來:得出的結果我們並不能看到什麼東西~

於是我們一般都重寫toString(),那麼列印出的結果就很方便我們除錯了


    @Override
    public String toString() {
        return "Address{" +
                "provinceNo=" + provinceNo +
                ", cityNo=" + cityNo +
                ", streetNo=" + streetNo +
                '}';
    }
複製程式碼

下面的結果看起來就好多了:

Object物件你真理解了嗎?

四、clone方法

我們也來看看它的頂部註釋:

Object物件你真理解了嗎?

看了上面的註釋我們可以總結以下的要點

  • clone方法用於物件的克隆,一般想要克隆出的物件是獨立的(與原有的物件是分開的)
  • 深拷貝指的是該物件的成員變數(如果是可變引用)都應該克隆一份,淺拷貝指的是成員變數沒有被克隆一份

下面我們來看一下淺拷貝:拷貝了Employee物件,但是其成員變數hireday沒有被克隆出去,所以指向的還是同一個Date物件

Object物件你真理解了嗎?

4.1clone用法

那麼我們如何克隆物件呢?無論是淺拷貝還是深拷貝都是這兩步:

  1. 克隆的物件要實現Cloneable介面
  2. 重寫clone方法,最好修飾成public

淺拷貝:僅僅拷貝了Person物件,而date沒有拷貝!


public class Person implements Cloneable {

    // 可變的成員變數
    private Date date;

    @Override
    public Object clone() throws CloneNotSupportedException {

        return super.clone();
    }

}
複製程式碼

深拷貝:不僅拷貝了Person物件,也拷貝了date成員變數


public class Person implements Cloneable {

    // 可變的成員變數
    public  Date date;

    @Override
    public Object clone() throws CloneNotSupportedException {


        // 拷貝Person物件
        Person person = (Person) super.clone();

        // 將可變的成員變數也拷貝
        person.date = (Date) date.clone();


        // 返回拷貝的物件
        return person;
    }

}
複製程式碼

4.2clone疑問進一步學習protected

不知道有沒有人跟我有相同的疑問

  • 我只想要淺拷貝,能不能直接呼叫該物件.clone()來實現

比如我現在有個Address物件:


public class Address  {

    private int provinceNo;
    private int cityNo;
    private int streetNo;

    public Address() {
    }

    public Address(int provinceNo, int cityNo, int streetNo) {
        this.provinceNo = provinceNo;
        this.cityNo = cityNo;
        this.streetNo = streetNo;
    }
}
複製程式碼

下面的程式碼你們認為如何


    Address address = new Address(1, 2, 3);
    address.clone();

複製程式碼

我們都知道:

  • protected修飾的類和屬性,對於自己、本包和其子類可見

可能會想clone()方法是定義在Object類上的(以protected來修飾),而我們自定義的Address物件隱式繼承著Object(所有的物件都是Object的子類),那麼子類呼叫Object以protected來修飾clone()是完全沒問題的

  • 但是,IDE現實告訴我,這編譯就不通過了

Object物件你真理解了嗎?

出現錯誤的原因我立馬就想到:是不是我對protected修飾符出現了偏差?

protected修飾的類和屬性,對於自己、本包和其子類可見,這句話本身是沒有錯的。但是還需要補充:對於protected的成員或方法,要分子類和超類是否在同一個包中。與基類不在同一個包中的子類,只能訪問自身從基類繼承而來的受保護成員,而不能訪問基類例項本身的受保護成員

  • 上面的程式碼就錯在:Address與Object不是在同一個包下的,而Address直接訪問了Object的clone方法。這是不行的。

下面我截兩張圖再來給你們看看(看完圖再看上面的描述,就能理解了):

Object物件你真理解了嗎?

Object物件你真理解了嗎?

圖片來源和更多的展開閱讀blog.csdn.net/wangyanguiy…

五、wait和notify方法

wait和notify方法其實就是Java給我們提供讓執行緒之間通訊的API。

按照慣例我們還是來看註釋怎麼說吧:

wait方法:

Object物件你真理解了嗎?

notify方法:

Object物件你真理解了嗎?

notifyAll()方法:

Object物件你真理解了嗎?

看完上面的註釋我們可以總結以下的要點

  • 無論是wait、notify還是notifyAll()都需要由監聽器物件(鎖物件)來進行呼叫
    • 簡單來說:他們都是在同步程式碼塊中呼叫的,否則會丟擲異常!
  • notify()喚醒的是在等待佇列的某個執行緒(不確定會喚醒哪個),notifyAll()喚醒的是等待佇列所有執行緒
  • 導致wait()的執行緒被喚醒可以有4種情況
    • 該執行緒被中斷
    • wait()時間到了
    • notify()喚醒
    • notifyAll()喚醒
  • 呼叫wait()的執行緒會釋放掉鎖

其實總結完上面的並不會有比較深刻的印象,可以嘗試著回答幾個問題來加深對wait()notify()的理解。

5.1為什麼wait和notify在Object方法上?

從一開始我們就說了:wait()notify()是Java給我們提供執行緒之間通訊的API,既然是執行緒的東西,那什麼是在Object類上定義,而不是在Thread類上定義呢?

因為我們的鎖是物件鎖【要是忘記的同學可回顧:Java鎖機制瞭解一下】,每個物件都可以成為鎖。讓當前執行緒等待某個物件的鎖,當然應該通過這個物件來操作了

  • 鎖物件是任意的,所以這些方法必須定義在Object類中

5.2notify方法呼叫後,會發生什麼?

上面已經說了,notify會喚醒某個處於等待佇列的執行緒。

但是要注意的是:

  • notify方法呼叫後,被喚醒的執行緒不會立馬獲得到鎖物件。而是等待notify的synchronized程式碼塊執行完之後才會獲得鎖物件

5.3sleep和wait有什麼區別?

Thread.sleep()Object.wait()二者都可以暫停當前執行緒,釋放CPU控制權。

  • 主要的區別在於Object.wait()在釋放CPU同時,釋放了物件鎖的控制
  • Thread.sleep()沒有對鎖釋放

參考資料:

六、finalize()方法

finalize()方法將在垃圾回收器清除物件之前呼叫,但該方法不知道何時呼叫,具有不定性

  • 一般我們都不會重寫它~

一個物件的finalize()方法只會被呼叫一次,而且finalize()被呼叫不意味著gc會立即回收該物件,所以有可能呼叫finalize()後,該物件又不需要被回收了,然後到了真正要被回收的時候,因為前面呼叫過一次,所以不會呼叫finalize(),產生問題。

參考資料:

進階的資料:

七、總結

總的來說也算是把Object看了一遍了,不至於一下子把它的方法給忘了~~~在學習的過程中也遇到過問題,最明顯的是對protected修飾符又加深了一次理解。

Object物件你真理解了嗎?

參考資料:

  • 《Java核心技術卷一》

如果文章有錯的地方歡迎指正,大家互相交流。習慣在微信看技術文章,想要獲取更多的Java資源的同學,可以關注微信公眾號:Java3y

文章的目錄導航

相關文章