關於Java自動裝箱拆箱的面試題

問:請寫出運行結果?

        Long l1 = 128L;
        Long l2 = 128L;
        
        System.out.println(l1 == l2);     //1
        System.out.println(l1 == 128L);   //2
        
        Long l3 = 127L;
        Long l4 = 127L;
        
        System.out.println(l3 == l4);     //3
        System.out.println(l3 == 127L);   //4
   

答:1,false;2, true;3,true;4,true。
對於註釋 1 的語句,Long 包裝類型常量 cache 爲 -128 到 127 之間,所以 l1 和 l2 變量是兩個對象,== 比較的是對象的地址,所以打印爲 false。

對於註釋 2 的語句,由於包裝類型在表達式中且表達式中至少有一個不是包裝類型,所以 Long l1 == 128L 中 l1 自動拆箱退化爲基本類型比較,所以數值比較爲 true。

對於註釋 3 的語句,Long 包裝類型 -128 到 127 之間的值維護在一個常量池中,所以 l3 和 l4 引用同一個對象,故打印 true。

對於註釋 4 的語句類似註釋 2 語句,所以打印爲 true。

問:java 是否存在使得語句 i > j || i <= j 結果爲 false 的 i、j 值?

答:存在,java 的數值 NaN 代表 not a number,無法用於比較,例如使 i = Double.NaN; j = i; 最後 i == j 的結果依舊爲 false,這是一道非常變態的題,巨坑,誰特麼會這麼用。

問:java 1.5 的自動裝箱拆箱機制是編譯特性還是虛擬機運行時特性?分別是怎麼實現的?

答:java 1.5 開始的自動裝箱拆箱機制其實是編譯時自動完成替換的,裝箱階段自動替換爲了 valueOf 方法,拆箱階段自動替換爲了 xxxValue 方法。對於 Integer 類型的 valueOf 方法參數如果是 -128~127 之間的值會直接返回內部緩存池中已經存在對象的引用,參數是其他範圍值則返回新建對象;而 Double 類型與 Integer 類型類似,一樣會調用 Double 的 valueOf 方法,但是 Double 的區別在於不管傳入的參數值是多少都會 new 一個對象來表達該數值(因爲在指定範圍內浮點型數據個數是不確定的,整型等個數是確定的,所以可以 Cache)。

注意:Integer、Short、Byte、Character、Long 的 valueOf 方法實現類似,而 Double 和 Float 比較特殊,每次返回新包裝對象,對於兩邊都是包裝類型的比較 = = 比較的是引用,equals 比較的是值,對於兩邊有一邊是表達式(包含算數運算)則 = = 比較的是數值(自動觸發拆箱過程),對於包裝類型 equals 方法不會進行類型轉換。

問:下面是一組 java 包裝類型、自動拆箱、裝箱的題目,請寫出運行結果?


        Integer i1 = 100;
        Integer i2 = 100;
        Integer i3 = 200;
        Integer i4 = 200;
        System.out.println(i1 == i2);//true
        System.out.println(i3 == i4);//false
        System.out.println(i3 == 200);//true

        Double d1 = 100.0;
        Double d2 = 100.0;
        Double d3 = 200.0;
        Double d4 = 200.0;
        System.out.println(d1 == d2);//false
        System.out.println(d3 == d4);//false
        System.out.println(d3 == 200.0);//true

        Float f1 = 100.0F;
        Float f2 = 100.0F;
        Float f3 = 200.0F;
        Float f4 = 200.0f;
        System.out.println(f1 == f2);//false
        System.out.println(f3 == f4);//false
        System.out.println(f3 == 200);//true
        
        Integer a1 = 1;
        Integer a2 = 2;
        Integer a3 = 3;
        Long l2 = 2L;
        Long l3 = 3L;

        System.out.println(a3 == (a1 + a2));//true
        System.out.println(a3.equals(a1 + a2));//true

        System.out.println(l3 == (a1 + a2));//true
        System.out.println(l3.equals(a1 + a2));//false
        System.out.println(l3.equals(a1 + l2));//true


        Integer a = 256;
        int b = 256;
        System.out.println(a == b);//true
        System.out.println(a.equals(b));//true

答:答案如上註釋部分,核心考察點就是上道題的答案,即 java 1.5 開始的自動裝箱拆箱機制其實是編譯器自動完成的替換,裝箱階段自動替換爲了 valueOf 方法,拆箱階段自動替換爲了 xxxValue 方法。對於 Integer 類型的 valueOf 方法參數如果是 -128~127 之間的值會直接返回內部緩存池中已經存在對象的引用,參數是其他範圍值則返回新建對象;而 Double 類型與 Integer 類型一樣會調用到 Double 的 valueOf 方法,但是 Double 的區別在於不管傳入的參數值是多少都會 new 一個對象來表達該數值(因爲在指定範圍內浮點型數據個數是不確定的,整型等個數是確定的,所以可以 Cache)。 注意:Integer、Short、Byte、Character、Long 的 valueOf 方法實現類似,而 Double 和 Float 比較特殊,每次返回新包裝對象。 對於兩邊都是包裝類型的比較 = = 比較的是引用,equals 比較的是值,對於兩邊有一邊是表達式(包含算數運算)則 = = 比較的是數值(自動觸發拆箱過程),對於包裝類型 equals 方法不會進行類型轉換。

問:java 語句 Integer i = 1; i += 1; 做了哪些事情?

答:首先 Integer i = 1; 做了自動裝箱(使用 valueOf() 方法將 int 裝箱爲 Integer 類型),接着 i += 1; 先將 Integer 類型的 i 自動拆箱成 int(使用 intValue() 方法將 Integer 拆箱爲 int),完成加法運行之後的 i 再裝箱成 Integer 類型。

問:下面程序的運行結果是什麼?

        Integer a = new Integer(2);
        Integer b = new Integer(2);

        System.out.println(a == b);//false
        System.out.println(a.equals(b));//true

        Integer c = new Integer(128);
        Integer d = new Integer(128);
        
        System.out.println(c == d);//false
        System.out.println(c.equals(d));//true

答:答案如上註釋所述,通過查看 Integer 的源碼可以發現,針對 -128 到 127 之間的數據做了一個數據緩衝池,如果數據是該範圍內的,每次並不創建新的對象,所以就有了上面的結果。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章