成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

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

VioletJack / 1049人閱讀

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

jdk源碼讀到現(xiàn)在這里,重要的集合類也讀了一部分了。
集合類再往下讀的話,就要涉及到兩個方向。
第一,是比較典型的但是不常用的數(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的對象系統(tǒng)設(shè)計是采用單根繼承,所有的對象往上追溯,Object都是它們共同的祖先。

有了這個假設(shè),我忽然想起java中一個有趣的事實(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中,會讓接口類型也擁有Object的所有方法。一個接口對象,也是一個Object對象。因?yàn)閱胃^承這一總體設(shè)計,所以這樣設(shè)計接口是合理的。
這里有關(guān)于該問題的有趣討論,所以這里就不詳細(xì)展開了。

作為鎖的Object

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

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

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

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

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

作為條件變量的Object

java的Object不僅可以認(rèn)為內(nèi)嵌了一把鎖,還內(nèi)嵌了一個條件變量。操作條件變量的函數(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來喚醒阻塞的線程。

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

wait還有兩個重載形式:

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);
}

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

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

笑哭了。。。。難道是我下載的jdk平臺不對?

hashCode、equals、toString

Object類提供了這三個函數(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種基本類型都是值類型,不是對象。因此無法直接放入泛型類對象中。

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

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

Integer

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

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;
}

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

工廠方法和緩存

我們知道,一般來說,在java中,使用工廠方法代替構(gòu)造函數(shù)是更好的設(shè)計。在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);
}

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

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

來看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手動修改該參數(shù)空間換時間。

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

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

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

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

其它裝箱類

其它裝箱類的代碼這里就不分析了。重點(diǎn)關(guān)注下各裝箱類的緩存范圍。
首先,Boolean,只有兩個值,當(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一樣。最重要的是,這個范圍無法修改。

    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)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/77093.html

相關(guān)文章

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

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

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

    摘要:棧隊(duì)列雙端隊(duì)列都是非常經(jīng)典的數(shù)據(jù)結(jié)構(gòu)。結(jié)合了棧和隊(duì)列的特點(diǎn)。因此,在中,有棧的使用需求時,使用代替。迭代器之前源碼源碼之與字段中分析過,容器的實(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_ 評論0 收藏0
  • Java學(xué)習(xí)路線總結(jié),搬磚工逆襲Java架構(gòu)師(全網(wǎng)最強(qiáng))

    摘要:哪吒社區(qū)技能樹打卡打卡貼函數(shù)式接口簡介領(lǐng)域優(yōu)質(zhì)創(chuàng)作者哪吒公眾號作者架構(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 評論0 收藏0
  • Java快速掃盲指南

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

    Tony_Zby 評論0 收藏0
  • java.lang.Integer 源碼深入解讀

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

    mingzhong 評論0 收藏0

發(fā)表評論

0條評論

VioletJack

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<