| 包裝類 | 緩存範圍 | 實現類 |
| Byte | -128 ~ 127 | ByteCache |
| Short | -128 ~ 127 | ShortCache |
| Integer | -128 ~ 127 | IntegerCache |
| Long | -128 ~ 127 | LongCache |
| Character | 0 ~ 127 (\\u0000-\\u007F) | CharacterCache |
| Boolean | true/false 兩個實例 | Boolean.TRUE/FALSE |
| Float/Double | 無緩存 | 每次 new |
驗證代碼
public class CacheDemo {
public static void main(String[] args) {
// Integer 緩存範圍驗證
Integer i1 = 100, i2 = 100; // 自動裝箱調用 Integer.valueOf(100)
Integer i3 = 128, i4 = 128;
System.out.println("100 == 100 ? " + (i1 == i2)); // true
System.out.println("128 == 128 ? " + (i3 == i4)); // false
// 其他類型
Character c1 = 'a', c2 = 'a'; // true (0-127)
Boolean b1 = true, b2 = true; // true
Double d1 = 1.0, d2 = 1.0; // false (無緩存)
}
}
二、IntegerCache 源碼剖析 (JDK 1.8)
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; // 可通過 -Djava.lang.Integer.IntegerCache.high=xxx 調整
static final Integer[] cache;
static {
int h = 127;
String prop = sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (prop != null) {
int v = Long.decode(prop).intValue();
h = Math.max(v, 127);
h = Math.min(h, Integer.MAX_VALUE - (-low) - 1);
}
high = h;
cache = new Integer[(high - low) + 1];
for (int k = 0; k < cache.length; k++)
cache[k] = new Integer(low + k);
}
private IntegerCache() {}
}
關鍵點:
- 靜態代碼塊初始化緩存數組,佔用極少內存(~1KB)
high 可通過 JVM 參數調大,low 固定 -128
- 自動裝箱
Integer i = 100 編譯為 Integer.valueOf(100)
三、String 常量池
特殊性
- JDK 7 起移至堆內存(原在永久代/元空間),受 GC 管理
- 兩種入池方式:
- 字面量聲明:
String s = "abc"; 編譯期入池
- 手動入池:
String s = new String("abc").intern(); 運行期入池
intern() 語義:池中有則返回引用,否則放入並返回引用
經典面試題
String s1 = "ab";
String s2 = "a" + "b"; // 編譯期常量折疊 → "ab" → 池中同一引用
String s3 = new String("ab"); // 堆中新對象
String s4 = s3.intern(); // 返回池中 "ab" 引用
System.out.println(s1 == s2); // true
System.out.println(s1 == s3); // false
System.out.println(s1 == s4); // true
System.out.println(s3 == s4); // false
四、常見誤區與最佳實踐
- 誤區:
Integer i = 200; Integer j = 200; i == j 為 true → 錯,超出緩存範圍各自 new
- 誤區:
String s = new String("a") + new String("b"); s.intern() == "ab" → JDK 7+ 為 true(池中無則放入堆對象引用),JDK 6 為 false(複製到永久代)
- 最佳實踐:
- 優先使用字面量
"text" 而非 new String("text")
- 大量字符串拼接用
StringBuilder
- 需比較內容用
equals(),== 僅比較引用
- 調整緩存範圍:
-XX:AutoBoxCacheMax=2000(部分 JVM 支持)
五、總結
常量池是 JVM「以空間換時間」的經典體現。基本類型包裝類緩存 -128~127、String 池存儲字面量與手動入池對象、IntegerCache 可配置上限。理解緩存邊界與 intern() 行為,能避免自動裝箱/字符串操作中的性能陷阱與邏輯 Bug。
- 上一篇文章: Java 文件上傳下載與郵件收發完整實戰:Servlet + JavaMail 核心代碼
- 下一篇文章: Struts2 通配符映射實戰:動態 Action 匹配與方法調用約定
Copyright ©
程式碼之家 All Rights Reserved