Java語法糖系列二:自動裝箱/拆箱和條件編譯

目錄:
Java語法糖系列一:可變長度參數和foreach循環
http://www.lxweimin.com/p/628568f94ef8

Java語法糖系列二:自動裝箱/拆箱和條件編譯
http://www.lxweimin.com/p/946b3c4a5db6

Java語法糖系列三:泛型與類型擦除
http://www.lxweimin.com/p/4de08deb6ba4

Java語法糖系列四:枚舉類型
http://www.lxweimin.com/p/ae09363fe734

Java語法糖系列五:內部類和閉包
http://www.lxweimin.com/p/f55b11a4cec2


上一篇寫到可變長參數和foreach循環,這篇討論下java的自動裝箱/拆箱和條件編譯這兩個語法糖。

自動裝箱/拆箱

自動拆箱/裝箱是在編譯期,依據代碼的語法,決定是否進行拆箱和裝箱動作。

裝箱過程:把基本類型用它們對應的包裝類型進行包裝,使基本類型具有對象特征。

拆箱過程:與裝箱過程相反,把包裝類型轉換成基本類型。

public static void main(String[] args){
    int i=1;
    Integer a = 1;
    Integer b = 1;
    Long c = 1L;
    System.out.println(a == b);
    System.out.println(a.equals(i));
    System.out.println(c.equals(a));
 }

結果是

 true
 true
 false

編譯出來的代碼如下

public static void main(String[] paramArrayOfString)
  {
      int i = 1;
       Integer localInteger1 = Integer.valueOf(1);
    Integer localInteger2 = Integer.valueOf(1);
       Long localLong = Long.valueOf(1L);
    System.out.println(localInteger1 == localInteger2);
       System.out.println(localInteger1.equals(Integer.valueOf(i)));
       System.out.println(localLong.equals(localInteger1));
  }

可以看到在自動裝箱的時候,Java虛擬機會自動調用Integer的valueOf方法;
在自動拆箱的時候,Java虛擬機會自動調用Integer的intValue方法。這就是自動拆箱和自動裝箱的原理。

注:上述例子的代碼應該盡量避免自動拆箱與裝箱。

條件編譯

很多編程語言都提供了條件編譯的途徑,C,C++中使用#ifdef。
看如下C代碼,在debug模式編譯代碼塊1,其他編譯代碼塊2

#define DEBUG  
#IFDEF DEBUUG  
  /* 
   code block 1 
   */   
#ELSE  
  /* 
   code block 2 
  */  
#ENDIF  

Java語言并沒有提供這種預編譯功能,但是Java也能實現預編譯。
源代碼

public static void main(String[] args){
    // TODO Auto-generated method stub
    if(true){  
        System.out.println("true");  
    }else{  
        System.out.println("false");  
    }  
}

編譯后的代碼

 public static void main(String[] paramArrayOfString)
  {
        System.out.println("true");
  }

可以看到編譯器會對代碼進行優化,對于條件永遠為false的語句,JAVA編譯器將不會對其生成字節碼。這一動作發生在編譯器解除語法糖階段。所以說,可以利用條件語句來實現預編譯。

至于運用當然是在bebug模式下打log啦

public static void main(String[] args){
    // TODO Auto-generated method stub
    boolean DEBUG=true;
    if(DEBUG) {  
        log.info("Syntactic Sugar!");  
    }  
}

一點拓展

看如下代碼

public static void main(String[] args){
    // TODO Auto-generated method stub
         Integer i1 = 127;
        Integer i2 = 127;
        Integer i3 = 128;
        Integer i4 = 128;
 
        System.out.println(i1 == i2);
        System.out.println(i3 == i4);
    
        Double d1 = 127.0;
        Double d2 = 127.0;
        Double d3 = 128.0;
        Double d4 = 128.0;
 
        System.out.println(d1 == d2);
        System.out.println(d3 == d4);
}

結果是

true
false
false
false

產生這樣的結果的原因是:Byte、Short、Integer、Long、Char這幾個裝箱類的valueOf()方法是以128位分界線做了緩存的,假如是[-128,127]區間的值是會取緩存里面的引用的,以Integer為例,其valueOf(int i)的源代碼為:

static final int low = -128;
static final int high=127;

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

而Float、Double不會的原因也很簡單,因為byte、Short、integer、long、char在某個范圍內的整數個數是有限的,但是float、double這兩個浮點數卻不是。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容