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對象指針:确定對象是哪個類的執行個體
- markWord
- 執行個體資料(Instance Data):對象存儲的真正有效資訊,也是在程式代碼中所定義的各種類型的字段内容
- 對齊填充(Padding):它僅僅起着占位符的作用
資料:
java對象在記憶體中的結構(HotSpot虛拟機)
《深入了解java虛拟機》2.3章節
參考:
極客時間:《Java核心技術面試精講》
本筆記根據專欄主題進行學習筆記,雖然參考了許多做了筆記,但是加上了自己的整理,跟原作者的行文可能有很大偏差。如果想檢視原版請自行搜尋。謝謝