Java從5.0版本開始,加入許多新特性,是Java歷史中修改最大的版本,許多特點模仿自C#,因而被認為是為了與C#對抗。
将Java中8个基本类型实现自动对象化和值化转换,通过编译器自动完成相关转换代码的生成。
沒有自動裝箱/拆箱:
intint1=1;Integerinteger2=newInteger(int1);intint3=integer2.intValue();
有自動裝箱/拆箱:
intint1=1;Integerinteger2=int1;// 自動裝箱intint3=integer2;// 自動拆箱
实际上将相关字节码反编译后,会还原出其隐式调用的转换方法:
intint1=1;Integerinteger2=Integer.valueOf(int1);// 自動裝箱的本质,通过调用valueOf将值对象化intint3=integer2.intValue();// 自動拆箱的本质,通过调用xxxValue将对象值化
自動裝箱的新功能,可能是從C#語言身上學習來的,Java已經越來越像C#。然而Java對自動裝箱/拆箱的支援,僅是利用編譯器實現,在Java Bytecode中,並無自動裝箱/拆箱的操作碼(opcode)。
泛型就像是C++的模板。原有的Collection API加上泛型支援後,增加對型別的檢查,減少程式錯誤的機會。
沒有泛型:
HashMaphm=newHashMap();inti=1;Stringtt="test";hm.put(newInteger(i),tt);
使用Generic:
HashMap<Integer,String>hm=newHashMap<Integer,String>();inti=1;Stringtt="test";hm.put(i,tt);// 在這裏對int自動裝箱成Integer,也使用了參數的型別檢查
Annotation全名是Program Annotation Facility,是Java SE 5.0的新功能。Java的Annotation類似於.NET的屬性(Attribute)。Java的注解是一種接口(interface),繼承自java.lang.annotation.Annotation。Class File則貼上ACC_ANNOTATION標籤。
從5.0開始,javadoc的@deprecated
(代表不建議使用的方法或類別)也被Annotation中的@Deprecated
取代;另外,使用Java實作SOP的AspectJ與Spring也使用了大量的Annotation。
// JDK 1.4/** * @todo to be implemented **/voidgimmeSomeLoving(){thrownewException("not implemented");}
// JDK 1.5@todovoidgimmeSomeLoving(){thrownewException("not implemented");}
枚举类型也是J2SE 5.0的新功能。過去Java認為enum的關鍵字是不必要的功能,因為用public static int field就可以取代enum,因此過去一直不用。J2SE 5.0中的class如果是enum,在class file中會被貼上一個ACC_ENUM標籤。
Enum 一般用来表示一组相同类型的常量。如性别、日期、月份、颜色等。对这些属性用常量的好处是显而易见的,不仅可以保证单例,且比较时候可以用 “==” 来替换 equals 。是一种好的习惯。 JDK1.5 之前没有 Enum 这个类型,那时候一般用接口常量来替代。Java有了Enum 之后,可以更贴近的表示这种常量。
// JDK 1.4classJavaTech{publicstaticfinalintJ2ME=1;publicstaticfinalintJ2SE=2;publicstaticfinalintJ2EE=3;}
// JDK 1.5publicenumNewJavaTech{J2ME,J2SE,J2EE}
Java语言严格区分字节和字符。字符的存储格式为UCS-2,也就是只能使用位於基本多文種平面的字元,从Java 5开始支持UTF-16字符。
另外,從5.0開始Java的程式也開始可以使用Unicode字元進行命名。
下面就是一個合法的Java程式,裡面包含了中文字符作為字串的名稱,這個程式可以在编譯器中通過編譯。
publicclassHelloWorld{privateString文本="HelloWorld";}
在jdk1.5及其以後版本中,java.util.Scanner
和java.util.Formatter
類別被应用到輸入輸出中。另外,也出現了類似C語言的printf()
函式。
foreach迴圈,有時又稱forin迴圈,在許多程式語言(包括C#、Ruby、JavaScript)中都有出現,可以直接將一個Array或Map展開,而不必由程式設計師自行檢查邊界,可以有效減少錯誤的機會。
int[]array1={1,3,5};for(inti:array1){// foreach迴圈System.out.println("Number: "+i);}
長久以來一直有使用者要求加入printf()
函式,受限於Java函式必須要有固定引數的限制,始終無法實現,在加入這個功能之後,連帶printf()
也變為可能。
這個特性允許程式設計師將一個類別中的靜態內容引入到程式中。
staticimportjava.lang.System.*;publicclassHelloWorld{publicstaticvoidmain(Stringargs[]){out.println("Hello World.");}}
Java 5.0雖然加入許多的新特性,但為了與舊版本相容,JVM並沒有隨之改變,而僅只是從編譯器動手腳,因而引發許多問題。討論Java語言問題的專書《Java Puzzle》就有專門的篇幅討論5.0之後造成的問題。
自動裝箱這功能也造成了一些矛盾,例如:
Integerint1=newInteger(1);Integerint2=newInteger(1);System.out.println(int1>=int2);// 檢查兩者的值(触发了自动拆箱), trueSystem.out.println(int1<=int2);// 檢查兩者的值(触发了自动拆箱), trueSystem.out.println(int1!=int2);// 檢查兩者的參考位置(没有触发自动拆箱),true!System.out.println(int1==int2);// 实际为檢查兩者的參考位置,false! 不能认为这是int值类型间的对比,此时还没有发生自动拆箱行为。
和C#,C++的泛型不同,Java的泛型只用在型別檢查,使用的時候還要再做一次轉型和类型检查。泛型信息在编译时会从代码中抹除(只保留作为元数据给反射功能获得),泛型对应的值类型在字节码中为java.lang.Object类型,这是为了降低JVM的修改难度和保证老旧代码的运行兼容。