国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

源碼|jdk源碼之Object及裝箱類型分析

VioletJack / 1004人閱讀

摘要:作為條件變量的的不僅可以認(rèn)為內(nèi)嵌了一把鎖,還內(nèi)嵌了一個(gè)條件變量。操作條件變量的函數(shù)將當(dāng)前線程在條件變量上阻塞,一般是為了等待其他線程的某件事情執(zhí)行完成。其它裝箱類其它裝箱類的代碼這里就不分析了。重點(diǎn)關(guān)注下各裝箱類的緩存范圍。

jdk源碼讀到現(xiàn)在這里,重要的集合類也讀了一部分了。
集合類再往下讀的話,就要涉及到兩個(gè)方向。
第一,是比較典型的但是不常用的數(shù)據(jù)結(jié)構(gòu),這部分我準(zhǔn)備將數(shù)據(jù)結(jié)構(gòu)復(fù)習(xí)、回顧后再繼續(xù)閱讀。
第二,是并發(fā)相關(guān)的集合,這部分我準(zhǔn)備留到和并發(fā)相關(guān)的類一起閱讀。

所以,今天就讀些輕松的。

Object 作為單根繼承的Object

java的對(duì)象系統(tǒng)設(shè)計(jì)是采用單根繼承,所有的對(duì)象往上追溯,Object都是它們共同的祖先。

有了這個(gè)假設(shè),我忽然想起java中一個(gè)有趣的事實(shí):

List list = new ArrayList();
list.toString();

這段代碼能正常編譯、運(yùn)行嗎?經(jīng)驗(yàn)告訴我,當(dāng)然可以。
可是從類型系統(tǒng)的角度仔細(xì)思考,list引用的類型為List,其為List接口。
然而,List接口中并沒有toString方法,為什么能調(diào)用?

這是由于,在java中,會(huì)讓接口類型也擁有Object的所有方法。一個(gè)接口對(duì)象,也是一個(gè)Object對(duì)象。因?yàn)閱胃^承這一總體設(shè)計(jì),所以這樣設(shè)計(jì)接口是合理的。
這里有關(guān)于該問題的有趣討論,所以這里就不詳細(xì)展開了。

作為鎖的Object

在java中,除了最基本的單根繼承的祖先類之外,Object還內(nèi)置了很多機(jī)制。如:

Object o = new Object();
synchronized(o) {
    /* ... */
}

在其它語言中,鎖這一機(jī)制都是標(biāo)準(zhǔn)庫中提供的函數(shù),成對(duì)使用。一個(gè)lock函數(shù)用于獲取鎖,一個(gè)release函數(shù)函數(shù)用于釋放鎖。

然而,java直接將鎖機(jī)制作為語法的一部分,還給它一個(gè)專屬關(guān)鍵字synchronized。每個(gè)Object對(duì)象,都內(nèi)嵌了一個(gè)鎖。java稱之監(jiān)視器鎖。

這樣設(shè)計(jì)有什么好處呢?一種觀點(diǎn)是,將鎖機(jī)制內(nèi)置為語法的一部分,有利于jvm對(duì)其進(jìn)行深度優(yōu)化提升性能,如java的鎖升級(jí)機(jī)制。

作為條件變量的Object

java的Object不僅可以認(rèn)為內(nèi)嵌了一把鎖,還內(nèi)嵌了一個(gè)條件變量。操作條件變量的函數(shù):

public final native void notify();
public final native void notifyAll();
public final native void wait(long timeout) throws InterruptedException;

wait將當(dāng)前線程在條件變量上阻塞,一般是為了等待其他線程的某件事情執(zhí)行完成。當(dāng)其他線程的事情執(zhí)行完成后,在條件變量上調(diào)用notifynotifyAll來喚醒阻塞的線程。

可以看到,這三個(gè)方法都是native,jvm原生實(shí)現(xiàn)。

wait還有兩個(gè)重載形式:

public final void wait() throws InterruptedException {
    wait(0);
}

public final void wait(long timeout, int nanos) throws InterruptedException {
    if (timeout < 0) {
        throw new IllegalArgumentException("timeout value is negative");
    }

    if (nanos < 0 || nanos > 999999) {
        throw new IllegalArgumentException(
                            "nanosecond timeout value out of range");
    }

    if (nanos > 0) {
        timeout++;
    }

    wait(timeout);
}

比較有意思的是第二個(gè)。
原生實(shí)現(xiàn)的wait(long timeout),只能設(shè)置毫秒級(jí)別的超時(shí)時(shí)間。但是這個(gè)wait(long timeout, int nanos)卻能設(shè)置納秒級(jí)別的超時(shí)時(shí)間。怎么實(shí)現(xiàn)的?

if (nanos > 0) {
    timeout++;
}

笑哭了。。。。難道是我下載的jdk平臺(tái)不對(duì)?

hashCode、equals、toString

Object類提供了這三個(gè)函數(shù)的默認(rèn)實(shí)現(xiàn)。來看一下:

public native int hashCode();

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

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

可以看到,hashCode的默認(rèn)方法是原生實(shí)現(xiàn),到底是不是指針不清楚。

equals方法的默認(rèn)實(shí)現(xiàn)僅僅簡單比較了是否為同一引用。

toString()方法打印出的是類名及十六進(jìn)制的hash值。

裝箱拆箱

裝箱拆箱機(jī)制的存在的原因是:

java中的泛型是類型擦除,類似集合等泛型類中實(shí)際存放的必須是Object的子類,也即引用類型。

java的8種基本類型都是值類型,不是對(duì)象。因此無法直接放入泛型類對(duì)象中。

為了解決這個(gè)沖突,只好設(shè)計(jì)一組對(duì)象,中間包裹基本類型,并且語法層次內(nèi)建裝箱類與基本類型的自動(dòng)轉(zhuǎn)換機(jī)制,也即自動(dòng)裝箱拆箱。

下面以Integer為例分析裝箱拆箱類的源碼。

Integer

大致看一下Integer中的組成。可以發(fā)現(xiàn)有三個(gè)不同的部分:

Integer類本身作為裝箱容器。

Integer類的static屬性定義了大量和int有關(guān)的常量。

Integer類的static方法定義了和int有關(guān)的工具函數(shù)。

屬性和構(gòu)造函數(shù)

先來看屬性。

private final int value;

public Integer(int value) {
    this.value = value;
}

對(duì)的,Integer對(duì)象中,只有包含這么一個(gè)數(shù)據(jù),被裝箱的原始值。
簡單到不能再簡單。

工廠方法和緩存

我們知道,一般來說,在java中,使用工廠方法代替構(gòu)造函數(shù)是更好的設(shè)計(jì)。在Integer里,就體現(xiàn)了它的好處之一。

Integer提供了一組靜態(tài)工廠方法:

public static Integer valueOf(String s) throws NumberFormatException {
    return Integer.valueOf(parseInt(s, 10));
}

public static Integer valueOf(String s, int radix) throws NumberFormatException {
    return Integer.valueOf(parseInt(s,radix));
}

public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}

前兩個(gè)工廠方法都利用最后一個(gè)工廠方法實(shí)現(xiàn)。最重要的是最后一個(gè)。

非常明顯,當(dāng)被裝箱的原始類型iIntegerCache.lowIntegerCache.high之間時(shí),則返回緩存的Integer對(duì)象。

來看IntegerCache:

    private static class IntegerCache {
        static final int low = -128;
        static final int high;
        static final Integer cache[];

        static {
            // high value may be configured by property
            int h = 127;
            String integerCacheHighPropValue =
                sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
            if (integerCacheHighPropValue != null) {
                try {
                    int i = parseInt(integerCacheHighPropValue);
                    i = Math.max(i, 127);
                    // Maximum array size is Integer.MAX_VALUE
                    h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
                } catch( NumberFormatException nfe) {
                    // If the property cannot be parsed into an int, ignore it.
                }
            }
            high = h;

            cache = new Integer[(high - low) + 1];
            int j = low;
            for(int k = 0; k < cache.length; k++)
                cache[k] = new Integer(j++);

            // range [-128, 127] must be interned (JLS7 5.1.7)
            assert IntegerCache.high >= 127;
        }

        private IntegerCache() {}
    }

可發(fā)現(xiàn):

默認(rèn)緩存的值是-128127

緩存的范圍可以通過java.lang.Integer.IntegerCache.high來設(shè)置。這樣,如果在某些場景下Integer影響性能,可以通過jvm手動(dòng)修改該參數(shù)空間換時(shí)間。

總結(jié)一下,由于Integer是對(duì)象,而對(duì)整數(shù)的操作是代碼里非常頻繁的地方。裝箱機(jī)制會(huì)導(dǎo)致程序產(chǎn)生大量的Integer對(duì)象,這導(dǎo)致:

對(duì)象會(huì)占據(jù)額外空間(如對(duì)象頭),造成內(nèi)存浪費(fèi)。

頻繁創(chuàng)建銷毀對(duì)象,給gc造成壓力。

因此,采用緩存機(jī)制,盡量降低裝箱對(duì)性能的影響。

其它裝箱類

其它裝箱類的代碼這里就不分析了。重點(diǎn)關(guān)注下各裝箱類的緩存范圍。
首先,Boolean,只有兩個(gè)值,當(dāng)然可以都緩存。

浮點(diǎn)類型,Double和Float,沒有緩存:

public static Float valueOf(float f) {
    return new Float(f);
}

public static Double valueOf(double d) {
    return new Double(d);
}

Short,緩存范圍為-128到127,和默認(rèn)的Integer一樣。最重要的是,這個(gè)范圍無法修改。

    public static Short valueOf(short s) {
        final int offset = 128;
        int sAsInt = s;
        if (sAsInt >= -128 && sAsInt <= 127) { // must cache
            return ShortCache.cache[sAsInt + offset];
        }
        return new Short(s);
    }

    private static class ShortCache {
        private ShortCache(){}

        static final Short cache[] = new Short[-(-128) + 127 + 1];

        static {
            for(int i = 0; i < cache.length; i++)
                cache[i] = new Short((short)(i - 128));
        }
    }

同樣:

Byte緩存范圍也是-128到127,全部緩存。

而Character緩存范圍為0到127.

Long的緩存范圍為-128到127。

可以發(fā)現(xiàn),只有Integer的緩存范圍能夠修改,其它的裝箱類型都不行。

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/77093.html

相關(guān)文章

  • 深入淺出了解“裝箱與拆箱”

    摘要:本章部分內(nèi)容從源碼中解讀一些自動(dòng)裝箱與拆箱的原理,以及會(huì)出現(xiàn)的一些陷阱已經(jīng)性能等。例題分析我們通過幾個(gè)經(jīng)典的問題,來看看大家到底理解了裝箱與拆箱的知識(shí)點(diǎn)沒。 showImg(https://img-blog.csdnimg.cn/20190426221838971.gif);showImg(https://img-blog.csdnimg.cn/20190426221918208.pn...

    FullStackDeveloper 評(píng)論0 收藏0
  • 源碼|jdk源碼棧、隊(duì)列ArrayDeque分析

    摘要:棧隊(duì)列雙端隊(duì)列都是非常經(jīng)典的數(shù)據(jù)結(jié)構(gòu)。結(jié)合了棧和隊(duì)列的特點(diǎn)。因此,在中,有棧的使用需求時(shí),使用代替。迭代器之前源碼源碼之與字段中分析過,容器的實(shí)現(xiàn)中,所有修改過容器結(jié)構(gòu)的操作都需要修改字段。 棧、隊(duì)列、雙端隊(duì)列都是非常經(jīng)典的數(shù)據(jù)結(jié)構(gòu)。和鏈表、數(shù)組不同,這三種數(shù)據(jù)結(jié)構(gòu)的抽象層次更高。它只描述了數(shù)據(jù)結(jié)構(gòu)有哪些行為,而并不關(guān)心數(shù)據(jù)結(jié)構(gòu)內(nèi)部用何種思路、方式去組織。本篇博文重點(diǎn)關(guān)注這三種數(shù)據(jù)結(jié)構(gòu)...

    ZHAO_ 評(píng)論0 收藏0
  • Java學(xué)習(xí)路線總結(jié),搬磚工逆襲Java架構(gòu)師(全網(wǎng)最強(qiáng))

    摘要:哪吒社區(qū)技能樹打卡打卡貼函數(shù)式接口簡介領(lǐng)域優(yōu)質(zhì)創(chuàng)作者哪吒公眾號(hào)作者架構(gòu)師奮斗者掃描主頁左側(cè)二維碼,加入群聊,一起學(xué)習(xí)一起進(jìn)步歡迎點(diǎn)贊收藏留言前情提要無意間聽到領(lǐng)導(dǎo)們的談話,現(xiàn)在公司的現(xiàn)狀是碼農(nóng)太多,但能獨(dú)立帶隊(duì)的人太少,簡而言之,不缺干 ? 哪吒社區(qū)Java技能樹打卡?【打卡貼 day2...

    Scorpion 評(píng)論0 收藏0
  • Java快速掃盲指南

    摘要:不相等的對(duì)象要具有不相等的哈希碼為了哈希表的操作效率,這一點(diǎn)很重要,但不是強(qiáng)制要求,最低要求是不相等的對(duì)象不能共用一個(gè)哈希碼。方法和方法協(xié)同工作,返回對(duì)象的哈希碼。這個(gè)哈希碼基于對(duì)象的身份生成,而不是對(duì)象的相等性。 本文面向 剛學(xué)完Java的新手們。這篇文章不講語法,而是一些除了語法必須了解的概念。 將要去面試的初級(jí)工程師們。查漏補(bǔ)缺,以免遭遇不測。 目前由于篇幅而被挪出本文的知識(shí)...

    Tony_Zby 評(píng)論0 收藏0
  • java.lang.Integer 源碼深入解讀

    摘要:最近算是比較深入的了解了一下的源碼,就想著寫點(diǎn)東西記錄一下,一來可以加深理解,再來也算是為我刷了那么久平臺(tái)貢獻(xiàn)一點(diǎn)自己的綿薄之力。這兩個(gè)方法都是給當(dāng)前的實(shí)例的屬性賦值,參數(shù)為類型的構(gòu)造器直接將參數(shù)賦值給屬性,參數(shù)為是將方法的返回值賦值。 最近算是比較深入的了解了一下Integer的源碼,就想著寫點(diǎn)東西記錄一下,一來可以加深理解,再來也算是為我刷了那么久segmentfault平臺(tái)貢獻(xiàn)一...

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

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

0條評(píng)論

VioletJack

|高級(jí)講師

TA的文章

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