語法糖(Syntactic Sugar),也稱糖衣語法础倍,指在計算機語言中添加的某種語法烛占,這種語法對語言本身功能來說沒有什么影響,只是為了方便程序員的開發(fā)沟启,提高開發(fā)效率忆家。說白了,語法糖就是對現(xiàn)有語法的一個封裝德迹。
Java作為一種與平臺無關的高級語言芽卿,當然也含有語法糖,這些語法糖并不被虛擬機所支持胳搞,在編譯成字節(jié)碼階段就自動轉換成簡單常用語法卸例。一般來說Java中的語法糖主要有以下幾種:
- 泛型與類型擦除
- 自動裝箱與拆箱,變長參數(shù)肌毅、
- 增強for循環(huán)
- 內(nèi)部類與枚舉類
泛型與類型擦除
Java語言并不是一開始就支持泛型的筷转。在早期的JDK中,只能通過Object類是所有類型的父類和強制類型轉換來實現(xiàn)泛型的功能悬而。強制類型轉換的缺點就是把編譯期間的問題延遲到運行時呜舒,JVM并不能為我們提供編譯期間的檢查。
在JDK1.5中笨奠,Java語言引入了泛型機制袭蝗。但是這種泛型機制是通過類型擦除來實現(xiàn)的,即Java中的泛型只在程序源代碼中有效(源代碼階段提供類型檢查)艰躺,在編譯后的字節(jié)碼中自動用強制類型轉換進行替代呻袭。也就是說,Java語言中的泛型機制其實就是一顆語法糖腺兴,相較與C++左电、C#相比,其泛型實現(xiàn)實在是不那么優(yōu)雅页响。
/**
* 在源代碼中存在泛型
*/
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);
}123456789
當上述源代碼被編譯為class文件后篓足,泛型被擦除且引入強制類型轉換
public static void main(String[] args) {
HashMap map = new HashMap(); //類型擦除
map.put("hello", "你好");
String hello = (String)map.get("hello");//強制轉換
System.out.println(hello);
}123456
自動裝箱與拆箱
Java中的自動裝箱與拆箱指的是基本數(shù)據(jù)類型與他們的包裝類型之間的相互轉換。
我們知道Java是一門面向對象的語言闰蚕,在Java世界中有一句話是這么說的:“萬物皆對象”栈拖。但是Java中的基本數(shù)據(jù)類型卻不是對象,他們不需要進行new操作没陡,也不能調用任何方法涩哟,這在使用的時候有諸多不便索赏。因此Java為這些基本類型提供了包裝類,并且為了使用方便贴彼,提供了自動裝箱與拆箱功能潜腻。自動裝箱與拆箱在使用的過程中,其實是一個語法糖器仗,內(nèi)部還是調用了相應的函數(shù)進行轉換融涣。
下面代碼演示了自動裝箱和拆箱功能
public static void main(String[] args) {
Integer a = 1;
int b = 2;
int c = a + b;
System.out.println(c);
}123456
經(jīng)過編譯后,代碼如下
public static void main(String[] args) {
Integer a = Integer.valueOf(1); // 自動裝箱
byte b = 2;
int c = a.intValue() + b;//自動拆箱
System.out.println(c);
}123456
變長參數(shù)
所謂變長參數(shù)精钮,就是方法可以接受長度不定確定的參數(shù)
變長參數(shù)特性是在JDK1.5中引入的威鹿,使用變長參數(shù)有兩個條件,一是變長的那一部分參數(shù)具有相同的類型轨香,二是變長參數(shù)必須位于方法參數(shù)列表的最后面忽你。變長參數(shù)同樣是Java中的語法糖,其內(nèi)部實現(xiàn)是Java數(shù)組弹沽。
public class Varargs {
public static void print(String... args) {
for(String str : args){
System.out.println(str);
}
}
public static void main(String[] args) {
print("hello", "world");
}
}1234567891011
編譯為class文件后如下檀夹,從中可以很明顯的看出變長參數(shù)內(nèi)部是通過數(shù)組實現(xiàn)的
public class Varargs {
public Varargs() {
}
public static void print(String... args) {
String[] var1 = args;
int var2 = args.length;
//增強for循環(huán)的數(shù)組實現(xiàn)方式
for(int var3 = 0; var3 < var2; ++var3) {
String str = var1[var3];
System.out.println(str);
}
}
public static void main(String[] args) {
//變長參數(shù)轉換為數(shù)組
print(new String[]{"hello", "world"});
}
}1234567891011121314151617181920
增強for循環(huán)
增強for循環(huán)與普通for循環(huán)相比,功能更強并且代碼更簡潔
增強for循環(huán)的對象要么是一個數(shù)組策橘,要么實現(xiàn)了Iterable接口炸渡。這個語法糖主要用來對數(shù)組或者集合進行遍歷,其在循環(huán)過程中不能改變集合的大小丽已。
public static void main(String[] args) {
String[] params = new String[]{"hello","world"};
//增強for循環(huán)對象為數(shù)組
for(String str : params){
System.out.println(str);
}
List<String> lists = Arrays.asList("hello","world");
//增強for循環(huán)對象實現(xiàn)Iterable接口
for(String str : lists){
System.out.println(str);
}
}12345678910111213
編譯后的class文件為
public static void main(String[] args) {
String[] params = new String[]{"hello", "world"};
String[] lists = params;
int var3 = params.length;
//數(shù)組形式的增強for退化為普通for
for(int str = 0; str < var3; ++str) {
String str1 = lists[str];
System.out.println(str1);
}
List var6 = Arrays.asList(new String[]{"hello", "world"});
Iterator var7 = var6.iterator();
//實現(xiàn)Iterable接口的增強for使用iterator接口進行遍歷
while(var7.hasNext()) {
String var8 = (String)var7.next();
System.out.println(var8);
}
}12345678910111213141516171819
內(nèi)部類
內(nèi)部類就是定義在一個類內(nèi)部的類
Java語言中之所以引入內(nèi)部類蚌堵,是因為有些時候一個類只在另一個類中有用,我們不想讓其在另外一個地方被使用沛婴。內(nèi)部類之所以是語法糖吼畏,是因為其只是一個編譯時的概念,一旦編譯完成嘁灯,編譯器就會為內(nèi)部類生成一個單獨的class文件泻蚊,名為outer$innter.class。
public class Outer {
class Inner{
}
}1234
使用javac編譯后丑婿,生成兩個class文件Outer.class和Outer$性雄,其中Inner.class,其中Outer$Inner.class的內(nèi)容如下:
class Outer$Inner {
Outer$Inner(Outer var1) {
this.this$0 = var1;
}
}12345
內(nèi)部類分為四種:成員內(nèi)部類羹奉、局部內(nèi)部類秒旋、匿名內(nèi)部類、靜態(tài)內(nèi)部類诀拭,每一種都有其用法迁筛,這里就不介紹了
枚舉類型
枚舉類型就是一些具有相同特性的類常量
java中類的定義使用class,枚舉類的定義使用enum耕挨。在Java的字節(jié)碼結構中细卧,其實并沒有枚舉類型尉桩,枚舉類型只是一個語法糖,在編譯完成后被編譯成一個普通的類贪庙。這個類繼承java.lang.Enum魄健,并被final關鍵字修飾。
public enum Fruit {
APPLE,ORINGE
}123
使用jad對編譯后的class文件進行反編譯后得到:
//繼承java.lang.Enum并聲明為final
public final class Fruit extends Enum
{
public static Fruit[] values()
{
return (Fruit[])$VALUES.clone();
}
public static Fruit valueOf(String s)
{
return (Fruit)Enum.valueOf(Fruit, s);
}
private Fruit(String s, int i)
{
super(s, i);
}
//枚舉類型常量
public static final Fruit APPLE;
public static final Fruit ORANGE;
private static final Fruit $VALUES[];//使用數(shù)組進行維護
static
{
APPLE = new Fruit("APPLE", 0);
ORANGE = new Fruit("ORANGE", 1);
$VALUES = (new Fruit[] {
APPLE, ORANGE
});
}
}