语法糖,又称糖衣语法,是英国计算机科学家发明的一个术语,指在计算机语言中加入某种语法,这种语法对语言的功能并没有影响,但是方便了程序员的操作,并且增加了代码的可读性,减少了出错的机会。
Java 是一个 “低糖语言”,因为在 JDK1.5 之前,语法糖很少出现。但是从 Java 7 开始 Java 语言层面上一直在添加各种糖,未来还会持续向着 “高糖” 的方向发展。
Java 中最常用的语法糖主要有泛型、switch 支持 String、自动装箱与拆箱、foreach 循环、内部类和枚举等。
语法糖主要是方便开发人员使用。但其实,Java 虚拟机并不支持这些语法糖,这些语法糖在编译阶段就会被还原成简单的基础语法结构,这个过程就是解语法糖。
很多语言都是支持泛型的,但是不同的编译器对于泛型的处理方式是不同的。通常,编译器处理泛型有两种方式:Code specialization 和 Code sharing。
也就是说,在 Java 虚拟机的运行期,ArrayList< Integer > 和 ArrayList< String > 是一样的。Java 需要在编译阶段通过类型擦除的方式进行解语法糖。
类型擦除的主要过程如下:
源代码:
Map<String, String> map = new HashMap<String, String>();
map.put("kobe", "Lakers");
map.put("curry", "worries");
解语法糖之后(擦除类型后):
Map map = new HashMap();
map.put("kobe", "Lakers");
map.put("curry", "worries");
源代码:
public static <A extends Comparable<A>>A max(Collection<A> c) {
Iterator<A> it = c.iterator();
A w = it.next();
while (it.hasNext()) {
A x = it.next();
if (w.compareTo(x) < 0)
w = x;
}
return w;
}
解语法糖之后(擦除类型后):
public static Comparable max(Collection c) {
Iterator it = c.iterator();
Comparable w = (Comparable)it.next();
while (it.hasNext()) {
Comparable x = (Comparable)it.next();
if (w.compareTo(x) < 0)
w = x;
}
return w;
}
Java 虚拟机中没有泛型,只有普通类和普通方法,所有泛型类的类型参数在编译时都会被擦除。泛型类并没有自己独有的 Class 类对象,比如并不存在 List< String>.class或是 List< Integer>.class,而只有 List.class。
在 Java 7 之前,switch 只能支持 byte、short、char、int 或者其对应的封装类以及 Enum 类型。对于 int 类型,直接进行数值的比较;对于 char 类型,则是比较其 ascii 码。所以,对于编译器来说,switch 中其实只能使用整型,任何类型的比较都要转换成整型。
从 Java 7 开始,switch 开始支持 String。测试代码:
public class Test {
public static void main(String[] args) {
String str = "world";
switch (str) {
case "hello":
System.out.println("hello");
break;
case "world":
System.out.println("world");
break;
default:
break;
}
}
}
反编译后,代码如下:
public class Test {
public static void main(String args[]){
String str = "world";
String s;
switch((s = str).hashCode()){
default:
break;
case 99162322:
if(s.equals("hello"))
System.out.println("hello");
break;
case 113318802:
if(s.equals("world"))
System.out.println("world");
break;
}
}
}
由反编译的结果看出,String 的 switch 是通过 equals() 和 hashCode() 方法来实现的。hashCode() 方法返回的是 int。
自动装箱就是 Java 自动将原始基本类型值转换成对应的对象类型,比如将 int 变量转换成 Integer 对象,这个过程叫做装箱。反之将 Integer 对象转换成 int 类型值,这个过程叫做拆箱。因为这里的装箱和拆箱是自动进行的非人为转换,所以就称作为自动装箱和拆箱。
基本类型 byte、short、char、int、long、float、double 和 boolean 对应的封装类分别为 Byte、Short、Character、Integer、Long、Float、Double、Boolean。
public static void main(String[] args) {
int i = 10;
Integer n = i;
}
反编译后代码如下:
public static void main(String args[]) {
int i = 10;
Integer n = Integer.valueOf(i);
}
自动装箱的实现就是调用了 Integer.valueOf() 方法。
public static void main(String[] args) {
Integer i = 10;
int n = i;
}
反编译后代码如下:
public static void main(String args[]) {
Integer i = Integer.valueOf(10);
int n = i.intValue();
}
public static void main(String[] args) {
List<Integer> list = new ArrayList<Integer>();
list.add(500);
list.add(2);
list.add(new Integer(20));
for(int sub : list){
System.out.println(sub);
}
}
反编译后,代码如下:
public static void main(String[] args) {
List list = new ArrayList();
list.add(Integer.valueOf(500));
list.add(Integer.valueOf(2));
list.add(new Integer(20));
for (Iterator localIterator = list.iterator(); localIterator.hasNext(); ){
int sub = ((Integer)localIterator.next()).intValue();
System.out.println(sub);
}
}
foreach 实际上是在调用 list 的 iterator 进行遍历。这也就是为什么 foreach 循环要求被遍历的集合必须实现了 Iterator 接口。
内部类又称为嵌套类,可以把内部类理解为外部类的一个普通成员。内部类之所以也是语法糖,是因为它仅仅是一个编译时的概念。
Java SE5 提供了一种新的类型——Java 的枚举类型。关键字 enum 可以将一组具名的值的有限集合创建为一种新的类型,而这些具名的值可以作为常规的程序组件使用,这是一种非常有用的功能。定义一个枚举类型:
public enum t {
SPRING,SUMMER;
}
enum 和 class 一样,只是一个关键字,它并不是一个类。
当我们使用 enum 来定义一个枚举类型的时候,编译器会自动帮我们创建一个 final 类型的类并继承 Enum 类来实现枚举,所以枚举类型不能被继承。
参考自:
Java 语法糖详解