语法糖
语法糖:也称糖衣语法,指在计算机语言中添加的某种语法,这种语法对语言的功能并没有影响,但是更方便程序员使用。Java 中最常用的语法糖主要有泛型、变长参数、条件编译、自动拆装箱、内部类等。
解语法糖:虚拟机并不支持这些语法,它们在编译阶段就被还原回了简单的基础语法结构。
java中的语法糖只存在于编译期, 在编译器将 .java 源文件编译成 .class 字节码时, 会进行解语法糖操作, 还原最原始的基础语法结构。
语法糖包含条件编译、断言、Switch语句与枚举及字符串结合、可变参数、自动装箱/拆箱、枚举、内部类、泛型擦除、增强for循环、lambda表达式、try-with-resources语句、JDK10的局部变量类型推断等等。
条件编译
public void Test() {
public static void main(String[] args) {
if(false){
System.out.println("yyy");
}else {
System.out.println("xxx");
}
}
}
命令行:java -jar cfr-0.151.jar Test.class
javac编译器在编译时期的解语法糖阶段, 会将条件分支不成立的代码进行消除。
自动装箱与拆箱
Java中的自动装箱与拆箱指的是基本数据类型与他们的包装类型之间的相互转换。
我们知道Java是一门面向对象的语言,在Java世界中有一句话是这么说的:“万物皆对象”。但是Java中的基本数据类型却不是对象,他们不需要进行new操作,也不能调用任何方法,这在使用的时候有诸多不便。因此Java为这些基本类型提供了包装类,并且为了使用方便,提供了自动装箱与拆箱功能。自动装箱与拆箱在使用的过程中,其实是一个语法糖,内部还是调用了相应的函数进行转换。
public class Test3 {
public static void main(String[] args) {
Integer a = 1;
int b = 2;
int c = a + b;
System.out.println(c);
}
}
编译后
public class Test3 {
public static void main(String[] paramArrayOfString) {
Integer integer = Integer.valueOf(1); //自动装箱
byte b = 2;
int i = integer.intValue() + b; //自动拆箱
System.out.println(i);
}
}
增强for循环
增强for循环与普通for循环相比,功能更强并且代码更简洁
增强for循环的对象要么是一个数组,要么实现了Iterable接口。这个语法糖主要用来对数组或者集合进行遍历,其在循环过程中不能改变集合的大小。
import java.util.Arrays;
import java.util.List;
public class Test4 {
public static void main(String[] args) {
String[] params = new String[]{"hello", "world"};
//增强for循环对象为数组
for (String str : params) {
System.out.println(str);
}
List<String> lists = Arrays.asList("hello", "world");
//增强for循环对象实现Iterable接口
for (String str : lists) {
System.out.println(str);
}
}
}
编译后
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
public class Test4 {
public Test4() {
}
public static void main(String[] var0) {
String[] var1 = new String[]{"hello", "world"};
String[] var2 = var1;
int var3 = var1.length;
//数组形式的增强for退化为普通for
for(int var4 = 0; var4 < var3; ++var4) {
String var5 = var2[var4];
System.out.println(var5);
}
List var6 = Arrays.asList("hello", "world");
Iterator var7 = var6.iterator();
//实现Iterable接口的增强for使用iterator接口进行遍历
while(var7.hasNext()) {
String var8 = (String)var7.next();
System.out.println(var8);
}
}
}
变长参数
所谓变长参数,就是方法可以接受长度不定确定的参数
变长参数特性是在JDK1.5中引入的,使用变长参数有两个条件,一是变长的那一部分参数具有相同的类型,二是变长参数必须位于方法参数列表的最后面。变长参数同样是Java中的语法糖,其内部实现是Java数组。
public class Test5 {
public static void print(String... args) {
for(String str : args){
System.out.println(str);
}
}
public static void main(String[] args) {
print("hello", "world");
}
}
编译后
public class Test5 {
public Test5() {
}
public static void print(String... args) {
String[] var1 = args;
int var2 = args.length;
for(int var3 = 0; var3 < var2; ++var3) {
String str = var1[var3];
System.out.println(str);
}
}
public static void main(String[] args) {
//变长参数转换为数组
print(new String[]{"hello", "world"});
}
}
泛型和类型擦除
Java语言并不是一开始就支持泛型的。在早期的JDK中,只能通过Object类是所有类型的父类和强制类型转换来实现泛型的功能。强制类型转换的缺点就是把编译期间的问题延迟到运行时,JVM并不能为我们提供编译期间的检查。在JDK1.5中,Java语言引入了泛型机制。但是这种泛型机制是通过类型擦除来实现的,即Java中的泛型只在程序源代码中有效(源代码阶段提供类型检查),在编译后的字节码中自动用强制类型转换进行替代。也就是说,Java语言中的泛型机制其实就是一颗语法糖。Java 语言中的泛型实现方法称为类型擦除,基于这种方法实现的泛型被称为伪泛型。
import java.util.HashMap;
import java.util.Map;
public class Test2 {
public static void main(String[] args) {
Map<String,String> map = new HashMap<String,String>();
map.put("hello","你好");
String hello = map.get("hello");
System.out.println(hello);
}
}
import java.util.HashMap;
public class Test2 {
public Test2() {
}
public static void main(String[] var0) {
HashMap var1 = new HashMap();//类型擦除
var1.put("hello", "你好");
String var2 = (String)var1.get("hello");//强制转换
System.out.println(var2);
}
}