成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

int和Integer深入分析

Half / 3158人閱讀

摘要:對(duì)象頭的另外一部分是類型指針,即對(duì)象指向它的類元數(shù)據(jù)的指針,虛擬機(jī)通過(guò)這個(gè)指針來(lái)確定這個(gè)對(duì)象是哪個(gè)類的實(shí)例。并不是所有的虛擬機(jī)實(shí)現(xiàn)都必須在對(duì)象數(shù)據(jù)上保留類型指針,換句話說(shuō),查找對(duì)象的元數(shù)據(jù)信息并不一定要經(jīng)過(guò)對(duì)象本身,這點(diǎn)將在節(jié)討論。

目錄介紹

1.關(guān)于int和Integer的問(wèn)題區(qū)別分析

2.Integer的值緩存的原理

2.1 Java 5 中引入緩存特性

2.2 Integer類中的IntegerCache類

2.3 其他整型類型的緩存機(jī)制

3.理解自動(dòng)裝箱和拆箱

3.1 什么是裝箱?什么是拆箱?

3.2 裝箱和拆箱是如何實(shí)現(xiàn)的

3.3 裝箱和拆箱在編程實(shí)際中注意點(diǎn)

4.原始類型線程安全問(wèn)題

4.1 那些類型是線程安全的

4.2 如何驗(yàn)證int類型是否線程安全

4.3 AtomicInteger線程安全版

5.Java 原始數(shù)據(jù)類型和引用類型局限性

5.1 原始數(shù)據(jù)類型和 Java 泛型并不能配合使用

5.2 無(wú)法高效地表達(dá)數(shù)據(jù),也不便于表達(dá)復(fù)雜的數(shù)據(jù)結(jié)構(gòu)

6.關(guān)于其他知識(shí)延伸

6.1 對(duì)象的內(nèi)存結(jié)構(gòu)

6.2 對(duì)象頭的結(jié)構(gòu)

6.3 如何計(jì)算或者獲取某個(gè)Java對(duì)象的大小

7.關(guān)于其他內(nèi)容介紹

7.1 關(guān)于博客匯總鏈接

7.2 關(guān)于我的博客

1.關(guān)于int和Integer的問(wèn)題區(qū)別分析

1.1 編譯階段、運(yùn)行時(shí),自動(dòng)裝箱 / 自動(dòng)拆箱是發(fā)生在什么階段?

1.2使用靜態(tài)工廠方法 valueOf 會(huì)使用到緩存機(jī)制,那么自動(dòng)裝箱的時(shí)候,緩存機(jī)制起作用嗎?

1.3為什么我們需要原始數(shù)據(jù)類型,Java 的對(duì)象似乎也很高效,應(yīng)用中具體會(huì)產(chǎn)生哪些差異?

1.4 閱讀過(guò) Integer 源碼嗎?分析下類或某些方法的設(shè)計(jì)要點(diǎn)?

1.5 int和Integer的區(qū)別

1、Integer是int的包裝類,int則是java的一種基本數(shù)據(jù)類型 
2、Integer變量必須實(shí)例化后才能使用,而int變量不需要 
3、Integer實(shí)際是對(duì)象的引用,當(dāng)new一個(gè)Integer時(shí),實(shí)際上是生成一個(gè)指針指向此對(duì)象;而int則是直接存儲(chǔ)數(shù)據(jù)值 
4、Integer的默認(rèn)值是null,int的默認(rèn)值是0

延伸: 
關(guān)于Integer和int的比較 
1、由于Integer變量實(shí)際上是對(duì)一個(gè)Integer對(duì)象的引用,所以兩個(gè)通過(guò)new生成的Integer變量永遠(yuǎn)是不相等的(因?yàn)閚ew生成的是兩個(gè)對(duì)象,其內(nèi)存地址不同)。

Integer i = new Integer(100);
Integer j = new Integer(100);
System.out.print(i == j); //false

2、Integer變量和int變量比較時(shí),只要兩個(gè)變量的值是向等的,則結(jié)果為true(因?yàn)榘b類Integer和基本數(shù)據(jù)類型int比較時(shí),java會(huì)自動(dòng)拆包裝為int,然后進(jìn)行比較,實(shí)際上就變?yōu)閮蓚€(gè)int變量的比較)

Integer i = new Integer(100);
int j = 100;
System.out.print(i == j); //true

3、非new生成的Integer變量和new Integer()生成的變量比較時(shí),結(jié)果為false。(因?yàn)榉莕ew生成的Integer變量指向的是java常量池中的對(duì)象,而new Integer()生成的變量指向堆中新建的對(duì)象,兩者在內(nèi)存中的地址不同)

Integer i = new Integer(100);
Integer j = 100;
System.out.print(i == j); //false

4、對(duì)于兩個(gè)非new生成的Integer對(duì)象,進(jìn)行比較時(shí),如果兩個(gè)變量的值在區(qū)間-128到127之間,則比較結(jié)果為true,如果兩個(gè)變量的值不在此區(qū)間,則比較結(jié)果為false

Integer i = 100;
Integer j = 100;
System.out.print(i == j); //true

Integer i = 128;
Integer j = 128;
System.out.print(i == j); //false

對(duì)于第4條的原因: 
java在編譯Integer i = 100 ;時(shí),會(huì)翻譯成為Integer i = Integer.valueOf(100);,而java API中對(duì)Integer類型的valueOf的定義如下:

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

java對(duì)于-128到127之間的數(shù),會(huì)進(jìn)行緩存,Integer i = 127時(shí),會(huì)將127進(jìn)行緩存,下次再寫Integer j = 127時(shí),就會(huì)直接從緩存中取,就不會(huì)new了
2.Integer的值緩存的原理 2.1 Java 5 中引入緩存特性

在 Java 5 中,為 Integer 的操作引入了一個(gè)新的特性,用來(lái)節(jié)省內(nèi)存和提高性能。整型對(duì)象在內(nèi)部實(shí)現(xiàn)中通過(guò)使用相同的對(duì)象引用實(shí)現(xiàn)了緩存和重用。

這種 Integer 緩存策略僅在自動(dòng)裝箱(autoboxing)的時(shí)候有用,使用構(gòu)造器創(chuàng)建的 Integer 對(duì)象不能被緩存。

2.2 Integer類中的IntegerCache類

在創(chuàng)建新的 Integer 對(duì)象之前會(huì)先在 IntegerCache.cache (是個(gè)Integer類型的數(shù)組)中查找。有一個(gè)專門的 Java 類來(lái)負(fù)責(zé) Integer 的緩存。

這個(gè)類是用來(lái)實(shí)現(xiàn)緩存支持,并支持 -128 到 127 之間的自動(dòng)裝箱過(guò)程。最大值 127 可以通過(guò) JVM 的啟動(dòng)參數(shù) -XX:AutoBoxCacheMax=size 修改。 緩存通過(guò)一個(gè) for 循環(huán)實(shí)現(xiàn)。從小到大的創(chuàng)建盡可能多的整數(shù)并存儲(chǔ)在一個(gè)名為 cache 的整數(shù)數(shù)組中。這個(gè)緩存會(huì)在 Integer 類第一次被使用的時(shí)候被初始化出來(lái)。以后,就可以使用緩存中包含的實(shí)例對(duì)象,而不是創(chuàng)建一個(gè)新的實(shí)例(在自動(dòng)裝箱的情況下)。

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


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() {}
}
2.3 其他整型類型的緩存機(jī)制

這種緩存行為不僅適用于Integer對(duì)象。我們針對(duì)所有整數(shù)類型的類都有類似的緩存機(jī)制。

有 ByteCache 用于緩存 Byte 對(duì)象

有 ShortCache 用于緩存 Short 對(duì)象

有 LongCache 用于緩存 Long 對(duì)象

有 CharacterCache 用于緩存 Character 對(duì)象

Byte,Short,Long 有固定范圍: -128 到 127。對(duì)于 Character, 范圍是 0 到 127。除了 Integer 可以通過(guò)參數(shù)改變范圍外,其它的都不行。

3.理解自動(dòng)裝箱和拆箱 3.1 什么是裝箱?什么是拆箱?

裝箱就是 自動(dòng)將基本數(shù)據(jù)類型轉(zhuǎn)換為包裝器類型;拆箱就是 自動(dòng)將包裝器類型轉(zhuǎn)換為基本數(shù)據(jù)類型。

//拆箱
int yc = 5;
//裝箱
Integer yc = 5;
3.2 裝箱和拆箱是如何實(shí)現(xiàn)的

以Interger類為例,下面看一段代碼來(lái)了解裝箱和拆箱的實(shí)現(xiàn)

public class Main {
    public static void main(String[] args) {
        Integer y = 10;
        int c = i;
    }
}

然后來(lái)編譯一下,看下圖所示:

從反編譯得到的字節(jié)碼內(nèi)容可以看出,在裝箱的時(shí)候自動(dòng)調(diào)用的是Integer的valueOf(int)方法。而在拆箱的時(shí)候自動(dòng)調(diào)用的是Integer的intValue方法。

因此可以用一句話總結(jié)裝箱和拆箱的實(shí)現(xiàn)過(guò)程:裝箱過(guò)程是通過(guò)調(diào)用包裝器的valueOf方法實(shí)現(xiàn)的,而拆箱過(guò)程是通過(guò)調(diào)用包裝器的 xxxValue方法實(shí)現(xiàn)的。(xxx代表對(duì)應(yīng)的基本數(shù)據(jù)類型)。

3.3 裝箱和拆箱在編程實(shí)際中注意點(diǎn)

建議避免無(wú)意中的裝箱、拆箱行為,尤其是在性能敏感的場(chǎng)合,創(chuàng)建 10 萬(wàn)個(gè) Java 對(duì)象和 10 萬(wàn)個(gè)整數(shù)的開(kāi)銷可不是一個(gè)數(shù)量級(jí)的,不管是內(nèi)存使用還是處理速度,光是對(duì)象頭的空間占用就已經(jīng)是數(shù)量級(jí)的差距了。

4.原始類型線程安全問(wèn)題 4.1 那些類型是線程安全的

Java自帶的線程安全的基本類型包括: AtomicInteger, AtomicLong, AtomicBoolean, AtomicIntegerArray,AtomicLongArray等

4.2 如何驗(yàn)證int類型是否線程安全

200個(gè)線程,每個(gè)線程對(duì)共享變量 count 進(jìn)行 50 次 ++ 操作

int 作為基本類型,直接存儲(chǔ)在內(nèi)存棧,且對(duì)其進(jìn)行+,-操作以及++,–操作都不是原子操作,都有可能被其他線程搶斷,所以不是線程安全。int 用于單線程變量存取,開(kāi)銷小,速度快

int count = 0;
private void startThread() {
    for (int i = 0;i < 200; i++){
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int k = 0; k < 50; k++){
                    count++;
                }
            }
        }).start();
    }
    // 休眠10秒,以確保線程都已啟動(dòng)
    try {
        Thread.sleep(1000*10);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }finally {
        Log.e("打印日志----",count+"");
    }
}

//期望輸出10000,最后輸出的是9818
//注意:打印日志----: 9818
4.3 AtomicInteger線程安全版

AtomicInteger類中有有一個(gè)變量valueOffset,用來(lái)描述AtomicInteger類中value的內(nèi)存位置 。

當(dāng)需要變量的值改變的時(shí)候,先通過(guò)get()得到valueOffset位置的值,也即當(dāng)前value的值.給該值進(jìn)行增加,并賦給next

compareAndSet()比較之前取到的value的值當(dāng)前有沒(méi)有改變,若沒(méi)有改變的話,就將next的值賦給value,倘若和之前的值相比的話發(fā)生變化的話,則重新一次循環(huán),直到存取成功,通過(guò)這樣的方式能夠保證該變量是線程安全的

value使用了volatile關(guān)鍵字,使得多個(gè)線程可以共享變量,使用volatile將使得VM優(yōu)化失去作用,在線程數(shù)特別大時(shí),效率會(huì)較低。

private static AtomicInteger atomicInteger = new AtomicInteger(1);
static Integer count1 = Integer.valueOf(0);
private void startThread1() {
    for (int i = 0;i < 200; i++){
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int k = 0; k < 50; k++){
                    // getAndIncrement: 先獲得值,再自增1,返回值為自增前的值
                    count1 = atomicInteger.getAndIncrement();
                }
            }
        }).start();
    }
    // 休眠10秒,以確保線程都已啟動(dòng)
    try {
        Thread.sleep(1000*10);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }finally {
        Log.e("打印日志----",count1+"");
    }
}

//期望輸出10000,最后輸出的是10000
//注意:打印日志----: 10000



//AtomicInteger使用了volatile關(guān)鍵字進(jìn)行修飾,使得該類可以滿足線程安全。
private volatile int value;
/**
 * Creates a new AtomicInteger with the given initial value.
 *
 * @param initialValue the initial value
 */
public AtomicInteger(int initialValue) {
    value = initialValue;
}
5.Java 原始數(shù)據(jù)類型和引用類型局限性 5.1 原始數(shù)據(jù)類型和 Java 泛型并不能配合使用

Java 的泛型某種程度上可以算作偽泛型,它完全是一種編譯期的技巧,Java 編譯期會(huì)自動(dòng)將類型轉(zhuǎn)換為對(duì)應(yīng)的特定類型,這就決定了使用泛型,必須保證相應(yīng)類型可以轉(zhuǎn)換為Object。

5.2 無(wú)法高效地表達(dá)數(shù)據(jù),也不便于表達(dá)復(fù)雜的數(shù)據(jù)結(jié)構(gòu)

Java 的對(duì)象都是引用類型,如果是一個(gè)原始數(shù)據(jù)類型數(shù)組,它在內(nèi)存里是一段連續(xù)的內(nèi)存,而對(duì)象數(shù)組則不然,數(shù)據(jù)存儲(chǔ)的是引用,對(duì)象往往是分散地存儲(chǔ)在堆的不同位置。這種設(shè)計(jì)雖然帶來(lái)了極大靈活性,但是也導(dǎo)致了數(shù)據(jù)操作的低效,尤其是無(wú)法充分利用現(xiàn)代 CPU 緩存機(jī)制。

Java 為對(duì)象內(nèi)建了各種多態(tài)、線程安全等方面的支持,但這不是所有場(chǎng)合的需求,尤其是數(shù)據(jù)處理重要性日益提高,更加高密度的值類型是非?,F(xiàn)實(shí)的需求。

6.關(guān)于其他知識(shí)延伸 6.1 對(duì)象的內(nèi)存結(jié)構(gòu)

對(duì)象在內(nèi)存中存儲(chǔ)的布局可以分為3塊區(qū)域:對(duì)象頭(Header)、實(shí)例數(shù)據(jù)(Instance Data)和對(duì)齊填充(Padding)。

6.2 對(duì)象頭的結(jié)構(gòu)

HotSpot虛擬機(jī)的對(duì)象頭包括兩部分信息,第一部分用于存儲(chǔ)對(duì)象自身的運(yùn)行時(shí)數(shù)據(jù),如哈希碼(HashCode)、GC分代年齡、鎖狀態(tài)標(biāo)志、線程持有的鎖、偏向線程ID、偏向時(shí)間戳等,這部分?jǐn)?shù)據(jù)的長(zhǎng)度在32位和64位的虛擬機(jī)(未開(kāi)啟壓縮指針)中分別為32bit和64bit,官方稱它為"Mark Word"。

對(duì)象頭的另外一部分是類型指針,即對(duì)象指向它的類元數(shù)據(jù)的指針,虛擬機(jī)通過(guò)這個(gè)指針來(lái)確定這個(gè)對(duì)象是哪個(gè)類的實(shí)例。并不是所有的虛擬機(jī)實(shí)現(xiàn)都必須在對(duì)象數(shù)據(jù)上保留類型指針,換句話說(shuō),查找對(duì)象的元數(shù)據(jù)信息并不一定要經(jīng)過(guò)對(duì)象本身,這點(diǎn)將在2.3.3節(jié)討論。另外,如果對(duì)象是一個(gè)Java數(shù)組,那在對(duì)象頭中還必須有一塊用于記錄數(shù)組長(zhǎng)度的數(shù)據(jù),因?yàn)樘摂M機(jī)可以通過(guò)普通Java對(duì)象的元數(shù)據(jù)信息確定Java對(duì)象的大小,但是從數(shù)組的元數(shù)據(jù)中卻無(wú)法確定數(shù)組的大小。

6.3 如何計(jì)算或者獲取某個(gè)Java對(duì)象的大小

獲取一個(gè)JAVA對(duì)象的大小,可以將一個(gè)對(duì)象進(jìn)行序列化為二進(jìn)制的Byte,便可以查看大小

//獲取一個(gè)JAVA對(duì)象的大小,可以將一個(gè)對(duì)象進(jìn)行序列化為二進(jìn)制的Byte,便可以查看大小
Integer value = 10;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos ;
try {
    oos = new ObjectOutputStream(bos);
    oos.writeObject(value);
    oos.close();
} catch (IOException e) {
    e.printStackTrace();
}
// 讀出當(dāng)前對(duì)象的二進(jìn)制流信息
Log.e("打印日志----",bos.size()+"");
//打印日志----: 81
7.關(guān)于其他內(nèi)容介紹 7.1 關(guān)于博客匯總鏈接

1.技術(shù)博客匯總

2.開(kāi)源項(xiàng)目匯總

3.生活博客匯總

4.喜馬拉雅音頻匯總

5.其他匯總

7.2 關(guān)于我的博客

我的個(gè)人站點(diǎn):www.yczbj.org,www.ycbjie.cn

github:https://github.com/yangchong211

知乎:https://www.zhihu.com/people/...

簡(jiǎn)書(shū):http://www.jianshu.com/u/b7b2...

csdn:http://my.csdn.net/m0_37700275

喜馬拉雅聽(tīng)書(shū):http://www.ximalaya.com/zhubo...

開(kāi)源中國(guó):https://my.oschina.net/zbj161...

泡在網(wǎng)上的日子:http://www.jcodecraeer.com/me...

郵箱:[email protected]

阿里云博客:https://yq.aliyun.com/users/a... 239.headeruserinfo.3.dT4bcV

segmentfault頭條:https://segmentfault.com/u/xi...

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

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

相關(guān)文章

  • 深入分析——HashSet是否真的無(wú)序?(JDK8)

    摘要:但是,如果像上例中只取最后幾位的時(shí)候,這可不是什么好事,即使我的數(shù)據(jù)分布很散亂,但是哈希沖突仍然會(huì)很嚴(yán)重。由于我們所創(chuàng)建的是類型的,這也是最巧的一點(diǎn),類型的返回值就是其值本身,而存儲(chǔ)的時(shí)候元素通過(guò)一些運(yùn)算后會(huì)得出自己在數(shù)組中所處的位置。 HashSet 是否無(wú)序 (一) 問(wèn)題起因: 《Core Java Volume I—Fundamentals》中對(duì)HashSet的描述是這樣的: H...

    everfight 評(píng)論0 收藏0
  • 深入淺出了解“裝箱與拆箱”

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

    FullStackDeveloper 評(píng)論0 收藏0
  • Java8-3-深入理解函數(shù)式編程模型

    摘要:接下來(lái)看下如果使用提供的接口會(huì)有哪些改進(jìn)首先看下接口定義省略該函數(shù)式接口唯一的抽象方法接收一個(gè)參數(shù),有返回值。是不是有點(diǎn)體驗(yàn)到函數(shù)式編程的靈活之處。 上一篇文章中,我們總體介紹了創(chuàng)建函數(shù)式接口實(shí)例的幾種方式以及Java8中接口新增的默認(rèn)方法特性,接下來(lái)我們來(lái)看下Java8中已經(jīng)為我們提供的幾種典型的函數(shù)式接口先看一個(gè)示例 public class FunctionTest { ...

    longshengwang 評(píng)論0 收藏0
  • 深入探究Java中equals()==的區(qū)別是什么

    摘要:相等判斷符介紹相等判斷符用于比較基本數(shù)據(jù)類型和引用類型數(shù)據(jù)當(dāng)比較基本數(shù)據(jù)類型的時(shí)候比較的是數(shù)值當(dāng)比較引用類型數(shù)據(jù)時(shí)比較的是引用指針判斷基本類型是否相等首先基本數(shù)據(jù)類型指的是中的八大數(shù)據(jù)類型這八大基本數(shù)據(jù)類型有個(gè)共同的特點(diǎn)是它們?cè)趦?nèi)存中是有具相等判斷符==介紹 ? ==相等判斷符用于比較基本數(shù)據(jù)類型和引用類型數(shù)據(jù). 當(dāng)比較基本數(shù)據(jù)類型的時(shí)候比較的是數(shù)值, 當(dāng)比較引用類型數(shù)據(jù)時(shí)比較的是引用(指...

    liaorio 評(píng)論0 收藏0
  • 深入探究Java中equals()==的區(qū)別是什么

    摘要:相等判斷符介紹相等判斷符用于比較基本數(shù)據(jù)類型和引用類型數(shù)據(jù)當(dāng)比較基本數(shù)據(jù)類型的時(shí)候比較的是數(shù)值當(dāng)比較引用類型數(shù)據(jù)時(shí)比較的是引用指針判斷基本類型是否相等首先基本數(shù)據(jù)類型指的是中的八大數(shù)據(jù)類型這八大基本數(shù)據(jù)類型有個(gè)共同的特點(diǎn)是它們?cè)趦?nèi)存中是有具相等判斷符==介紹 ==相等判斷符用于比較基本數(shù)據(jù)類型和引用類型數(shù)據(jù). 當(dāng)比較基本數(shù)據(jù)類型的時(shí)候比較的是數(shù)值, 當(dāng)比較引用類型數(shù)據(jù)時(shí)比較的是引用(指針...

    番茄西紅柿 評(píng)論0 收藏0

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

0條評(píng)論

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