天天看點

第7講 int和Integer有什麼差別?

int和Integer有什麼差別?談談Integer的值緩存範圍

int

是我們常說的整形數字,是Java的8個原始資料類型

(Primitive Types, boolean、 byte 、 short、 char、 int、 float、 double、 long)之一。 Java語言雖然号稱一切都是對象,但原始資料類型是例外。

Integer

是int對應的包裝類,它有一個int類型的字段存儲資料,并且提供了基本操作,比如數學運算、 int和字元串之間轉換等。在Java 5中,引入了自動裝箱和自動拆箱功能

(boxing/unboxing), Java可以根據上下文,自動進行轉換,極大地簡化了相關程式設計。

關于Integer的值緩存

這涉及Java 5中另一個改進。建構Integer對象的傳統方式是直接調用構造器,直接new一個對象。但是根據實踐,我們發現大部分資料操作都是集中在有

限的、較小的數值範圍,因而,在Java 5中新增了靜态工廠方法valueOf,在調用它的時候會利用一個緩存機制,帶來了明顯的性能改進。按照Javadoc, 這個值預設緩存

是-128到127之間。

知識擴充

了解自動裝箱、拆箱

自動裝箱實際上算是一種文法糖。它們發生在編譯階段,也就是生成的位元組碼

是一緻的

前面提到的整數, javac替我們自動把裝箱轉換為Integer.valueOf(),把拆箱替換為Integer.intValue() ,這似乎這也順道回答了另一個問題,既然調用的是Integer.valueOf,

自然能夠得到緩存的好處啊。

緩存機制并不是隻有Integer才有,同樣存在于其他的一些包裝類,比如:

  • Boolean,緩存了true/false對應執行個體,确切說,隻會傳回兩個常量執行個體Boolean.TRUE/FALSE。
  • Short,同樣是緩存了-128到127之間的數值
  • Byte,數值有限,是以全部都被緩存
  • Character,緩存範圍’\u0000’ 到 ‘\u007F’。

源碼分析

Integer的緩存範圍雖然預設是-128到127,但是在特别的應用場景,比如我們明确知道應用會頻繁使用更大的數值,這時候應該怎麼辦呢?

(一)

緩存上限值實際是可以根據需要調整的, JVM提供了參數設定:

-XX:AutoBoxCacheMax=N
           

實作在IntegerCache的靜态初始化塊裡

/**
     * Cache to support the object identity semantics of autoboxing for values between
     * -128 and 127 (inclusive) as required by JLS.
     *
     * The cache is initialized on first usage.  The size of the cache
     * may be controlled by the {@code -XX:AutoBoxCacheMax=<size>} option.
     * During VM initialization, java.lang.Integer.IntegerCache.high property
     * may be set and saved in the private system properties in the
     * sun.misc.VM class.
     */

    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() {}
    }
           
(二)

字元串是不可變的,保證了基本的資訊安全和并發程式設計中的線程安全。如果你去看包裝類裡存儲數值的成員變量“value”,你會發現,

不管是Integer還Boolean等,都被聲明為“private fnal”,是以,它們同樣是不可變類型!

(三)

Integer等包裝類,定義了類似SIZE或者BYTES這樣的常量,這反映了什麼樣的設計考慮呢?

開發者無需擔心資料的位數差

異。

原始類型線程安全

如果有線程安全的計算需要,建議考慮使用類

似AtomicInteger、 AtomicLong這樣的線程安全類。

部分比較寬的資料類型,比如foat、 double,甚至不能保證更新操作的原子性,可能出現程式讀取到隻更新了一半資料位的數值!

值緩存面試題

public class main {

	public static void main(String[] args) {
        Integer i1 = 127;  
        Integer i2 = 127;  
        System.err.println(i1 == i2);  //true
          
        i1 = 128;  
        i2 = 128;  
        System.err.println(i1 == i2);  //false
	}
}
           

結果

true
false
           

java對象結構

Java對象要比原始資料類型開銷大的多。你知道對象的記憶體結構是什麼樣的嗎?比如,

對象頭的結構。如何計算或者擷取某個Java對象的大小?

對象的記憶體結構是什麼樣的?

對象在記憶體中存儲的布局可以分為三塊區域:

  • 對象頭(Header)有兩部分,
    • markWord
      • markword包括存儲對象自身的運作時資料, 如哈希碼(HashCode)、 GC分代年齡、鎖狀态标志、線程持有的鎖、偏向線程ID、偏向時間戳
    • Class對象指針:确定對象是哪個類的執行個體
  • 執行個體資料(Instance Data):對象存儲的真正有效資訊,也是在程式代碼中所定義的各種類型的字段内容
  • 對齊填充(Padding):它僅僅起着占位符的作用
資料:

java對象在記憶體中的結構(HotSpot虛拟機)

《深入了解java虛拟機》2.3章節

參考:

極客時間:《Java核心技術面試精講》

本筆記根據專欄主題進行學習筆記,雖然參考了許多做了筆記,但是加上了自己的整理,跟原作者的行文可能有很大偏差。如果想檢視原版請自行搜尋。謝謝