语法糖(Syntactic Sugar),也称糖衣语法,是由英国计算机学家Peter.J.Landin发明的一个术语,指在计算机语言中添加的某种语法,这种语法对语言的功能并没有影响,但是更方便程序员使用。
Java中最常用的语法糖主要有泛型、变长参数、条件编译、自动拆装箱、内部类等。
虚拟机并不支持这些语法,它们在编译阶段就被还原回了简单的基础语法结构,这个过程成为解语法糖。
泛型与泛型擦除
泛型实际上只在程序源码中存在,在编译后的字节码文件中,就已经被替换为了原来的原生类型,并且在相应的地方插入了强制转型代码。
因此对于运行期的Java语言来说,ArrayList<String>和ArrayList<Integer>就是同一个类。
所以泛型技术实际上是Java语言的一颗语法糖,Java语言中的泛型实现方法称为类型擦除,基于这种方法实现的泛型被称为伪泛型。
1 2 3 4 5 6 7 8
| public class FanxingTest{ public void method(List<String> list){ System.out.println("List String"); } public void method(List<Integer> list){ System.out.println("List Int"); } }
|
当我用Javac编译器编译这段代码时,报出了如下错误:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| FanxingTest.java:3: 名称冲突:method(java.util.List<java.lang.String>) 和 method (java.util.List<java.lang.Integer>) 具有相同疑符 public void method(List<String> list){ ^ FanxingTest.java:6: 名称冲突:method(java.util.List<java.lang.Integer>) 和 metho d(java.util.List<java.lang.String>) 具有相同疑符 public void method(List<Integer> list){ ^ 2 错误
|
这是因为泛型List和List编译后都被擦除了,变成了一样的原生类型List,擦除动作导致这两个方法的特征签名变得一模一样,在Class类文件结构一文中讲过,Class文件中不能存在特征签名相同的方法。
1 2 3 4 5 6 7 8 9 10
| public class FanxingTest{ public int method(List<String> list){ System.out.println("List String"); return 1; } public boolean method(List<Integer> list){ System.out.println("List Int"); return true; } }
|
修改后发现这时编译可以通过了(注意:Java语言中true和1没有关联,二者属于不同的类型,不能相互转换,不存在C语言中整数值非零即真的情况)。两个不同类型的返回值的加入,使得方法的重载成功了。
Java代码中的方法特征签名只包括了方法名称、参数顺序和参数类型,并不包括方法的返回值,因此方法的返回值并不参与重载方法的选择,这样看来为重载方法加入返回值貌似是多余的。对于重载方法的选择来说,这确实是多余的,但我们现在要解决的问题是让上述代码能通过编译,让两个重载方法能够合理地共存于同一个Class文件之中,这就要看字节码的方法特征签名,它不仅包括了Java代码中方法特征签名中所包含的那些信息,还包括方法返回值及受查异常表。为两个重载方法加入不同的返回值后,因为有了不同的字节码特征签名,它们便可以共存于一个Class文件之中。
注:
(A)、Java语言层面的方法特征签名:
特征签名 = 方法名 + 参数类型 + 参数顺序;
(B)、JVM层面的方法特征签名:
特征签名 = 方法名 + 参数类型 + 参数顺序 + 返回值类型;
自动装箱拆箱
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
| public static void main(String[] args) { Integer i1 = 111111; int i2 = 111111; Integer i3 = Integer.valueOf(111111); Integer i4 = new Integer(111111); System.out.println(i1 == i2); System.out.println(i1 == i3); System.out.println(i2 == i4); System.out.println(i3 == i4); System.out.println(i2 == i3); System.out.println(i1 == i4); public static Integer valueOf(int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); } */ public static Double valueOf(double d) { return new Double(d); } */ Double d1 = 34.0; Double d2 = 34.0; System.out.println("d1 == d2 -> " + (d1 == d2)); Long ll = 3l; int a = 1; int b = 2; System.out.println(ll == (a + b)); System.out.println(ll.equals(a + b)); byte b1=1,b2=2,b3,b6; final byte b4=4,b5=6; b6=b4+b5; System.out.println(b6); Byte b7 = 8+2; System.out.println(b7); }
|