首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java int 與 Integer 差異深度解析:自動裝箱拆箱、快取機制與陷阱

     編輯:Java 相關知識

前言

int 是基本型別,Integer 是其包裝類別。這對看似簡單的關係,實則包含記憶體模型、效能考量、語言設計哲學等深層議題。本文從基礎差異切入,深入剖析自動裝箱拆箱機制、Integer 快取範圍、== 比較陷阱與最佳實踐。

基礎差異總覽

維度intInteger
型別分類基本型別參考型別(類別)
記憶體儲存Stack(棧)直接存值Heap(堆)存物件,棧存參考
預設值0null
記憶體佔用4 bytes~16 bytes (物件頭 + 值 + 參考)
可為 null否是
泛型支援不可(List<int> 錯誤)可(List<Integer> 正確)
方法呼叫不可可(parseInt、toString、compareTo 等)

自動裝箱與拆箱

Java 5 引入編譯器語法糖,自動在基本型別與包裝類別間轉換:

// 裝箱:int -> Integer
Integer a = 100;              // 編譯為 Integer.valueOf(100)
Integer b = Integer.valueOf(100);

// 拆箱:Integer -> int
int c = a;                    // 編譯為 a.intValue()
int d = a + b;                // 隱式拆箱進行運算

// 陷阱:null 拆箱拋 NPE
Integer n = null;
int crash = n;                // NullPointerException

Integer.valueOf() 快取機制 - 核心知識點

為了效能,Integer.valueOf(int) 對 -128 到 127 範圍內的整數維護快取池:

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

// 快取範圍可透過 JVM 參數調整
// -XX:AutoBoxCacheMax=2000

經典面試題:== 比較行為

Integer a = 100;
Integer b = 100;
System.out.println(a == b); // true(快取命中)

Integer c = 200;
Integer d = 200;
System.out.println(c == d); // false(新物件,比較參考位址)

// 正確比較方式
System.out.println(c.equals(d)); // true
System.out.println(Objects.equals(c, d)); // 安全防 null

new Integer() vs valueOf()

Integer x = new Integer(100); // 強制建立新物件,不走快取
Integer y = Integer.valueOf(100); // 走快取
System.out.println(x == y); // false
System.out.println(x.equals(y)); // true

// Java 9+ 已棄用 new Integer(),建議統一用 valueOf() 或 parseInt()

集合框架中的實務影響

List list = new ArrayList<>();
list.add(100);           // 自動裝箱 -> Integer.valueOf(100)
list.add(200);           // 新物件

// 移除元素陷阱
list.remove(100);        // 呼叫 remove(int index) 移除索引 100,而非值 100!
list.remove(Integer.valueOf(100)); // 正確:呼叫 remove(Object) 移除值

效能基準測試參考

@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public class IntegerBenchmark {
    @Benchmark
    public int primitiveLoop() {
        int sum = 0;
        for (int i = 0; i < 1000; i++) sum += i;
        return sum;
    }

    @Benchmark
    public int boxedLoop() {
        Integer sum = 0;
        for (int i = 0; i < 1000; i++) sum += i; // 大量裝箱拆箱
        return sum;
    }
}
// 典型結果:primitive ~500ns, boxed ~5000ns (慢 10 倍)

最佳實踐總結

  1. 預設用 int:區域變數、運算、陣列索引、效能敏感路徑
  2. 必須用 Integer:集合元素、泛型參數、需表達「無值」(null)、序列化、資料庫映射
  3. 比較用 equals():絕不使用 == 比較 Integer 值
  4. 避免不必要裝箱:迴圈累加用基本型別,最後再裝箱
  5. 使用 Optional:替代 null 表達缺失值,語意更清晰
  6. JSON 序列化:Jackson 預設將 null 序列化為 null,非 null 輸出數字

擴展:其他包裝類別快取範圍

包裝類別快取範圍
Byte-128 ~ 127 (全域)
Short-128 ~ 127
Integer-128 ~ 127 (可調整上限)
Long-128 ~ 127
Character0 ~ 127 (ASCII)
BooleanTRUE/FALSE 兩個單例
Float/Double無快取

總結

理解 int 與 Integer 的差異不只是語法層面,更關乎記憶體模型、效能特徵與語言設計權衡。掌握快取機制、正確比較方式、避免無謂裝箱,是寫出高品質 Java 代碼的基本功。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved