Java 5.0
此条目需要扩充。 (2010年9月27日) |
Java从5.0版本开始,加入许多新特性,是Java历史中修改最大的版本,许多特点模仿自C#,因而被认为是为了与C#对抗。
新的特性[1]
自动装箱/拆箱(Auto-Boxing/Unboxing)
将Java中8个基本类型实现自动对象化和值化转换,通过编译器自动完成相关转换代码的生成。
没有自动装箱/拆箱:
int int1 = 1;
Integer integer2 = new Integer(int1);
int int3 = integer2.intValue();
有自动装箱/拆箱:
int int1 = 1;
Integer integer2 = int1; // 自動裝箱
int int3 = integer2; // 自動拆箱
实际上将相关字节码反编译后,会还原出其隐式调用的转换方法:
int int1 = 1;
Integer integer2 = Integer.valueOf(int1); // 自動裝箱的本质,通过调用valueOf将值对象化
int int3 = integer2.intValue(); // 自動拆箱的本质,通过调用xxxValue将对象值化
自动装箱的新功能,可能是从C#语言身上学习来的,Java已经越来越像C#。然而Java对自动装箱/拆箱的支援,仅是利用编译器实现,在Java Bytecode中,并无自动装箱/拆箱的操作码(opcode)。
泛型(Generic Types)
泛型就像是C++的模板。原有的Collection API加上泛型支援后,增加对型别的检查,减少程式错误的机会。
没有泛型:
HashMap hm = new HashMap();
int i=1;
String tt="test";
hm.put(new Integer(i), tt);
使用Generic:
HashMap <Integer, String>hm = new HashMap<Integer, String>();
int i=1;
String tt = "test";
hm.put(i, tt); // 在這裏對int自動裝箱成Integer,也使用了參數的型別檢查
注解(Annotation)
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
**/
void gimmeSomeLoving() {
throw new Exception("not implemented");
}
// JDK 1.5
@todo
void gimmeSomeLoving() {
throw new Exception("not implemented");
}
枚举类型(enum)
枚举类型也是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.4
class JavaTech {
public static final int J2ME = 1;
public static final int J2SE = 2;
public static final int J2EE = 3;
}
// JDK 1.5
public enum NewJavaTech {
J2ME, J2SE, J2EE
}
国际化
Java语言严格区分字节和字符。字符的存储格式为UCS-2,也就是只能使用位于基本多文种平面的字元,从Java 5开始支持UTF-16字符。
另外,从5.0开始Java的程式也开始可以使用Unicode字元进行命名。
下面就是一个合法的Java程式,里面包含了中文字符作为字串的名称,这个程式可以在编译器中通过编译。
public class HelloWorld {
private String文本 = "HelloWorld";
}
输入输出
在jdk1.5及其以后版本中,java.util.Scanner
和java.util.Formatter
类别被应用到输入输出中。另外,也出现了类似C语言的printf()
函式。
foreach回圈
foreach回圈,有时又称forin回圈,在许多程式语言(包括C#、Ruby、JavaScript)中都有出现,可以直接将一个Array或Map展开,而不必由程式设计师自行检查边界,可以有效减少错误的机会。
int[] array1 = {1, 3, 5};
for(int i : array1){ // foreach迴圈
System.out.println("Number: "+i);
}
可变长度的引数
长久以来一直有使用者要求加入printf()
函式,受限于Java函式必须要有固定引数的限制,始终无法实现,在加入这个功能之后,连带printf()
也变为可能。
static引入
这个特性允许程式设计师将一个类别中的静态内容引入到程式中。
static import java.lang.System.*;
public class HelloWorld {
public static void main(String args[]){
out.println("Hello World.");
}
}
批评
Java 5.0虽然加入许多的新特性,但为了与旧版本相容,JVM并没有随之改变,而仅只是从编译器动手脚,因而引发许多问题。讨论Java语言问题的专书《Java Puzzle》就有专门的篇幅讨论5.0之后造成的问题。
自动装箱/拆箱的矛盾
自动装箱这功能也造成了一些矛盾,例如:
Integer int1 = new Integer(1);
Integer int2 = new Integer(1);
System.out.println(int1 >= int2); // 檢查兩者的值(触发了自动拆箱), true
System.out.println(int1 <= int2); // 檢查兩者的值(触发了自动拆箱), true
System.out.println(int1 != int2); // 檢查兩者的參考位置(没有触发自动拆箱),true!
System.out.println(int1 == int2); // 实际为檢查兩者的參考位置,false! 不能认为这是int值类型间的对比,此时还没有发生自动拆箱行为。
泛型擦除
和C#,C++的泛型不同,Java的泛型只用在型别检查,使用的时候还要再做一次转型和类型检查。泛型信息在编译时会从代码中抹除(只保留作为元数据给反射功能获得),泛型对应的值类型在字节码中为java.lang.Object类型,这是为了降低JVM的修改难度和保证老旧代码的运行兼容。
注释
- ^ New Features and Enhancements J2SE 5.0. [2013-05-14]. (原始内容存档于2021-01-26).