Java語法糖(一)
阿新 • • 發佈:2017-10-12
級別 類型擦除 簽名 轉換 uga pre 它的 out fde
概述
語法糖(Syntactic Sugar):主要作用是提高編碼效率,減少編碼出錯的機會。
解語法糖發生在Java源碼被編譯成Class字節碼的過程中,還原回簡單的基礎語法結構。
語法糖之一:泛型(Generics)
Java中的泛型又稱為類型擦除,它只在Java源碼中存在,被編譯成字節碼後,就已經替換為原生類型了,並在相應的地方加入強制類型轉換。
例如:
public class GenericTypes { /* * 兩個mothod1方法不能被編譯,因為List<Integer>和List<String>被編譯成class文件後都被擦除了, * 變成了一樣的原生類型List<T>,擦除之後兩個方法的簽名一樣。*/ public static void mothod1(List<Integer> list) { } public static void mothod1(List<String> list) { } /* * 在jdk1.7 * 兩個mothod2方法不能被編譯,因為List<Integer>和List<String>被編譯成class文件後都被擦除了, * 變成了一樣的原生類型List<T>,擦除之後兩個方法的簽名一樣。返回值不參與重載選擇 * * Sun JDK1.6中Javac才能編譯成功 * 在Class文件格式中,只要描述符不是完全一致的兩個方法就可以共存。*/ public static String mothod2(List<String> list) { return ""; } public static Integer mothod2(List<Integer> list) { return 1; } }
語法糖之二:自動拆箱和裝箱、Foreach、變長參數
例如:
public class Foreach_Varargs { public static void main(String[] args) { List<Integer> list = Arrays.asList(1, 2, 3, 4);//變長參數(Varargs) int sum = 0; for(int i : list) { //遍歷循環Foreach sum += i; } System.out.println(sum); } /* * 反編譯之後的代碼 * 1、變長參數還原為數組類型的參數:Arrays.asList(...) ----> new Integer[]{...} * 2、Foreach還原為叠代器實現 * 3、自動拆箱和裝箱還原為Integer.valueOf()和Integer.intValue()方法 * public static void main(String[] args) { java.util.List<Integer> list = java.util.Arrays.asList(new Integer[] { Integer.valueOf(1), Integer.valueOf(2), Integer.valueOf(3), Integer.valueOf(4) }); int sum = 0; for (Iterator localIterator = list.iterator(); localIterator.hasNext();) { int i = ((Integer) localIterator.next()).intValue(); sum += i; } System.out.println(sum); } */ }
一個更復雜的自動裝箱拆箱的栗子:
public class Autoboxing { public static void main(String[] args) { Integer a = 1; Integer b = 2; Integer c = 3; Integer d = 3; Integer e = 321; Integer f = 321; Long g = 3L; System.out.println(c == d); //(1) System.out.println(e == f); //(2) System.out.println(c == (a + b)); //(3) System.out.println(c.equals(a + b)); //(4) System.out.println(g == (a + b)); //(5) System.out.println(g.equals(a + b)); //(6) } /* * 反編譯後的代碼 * * 包裝類的“==”運算在不遇到算數運算的情況下不會自動拆箱; * equals方法不處理數據轉型的關系。 * * 在 Java 中,== 比較的是對象引用,而 equals 比較的是值。 * * 一、(1)為true,(2)為false原因: * IntegerCache:把-128到127(可調)的整數都提前實例化了,不管創建多少個這個範圍內的Integer用ValueOf出來的都是同一個對象; * 用來節省內存和提高性能。這種 Integer緩存策略僅在自動裝箱(autoboxing)的時候有用,使用構造器創建的 Integer 對象不能被緩存。 * 這個緩存會在 Integer 類第一次被使用的時候被初始化出來.是什麽原因選擇這個 -128 到 127 這個範圍呢?因為這個範圍的整數值是使用最廣泛的。 * Byte,Short,Long 有固定範圍: -128 到 127。對於 Character, 範圍是 0 到 127。除了 Integer 可以通過參數改變範圍外,其它的都不行 * * 不在緩存範圍的會新new Integer對象。 * 二、(3)為true,(5)為true * 自動拆箱,相當於數值類型int * 三、(4)為true * a,b先拆箱計算數值和,再將計算結果裝箱為Integer * 四、(5)為false * g為Long類型,a + b為Integer,類型不一致 * 五、(6)為false, g為Long類型,a + b為Integer,類型不一致,返回false public boolean equals(Object obj) { if (obj instanceof Long) { return value == ((Long)obj).longValue(); } return false; } * public class Autoboxing { public static void main(String[] args) { Integer a = Integer.valueOf(1); Integer b = Integer.valueOf(2); Integer c = Integer.valueOf(3); Integer d = Integer.valueOf(3); Integer e = Integer.valueOf(321); Integer f = Integer.valueOf(321); Long g = Long.valueOf(3L); System.out.println(c == d); System.out.println(e == f); System.out.println(c.intValue() == a.intValue() + b.intValue()); System.out.println(c.equals(Integer.valueOf(a.intValue() + b.intValue()))); System.out.println(g.longValue() == (long)(a.intValue() + b.intValue())); System.out.println(g.equals(Integer.valueOf(a.intValue() + b.intValue()))); } } */ }
語法糖之三:條件編譯
栗子:
public class ifdef { public static void main(String[] args) { final boolean isCompile = true; if(isCompile) { System.out.println("11111"); } else { System.out.println("2222"); } } /* * 條件編譯 * System.out.println("2222"); 不會編譯 * Java只能實現語句基本塊級別的條件編譯,而無法實現根據條件調整整個Java類的結構。 * * 反編譯後的代碼: * public class ifdef { public static void main(String[] args) { boolean isCompile = true; System.out.println("11111"); } } */ }
除以上外,語法糖還有:內部類、枚舉類、斷言語句、對枚舉和字符串的switch支持(1.7)、try語句中定義和關閉資源(1.7)等,接下來繼續Java語法糖系列。
Java語法糖(一)