聊聊面試-int和Integer的區別

  • 2019 年 10 月 22 日
  • 筆記

680x450.jpg

最近面試了很多候選人,發現很多人都不太重視基礎,甚至連工作十幾年,項目經驗十幾頁的老程式設計師,框架學了一大堆,但是很多 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

這裡面細節很多,我們就不一一講述,到這裡我們已經可以得出結果了,就是

  1. a1 == b1 對象的引用都是從快取中取出,實際上是相同對象,所以結果的 true
  2. a2 == b2 是因為128已經超過了快取值的範圍,Integer 通過 new 構造的對象,因為 == 比較的對象的引用而不是對象的值,所以結果自然就為 false

通過以上案例可以我們可以舉一反三,不僅僅 Integer 有快取機制,整個包裝類都有快取機制:

  • Boolean 快取了 true/false 實例,也就是說 Boolean 只會有 Boolean.TRUE/FALSE 兩個常量實例
  • Short 快取範圍是 -128 到 127 之間
  • Byte 範圍有限,全部數值都被快取
  • 等等……

如果繼續深挖快取,例如明確會頻繁使用更大範圍的 Integer 值得時候,我們可以使用 JVM 提供的參數

-XX:AutoBoxCacheMax=N
Integer 用起來有什麼注意事項嗎?
  1. 應當避免無意的使用拆裝箱
    自動拆/裝箱實際上是 Java 一種編譯期的優化(技巧),算是一種語法糖,只是 Java 在編譯期幫你自動轉化,最終生成的位元組碼還是和你自己轉換是一樣的,無意的創建十萬個對象對於程式的記憶體開銷和處理速度來說是巨大的代價
  2. 包裝類應避免使用 == 運算符進行值比較
  3. 注意快取機制的範圍
總結

以上我只大概列出的典型回答,其實對於大多數面試能回答以上內容就已經算可以及格了,有的公司面試官以喜歡追問出名,直到候選人回答說不知道,才會打住,這道看似簡單的題目,其實可以深挖的點還有很多,進一步考察你的基本功是否紮實,例如:

  1. 執行緒安全的 Integer (考察你對 java.util.concurrent 並發包的理解)
  2. 基本數據類型和引用類型的局限(考察你對 Java 泛型的理解)
  3. 對象在記憶體中的結構(對象頭 Header,實例數據 Instance Data,對齊填充 Padding)

int 和 Integer 的區別,這算是典型高頻面試題之一,也是考察候選人基本功的題目之一,如果你基本功紮實,那麼這基本算是一道送分題,目前我了解的大多數大廠和重視技術的公司都是非常重視候選人的基本功,基礎決定你的上限在哪裡,所以這裡我也建議大家不要花太多精力在框架的使用和工具的安裝配置上,多沉下心的修鍊基礎知識,理解基礎原理不僅可以很好的滿足日常開發,而且還可以幫助你走的更遠