最近面試了很多候選人,發現很多人都不太重視基礎,甚至連工作十幾年,項目經驗十幾頁的老程序員,框架學了一大堆,但是很多 Java 相關的基礎知識卻很多都答不上來。還有很多人會回答,只知道要用,但是從來不會去看看它具體是怎么實現的。
我們都知道作為合格的程序員,基本功不扎實會導致你的程序出現許多你難以診斷的詭異問題,例如產生過大開銷(頻繁GC導致程序卡頓或者產生OOM),Integer 緩存機制產生的詭異現場(下面會詳細說),所以就有想寫一個關於面試相關系列的文章,把常見又容易采坑的面試問題總結一下,今天想站在面試官的角度去和大家聊聊一些面試的基礎題目,以及盡可能指導大家如何給出一個能讓面試官滿意的答復
基本回答
int 是 8 個基本數據類型(boolean, byte, short, char, int, float, double, long)之一的整形類型,大小占用4字節,取值范圍是正負 2 的 32(4 * 8)次冪,Java 雖然號稱一切都是對象,但是基本數據類型是例外
Integr 是 int 的包裝類,是 JDK 1.5 中引入,提供了字符串轉換,數學運算,泛型,自動拆箱裝箱等實用功能,極大簡化了相關的編程難度
聊聊 Intger 的值緩存范圍
下面給出一個典型例子,也是很多人踩過的坑,程序如下(建議自己在機器上實踐操作下)
Integer a1 = 127, b1 = 127;
Integer a2 = 128, b2 = 128;
System.out.println(a1 == b1); // true
System.out.println(a2 == b2); // false
包裝類緩存機制的原因
可以思考下為什么會出現以上這種詭異的情況,然后我們下面可以看看 Integer.valueOf 的源碼
// Integer.valueOf 的源碼
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 {
int h = 127;
...
high = h;
}
}
源碼之內無秘密,我們可以看出來出現以上問題的原因是原由 JDK 對 Integer 構造的改進引入緩存機制導致的,傳統構造 Integer 的方式是直接調用構造器 new 一個對象,但是在考察和調研后發現大多數人使用 Integer 都集中在較小的范圍,因此 JDK 為 Integer.valueOf 增強了一個緩存機制來改善構造對象的性能開銷(沒錯,自動拆箱裝箱反編譯后也是調用 valueOf() 方法實現構造對象)Java 官方文檔給出 Integer 緩存范圍是 -128 ~ 127
這里面細節很多,我們就不一一講述,到這里我們已經可以得出結果了,就是
- a1 == b1 對象的引用都是從緩存中取出,實際上是相同對象,所以結果的 true
- a2 == b2 是因為128已經超過了緩存值的范圍,Integer 通過 new 構造的對象,因為 == 比較的對象的引用而不是對象的值,所以結果自然就為 false
通過以上案例可以我們可以舉一反三,不僅僅 Integer 有緩存機制,整個包裝類都有緩存機制:
- Boolean 緩存了 true/false 實例,也就是說 Boolean 只會有 Boolean.TRUE/FALSE 兩個常量實例
- Short 緩存范圍是 -128 到 127 之間
- Byte 范圍有限,全部數值都被緩存
- 等等……
如果繼續深挖緩存,例如明確會頻繁使用更大范圍的 Integer 值得時候,我們可以使用 JVM 提供的參數
-XX:AutoBoxCacheMax=N
Integer 用起來有什么注意事項嗎?
- 應當避免無意的使用拆裝箱
自動拆/裝箱實際上是 Java 一種編譯期的優化(技巧),算是一種語法糖,只是 Java 在編譯期幫你自動轉化,最終生成的字節碼還是和你自己轉換是一樣的,無意的創建十萬個對象對於程序的內存開銷和處理速度來說是巨大的代價 - 包裝類應避免使用 == 運算符進行值比較
- 注意緩存機制的范圍
總結
以上我只大概列出的典型回答,其實對於大多數面試能回答以上內容就已經算可以及格了,有的公司面試官以喜歡追問出名,直到候選人回答說不知道,才會打住,這道看似簡單的題目,其實可以深挖的點還有很多,進一步考察你的基本功是否扎實,例如:
- 線程安全的 Integer (考察你對 java.util.concurrent 並發包的理解)
- 基本數據類型和引用類型的局限(考察你對 Java 泛型的理解)
- 對象在內存中的結構(對象頭 Header,實例數據 Instance Data,對齊填充 Padding)
int 和 Integer 的區別,這算是典型高頻面試題之一,也是考察候選人基本功的題目之一,如果你基本功扎實,那么這基本算是一道送分題,目前我了解的大多數大廠和重視技術的公司都是非常重視候選人的基本功,基礎決定你的上限在哪里,所以這里我也建議大家不要花太多精力在框架的使用和工具的安裝配置上,多沉下心的修煉基礎知識,理解基礎原理不僅可以很好的滿足日常開發,而且還可以幫助你走的更遠