亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專(zhuān)欄INFORMATION COLUMN

JDK源碼閱讀(一):Object源碼分析

xuexiangjys / 2674人閱讀

摘要:最近經(jīng)過(guò)某大佬的建議準(zhǔn)備閱讀一下的源碼來(lái)提升一下自己所以開(kāi)始寫(xiě)源碼分析的文章閱讀版本為目錄結(jié)構(gòu)圖構(gòu)造器方法方法方法方法方法方法結(jié)構(gòu)圖類(lèi)構(gòu)造器類(lèi)構(gòu)造器是創(chuàng)建對(duì)象的方法之一。還有一種情況是兩個(gè)元素不相同,但是相同,這就是哈希碰撞。

最近經(jīng)過(guò)某大佬的建議準(zhǔn)備閱讀一下JDK的源碼來(lái)提升一下自己

所以開(kāi)始寫(xiě)JDK源碼分析的文章

閱讀JDK版本為1.8

目錄

Object結(jié)構(gòu)圖

構(gòu)造器

equals 方法

getClass 方法

hashCode 方法

toString 方法

finalize 方法

registerNatives 方法

1. Object結(jié)構(gòu)圖

2. 類(lèi)構(gòu)造器

??類(lèi)構(gòu)造器是創(chuàng)建Java對(duì)象的方法之一。一般我們都使用new關(guān)鍵字來(lái)進(jìn)行實(shí)例,還可以在構(gòu)造器中進(jìn)行相應(yīng)的初始化操作。

??在一個(gè)Java類(lèi)中必須存在一個(gè)構(gòu)造器,如果沒(méi)有添加系統(tǒng)在編譯時(shí)會(huì)默認(rèn)創(chuàng)建一個(gè)無(wú)參構(gòu)造。

/*實(shí)例一個(gè)Object對(duì)象*/
Object obj = new Object()
3. equals 方法

??在面試中面試官經(jīng)常會(huì)問(wèn) equals() 方法和 == 運(yùn)算符的區(qū)別,== 運(yùn)算符用于比較基本類(lèi)型的值是否相同而 equals 用于比較兩個(gè)對(duì)象是否相等,那么有個(gè)問(wèn)題來(lái)了,兩個(gè)對(duì)象怎么才算是相等的呢。
看object中的equals實(shí)現(xiàn)

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

在Object中equals和==是等價(jià)的。所以在Object中兩個(gè)對(duì)象的引用相同,那么一定就是相同的。在我們自定義對(duì)象的時(shí)候一定要重寫(xiě)equals方法。我參考了以下網(wǎng)上的資料來(lái)分析一下String中重寫(xiě)的 equals方法:

public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String anotherString = (String)anObject;
            int n = value.length;
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }

String 是引用類(lèi)型,比較時(shí)不能比較引用是否相等,重點(diǎn)是字符串的內(nèi)容是否相等。所以 String 類(lèi)定義兩個(gè)對(duì)象相等的標(biāo)準(zhǔn)是字符串內(nèi)容都相同。

在Java規(guī)范中,對(duì) equals 方法的使用必須遵循以下幾個(gè)原則:

自反性:對(duì)于任何非空引用值 x,x.equals(x) 都應(yīng)返回 true。

對(duì)稱(chēng)性:對(duì)于任何非空引用值 x 和 y,當(dāng)且僅當(dāng) y.equals(x) 返回 true 時(shí),x.equals(y) 才應(yīng)返回 true。

傳遞性:對(duì)于任何非空引用值 x、y 和 z,如果 x.equals(y) 返回 true,并且 y.equals(z) 返回 true,那么 x.equals(z) 應(yīng)返回 true。

一致性:對(duì)于任何非空引用值 x 和 y,多次調(diào)用 x.equals(y) 始終返回 true 或始終返回 false,前提是對(duì)象上 equals 比較中所用的信息沒(méi)有被修改

對(duì)于任何非空引用值 x,x.equals(null) 都應(yīng)返回 false



下面定義一個(gè)類(lèi),在這個(gè)類(lèi)中重寫(xiě)equals方法 對(duì)象屬性相同則相等 否則不相等

public class Student {
    private String name;

    /**
     * 無(wú)參構(gòu)造方法
     */
    public Student() {

    }

    /**
     * 無(wú)參構(gòu)造方法
     */
    public Student(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public boolean equals(Object obj) {
        //引用相同 兩個(gè)對(duì)象肯定是相同的
        if(this==obj){
            return true;
        }
        //對(duì)象等于空 或者不是Student 是不想等的
        if(obj==null || !(obj instanceof Student)){
            return false;
        }
        //轉(zhuǎn)為Student對(duì)象
        Student student = (Student)obj;
        //屬性相同 返回true
        return this.getName()==student.getName();
    }

}

然后創(chuàng)建一個(gè)測(cè)試類(lèi)來(lái)進(jìn)行測(cè)試:

        Student t1 = new Student("yes");
        Student t2 = new Student("slm");
        System.out.println("對(duì)象不同 屬性不同 ==  "+(t1==t2));
        System.out.println("對(duì)象不同 屬性不同 equals  "+(t1.equals(t2)));
        Student t3 = new Student("slm");
        System.out.println("對(duì)象不同 屬性相同"+(t2.equals(t3)));

輸出結(jié)果:

對(duì)象不同 屬性不同 ==  false 

對(duì)象不同 屬性不同 equals false

對(duì)象不同 屬性相同true

現(xiàn)在可以看出 如果在這里不重寫(xiě)equals方法的話永遠(yuǎn)只會(huì)執(zhí)行Object的equals也就是通過(guò)==對(duì)比對(duì)象引用地址是否相同。


下面再看一個(gè)例子,這個(gè)時(shí)候如果出現(xiàn)一個(gè)Student的子類(lèi)我們?cè)趯?duì)比一下

/**
 * @Author: sunluomeng
 * @CreateTime: 2019-06-06 23:35
 * @Description:
 */
public class Language  extends Student{
    private String name;

    /**
     * 無(wú)參構(gòu)造
     */
    public Language(){

    }

    /**
     * 有參構(gòu)造
     * @param name
     */
    public Language(String name){
        this.name=name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public boolean equals(Object obj) {
        //引用相同 兩個(gè)對(duì)象肯定是相同的
        if(this==obj){
            return true;
        }
        //對(duì)象等于空 或者不是Student 是不想等的
        if(obj==null || !(obj instanceof Language)){
            return false;
        }
        //轉(zhuǎn)為Student對(duì)象
        Language language = (Language)obj;
        //屬性相同 返回true
        return this.getName()==language.getName();
    }

}

這個(gè)時(shí)候我們的新創(chuàng)建的Language類(lèi)繼承Student然后創(chuàng)建兩個(gè)對(duì)象去做比較


輸出結(jié)果:

父類(lèi)對(duì)比子類(lèi) 屬性相同---true 

子類(lèi)對(duì)比父類(lèi) 屬性相同---false

可以看出父類(lèi)去對(duì)比子類(lèi)既 student.equals(language) 結(jié)果為true 而子類(lèi)去對(duì)比父類(lèi) 既 language.equals(student) 返回false

這樣的話就違反了問(wèn)哦們上面說(shuō)到的對(duì)稱(chēng)性

對(duì)于任何非空引用值 x 和 y,當(dāng)且僅當(dāng) y.equals(x) 返回 true 時(shí),x.equals(y) 才應(yīng)返回 true

如果y是Student x 是Language
那么現(xiàn)在就是 y.equals(x) 等于true 反過(guò)來(lái)x.equals(y)也應(yīng)該返回true,但是現(xiàn)在為什么會(huì)返回false呢?

先來(lái)看一下代碼


我們?cè)谂袛嗟臅r(shí)候使用了instanceof關(guān)鍵字來(lái)判斷運(yùn)行的時(shí)候是否是指定的類(lèi)型

java 中的instanceof 運(yùn)算符是用來(lái)在運(yùn)行時(shí)指出對(duì)象是否是特定類(lèi)的一個(gè)實(shí)例。instanceof通過(guò)返回一個(gè)布爾值來(lái)指出,這個(gè)對(duì)象是否是這個(gè)特定類(lèi)或者是它的子類(lèi)的一個(gè)實(shí)例。

這樣的話也就是說(shuō) Language是Student的子類(lèi) 在用instanceof判斷的時(shí)候是返回true,而Language雖然是繼承Student 但是使用instanceof判斷的時(shí)候會(huì)發(fā)現(xiàn) Language和Student的類(lèi)型不同 然后Student也不是Language的子類(lèi)所以會(huì)返回false。


而解決的辦法就是

然后我們?cè)谶\(yùn)行一下剛剛的代碼

輸出結(jié)果:

父類(lèi)對(duì)比子類(lèi) 屬性相同---false 

子類(lèi)對(duì)比父類(lèi) 屬性相同---false

完美解決,滿足對(duì)稱(chēng)性

注意:使用getClass是要根據(jù)情況而定,使用getClass 不符合多態(tài)的定義

那什么時(shí)候使用instanceof,什么時(shí)候使用getClass呢?

如果子類(lèi)能夠擁有自己的相等概念,則對(duì)稱(chēng)性需求將強(qiáng)制采用 getClass 進(jìn)行檢測(cè)。

如果有超類(lèi)決定相等的概念,那么就可以使用 instanceof 進(jìn)行檢測(cè),這樣可以在不同的子類(lèi)的對(duì)象之間進(jìn)行相等的比較。

還有就是一定要注意無(wú)論何時(shí)重寫(xiě)此方法,通常都必須重寫(xiě)hashCode方法,以維護(hù)hashCode方法的一般約定,該方法聲明相等對(duì)象必須具有相同的哈希代碼。

4.getClass 方法

我們首先看一下getClass在Object中的實(shí)現(xiàn)。


我們看到getClass被native標(biāo)識(shí),這代表這是調(diào)用本地方法實(shí)現(xiàn)

關(guān)于native更多請(qǐng)百度。native是由操作系統(tǒng)幫我們實(shí)現(xiàn)

文檔說(shuō)明的是調(diào)用getClass返回一個(gè)運(yùn)行時(shí)的類(lèi)。什么意思呢 我們看下面的代碼實(shí)現(xiàn)。


打印結(jié)果:

可以看出getClass是返回一個(gè)運(yùn)行時(shí)的對(duì)象。class是返回編譯的類(lèi)對(duì)象

可以看到getClass方法被final修飾,說(shuō)明此方法不能被重寫(xiě)。

5.hashCode

先看一下hashCode在Object中的實(shí)現(xiàn):

hashCode也是一個(gè)被native修飾的本地方法

注釋說(shuō)明的是返回該對(duì)象的哈希值。那么它有什么作用呢?

主要是保證基于散列的集合,如HashSet、HashMap以及HashTable等,在插入元素時(shí)保證元素不可重復(fù),同時(shí)為了提高元素的插入刪除便利效率而設(shè)計(jì);主要是為了查找的便捷性而存在。

就比如使用Set進(jìn)行舉例子。

Set集合是不可重復(fù)的,如果每次添加數(shù)據(jù)都使用equals去做對(duì)比的話,插入十萬(wàn)條數(shù)據(jù)就要對(duì)比十萬(wàn)次效率是非常慢的。


所以在添加數(shù)據(jù)的時(shí)候使用了哈希表,哈希算法也稱(chēng)之為散列算法,當(dāng)添加一個(gè)值的時(shí)候先算出它的哈希值根據(jù)算出的哈希值將數(shù)據(jù)插入指定位置。這樣的話就避免了一直調(diào)用equals造成的效率隱患。同時(shí)有以下條件:

如果位置為空則直接添加

如果位置不為空,判斷兩個(gè)元素是否相同如果相同則不存儲(chǔ)。

還有一種情況是兩個(gè)元素不相同,但是hashCode相同,這就是哈希碰撞。

如果發(fā)生了hash key相同的情況就在相同的元素創(chuàng)建一個(gè)鏈表。把所有相同的元素存放在鏈表中。


可以看出T1的哈希和T2相同,但是元素不同,所以現(xiàn)在會(huì)形成一個(gè)鏈來(lái)存儲(chǔ)。

6.toString

先看toString的實(shí)現(xiàn)


可以看出toString是返回的類(lèi)名加16進(jìn)制無(wú)符號(hào)整數(shù)形式返回此哈希碼的字符串表示形式。

運(yùn)行輸出結(jié)果:


直接輸出對(duì)象和使用toString是一樣的


如果想要toString輸出屬性內(nèi)容則需要重寫(xiě)toString方法

7.finalize

源碼中實(shí)現(xiàn)方法:


finalize用戶垃圾回收是由JVM調(diào)用。

8.registerNatives

源碼實(shí)現(xiàn):


上面說(shuō)到native是調(diào)用本地實(shí)現(xiàn)方法,而registerNatives則是對(duì)本地方法注冊(cè),裝載本地庫(kù)。在Object初始化時(shí)執(zhí)行。

還有notify()/notifyAll()/wait()等寫(xiě)到多線程的時(shí)候在做分析

最后
小弟不才,如有錯(cuò)誤請(qǐng)指出。喜歡請(qǐng)關(guān)注,慢慢更新JDK源碼閱讀筆記

小弟公眾號(hào),亂敲代碼。歡迎點(diǎn)贊,關(guān)注

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/75382.html

相關(guān)文章

  • HashSet源碼分析:JDK源碼系列

    摘要:簡(jiǎn)介繼續(xù)分析源碼,上一篇文章把的分析完畢。本文開(kāi)始分析簡(jiǎn)單的介紹一下。存儲(chǔ)的元素是無(wú)序的并且允許使用空的元素。 1.簡(jiǎn)介 繼續(xù)分析源碼,上一篇文章把HashMap的分析完畢。本文開(kāi)始分析HashSet簡(jiǎn)單的介紹一下。 HashSet是一個(gè)無(wú)重復(fù)元素集合,內(nèi)部使用HashMap實(shí)現(xiàn),所以HashMap的特征耶繼承了下來(lái)。存儲(chǔ)的元素是無(wú)序的并且HashSet允許使用空的元素。 HashSe...

    用戶83 評(píng)論0 收藏0
  • 源碼|jdk源碼Object及裝箱類(lèi)型分析

    摘要:作為條件變量的的不僅可以認(rèn)為內(nèi)嵌了一把鎖,還內(nèi)嵌了一個(gè)條件變量。操作條件變量的函數(shù)將當(dāng)前線程在條件變量上阻塞,一般是為了等待其他線程的某件事情執(zhí)行完成。其它裝箱類(lèi)其它裝箱類(lèi)的代碼這里就不分析了。重點(diǎn)關(guān)注下各裝箱類(lèi)的緩存范圍。 jdk源碼讀到現(xiàn)在這里,重要的集合類(lèi)也讀了一部分了。集合類(lèi)再往下讀的話,就要涉及到兩個(gè)方向。第一,是比較典型的但是不常用的數(shù)據(jù)結(jié)構(gòu),這部分我準(zhǔn)備將數(shù)據(jù)結(jié)構(gòu)復(fù)習(xí)、回...

    VioletJack 評(píng)論0 收藏0
  • 源碼|jdk源碼-ArrayList與Vector源碼閱讀

    摘要:畢業(yè)兩個(gè)星期了,開(kāi)始成為一名正式的碼農(nóng)了。將指定位置的數(shù)據(jù)移除。但是問(wèn)題是,為時(shí),并不是直接一個(gè)大小為的數(shù)組,而是使用靜態(tài)變量來(lái)代替。此外,函數(shù)還做了越界檢查。返回迭代器,與之有一個(gè)搭配的輔助類(lèi)。 畢業(yè)兩個(gè)星期了,開(kāi)始成為一名正式的java碼農(nóng)了。一直對(duì)偏底層比較感興趣,想著深入自己的java技能,看書(shū)、讀源碼、總結(jié)、造輪子實(shí)踐都是付諸行動(dòng)的方法。說(shuō)到看源碼,就應(yīng)該由簡(jiǎn)入難,逐漸加深,...

    0x584a 評(píng)論0 收藏0
  • HashMap源碼分析():JDK源碼分析系列

    摘要:當(dāng)一個(gè)值中要存儲(chǔ)到的時(shí)候會(huì)根據(jù)的值來(lái)計(jì)算出他的,通過(guò)哈希來(lái)確認(rèn)到數(shù)組的位置,如果發(fā)生哈希碰撞就以鏈表的形式存儲(chǔ)在源碼分析中解釋過(guò),但是這樣如果鏈表過(guò)長(zhǎng)來(lái)的話,會(huì)把這個(gè)鏈表轉(zhuǎn)換成紅黑樹(shù)來(lái)存儲(chǔ)。 正文開(kāi)始 注:JDK版本為1.8 HashMap1.8和1.8之前的源碼差別很大 目錄 簡(jiǎn)介 數(shù)據(jù)結(jié)構(gòu) 類(lèi)結(jié)構(gòu) 屬性 構(gòu)造方法 增加 刪除 修改 總結(jié) 1.HashMap簡(jiǎn)介 H...

    wdzgege 評(píng)論0 收藏0
  • JDK1.8源碼分析01之學(xué)習(xí)建議(可以延伸其他源碼學(xué)習(xí))

    摘要:唐老師,回答道讀源碼是要建立在你的基礎(chǔ)經(jīng)驗(yàn)足夠的情況下。除了自己去閱讀源碼之外,比如學(xué)習(xí)某個(gè)類(lèi)的時(shí)候,可以專(zhuān)門(mén)結(jié)合一些優(yōu)質(zhì)的博客針對(duì)性的對(duì)比學(xué)習(xí),并查漏補(bǔ)缺。制定源碼學(xué)習(xí)計(jì)劃。多調(diào)試,跟蹤源碼。如若有好的學(xué)習(xí)方法,可以留言一起交流學(xué)習(xí)。 序言:目前看一看源碼,來(lái)提升自己的技術(shù)實(shí)力。同時(shí)現(xiàn)在好多面試官都喜歡問(wèn)源碼,問(wèn)你是否讀過(guò)JDK源碼等等? 針對(duì)如何閱讀源碼,也請(qǐng)教了我的老師。下面就先...

    ky0ncheng 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<