本文中,我们将讨论几个在JDK1.5中新的语言特征,包括:

泛型(Generics)--为集合(collections)提供编译时类型安全,无需每刻从Collections取得一个对象就进行强制转换(cast)

增强的“for”循环(Enhanced For loop)--减少迭代器(iterator)的潜在错误(error-proneness)

自动置入/自动取出(Autoboxing/unboxing)--无需在基本类型(primitive types)(例如double)和包装类型(wrapper types)(例如Double)之间人工地进行转换。

类型安全的枚举(Typesafeenums)--提供类型安全枚举模式的各项好处。

静态导入(Static import)--无需在使用其他类的静态成员变量前缀其类名.这将使得代码更为简洁。

元数据(Metadata)--使编程人员避免编写样板化代码(boiler plate code),并提供机会进行宣告式程式设计(declarative programming)。

让我们详细讨论每个新特性,并看一些例子。

泛型(Generics)

泛型是JDK1.5中一个最“酷”的特征。通过引入泛型,我们将获得编译时类型的安全和运行时更小地抛出ClassCastExceptions的可 能。在JDK1.5中,你可以声明一个集合将接收/返回的对象的类型。在JDK1.4中,创建雇员名字的清单(List)需要一个集合对象,像下面的语 句:

List listOfEmployeeName = new ArrayList();

在JDK1.5中,你将使用下面语句

List<String> listOfEmployeeName = new ArrayList<String>();

最“酷”的是,如果你试图插入非string类型的值,你将在编译时发现并且修正这类问题。没有泛型,你会发现这样一个bug,当你的客户调用后会告诉你,你所编写的程序抛出ClassCastException异常而崩溃。

另外,当你从集合中得到一个元素时你无需进行强制转换。故原先为:

String employeeName = ((String) listOfEmployee.get(i));

而下面的语句将比上面的更加简单:

String employeeName = listOfEmployee.get(i);

不清楚对象的类型而强制转换对象是不合理的,并且更重要的是,它将在运行时失败。假使用户无意间传入一个包含string buffers类型而非string类型的集合,那结果会怎样呢。在Listing A中,客户被要求传入一个编译器无法强制的strings类型集合。Listing B中显示了同样的方法使用泛型是如何实现的。

Listing A

staticbooleancheckName(Collection employeeNameList, String name) {

for (Iteratori = employeeNamList.iterator(); i.hasNext(); ) {

String s = (String) i.next();

if(s.equals(name)){

return true;

//print employee name here ......

}

}

return false;

}

Listing B

staticbooleancheckName(Collection<String> employeeNameList, String name) {

for (Iteratori = employeeNamList.iterator(); i.hasNext(); ) {

if(i.next().equals(name)){

return true;

//print employee name here ......

}

}

return false;

}

现在,通过方法签名可以清楚知道输入集合必须只能包含strings。如果客户试图传入一个包含string buffers的集合,程序将不会编译。同时注意,该方法不包含任何强制转换。它只需要短短一行,一旦你习惯泛型后,它也更加清晰。

在JDK当前版本下的For循环语法如下:

void printAll(Collection c) {

for (Iteratori = c.iterator(); i.hasNext(); ) {

Employee emp = (Employee)i.next();

System.out.println(emp.getName());

}

}

现在,用增强的For语句实现相同方法:

voidprintAll(Collection c) {

for (Object o : c)

System.out.println((TimerTask)o).getName());

}

在这类For循环中,你应该将":"看成"in",所以,在该例中可以看成"for Object o in c"。你可以发现这种For循环更具可读性。

自动置入/自动取出(Autoboxing/unboxing)

Java有基本数据类型,在这些基本数据类型周围又有包装类。通常,编程人员需要将一种类型转换成另一种。看看Listing C.中的代码片断。

Listing C

public class Employee {

private static final Integer CHILD = new Integer(0);

public static void main(String args[]) {

//code for adding n to an Integer

int n=10;

Integer age= new Integer(30);

Integer ageAfterTenYear= new Integer(age.intValue +10);

}

}

请注意,用于计算ageAfterTenYear的内循环代码看上去是多么杂乱。现在,在Listing D.中看看相同的程序使用autoboxing重写后的样子。

Listing D

public class Employee {

public static void main(String args[]) {

int n=10;

Integer age= new Integer(30);

Integer ageAfterTenYear= age +10;

}

}

有一件事值得注意的:在先前,如果你取出(unbox)Null值,它将变为0。在次代码中,编译器将自动地转换Integer为int然后加上10,接着将其转换回Integer.。

类型安全的枚举(Typesafeenums)

类型安全枚举提供下列特性:

他们提供编译时类型安全。

他们都是对象,因此你不需要将他们放入集合中。

他们作为一种类的实现,因此你可以添加一些方法。

他们为枚举类型提供了合适的命名空间。

他们打印的值具有情报性(informative)― 如果你打印一个整数枚举(intenum),你只是看见一个数字,它可能并不具有情报性。

例一:

enum Season { winter, spring, summer, fall }

例二:

public enum Coin {

penny(1), nickel(5), dime(10), quarter(25);

Coin(int value) { this.value = value; }

private final int value;

public int value() { return value; }

}

静态导入(Static import)

静态导入使代码更易读。通常,你要使用定义在另一个类中的常量(constants),像这样:

importorg.yyy.pkg.Increment;

class Employee {

public Double calculateSalary(Double salary{

return salary + Increment.INCREMENT * salary;

}

}

当时使用静态导入,我们无需为常量名前缀类名就能使用这些常量,像这样:

import static org.yyy.pkg.Increment;

class Employee {

public Double calculateSalary(Double salary{

return salary + INCREMENT * salary;

}

}

注意,我们可以调用INCREMENT这一常量而不要使用类名Increment.。

元数据(Metadata)

元数据特征志于使开发者们借助厂商提供的工具可以进行更简易的开发。看一看Listing E.中的代码。

Listing E

importorg.yyy.hr;

public interface EmployeeI extends Java.rmi.Remote {

public String getName()

throwsJava.rmi.RemoteException;

public String getLocation ()

throwsJava.rmi.RemoteException;

}

public class EmployeeImpl implements EmployeeI {

public String getName(){

}

public String getLocation (){

}

}

通过元数据的支持,你可以改写Listing E中的代码为:

importorg.yyy.hr;

public class Employee {

@Remote public String getName() {

...

}

@Remote public public String getLocation() {

...

}

}

正像你所看到的,所有样板化的代码都不见了。

这些新特性和规格说明将在JDK1.5中实现。它将提供Java编程社区更多的选择以编写鲁棒的、可扩展的代码。认真的Java编程人员将感到着手去熟悉这一Java编程语言的新版本是很有益的。
本文来自:http://www.linuxpk.com/43851.html
 Java2标准版(Java 2 Platform, Standard Edition, J2SE)1.5即将正式推出,这一次的版本更新不同于以往,它带来了很多里程碑式的革新,SUN将其绰号取名为“虎”。这一次的变革将是Java诞生以 来从未有过的,它给我们带来了耳目一新的感觉。下面我们就来欣赏一下其中的部分典型变化:

1.自动包装和解包(Autoboxing and unboxing)

代码示例

往一个ArrayList中加入一个整数,1.5版本以前的版本写法是:

List list = new ArrayList();

list.add( new Integer( 10 ) );

而在1.5版本中可以写为:

list.add( 10 );

因为,在1.5版本中,对一个整数进行包装,使之成为一个Integer对象(即包装,boxing),然后加入到一个ArrayList中的做法被认 为是没有必要的,反之,解包(unboxing)的做法也是没有必要的,这样的代码只是增加了程序的文本长度而已,所以1.5版本支持了自动包装和解包操 作,对于bool/Boolean,byte/Byte,double/Double,short/Short,int/Integer, long/Long,float/Float的相应包装/解包操作都进行了支持,从而使代码变得简单。

2.更优化的循环语句(The inhanced for loop)

代码示例

一个典型的遍历数组的循环语句,1.5版本以前的写法是:

for ( Iterator iterator = list.iterator(); iterator.hasNext(); )

{

Integer n = (Integer)iterator.next();

...

}//for

而在1.5版本中可以写为:

for ( Integer n : list )

{

...

}//for

显然1.5版本的写法比以前是大大简化了,但是在需要修改集合,比如删除其中元素时不能采用这种写法。之所以Java1.5版本没有象C#那样干脆定义 一个foreach关键词,主要是因为SUN认为增加一个专门的关键词成本太高了(too costly)。但1.4版本中就曾经增加了assert关键词,1.5版本中也新增加了enum关键词,因此这一解释恐怕并不那么令人信服。

3.参数可变的方法和printf

代码示例

当不能确定一个方法的入口参数的个数时,以往版本的Java中,通常的做法是将多个参数放在一个数组或者对象集合中作为参数来传递,1.5版本以前的写法是:

int sum(Integer[] numbers)

{

int nSum = 0;

for(int i: numbers)

nSum += i;

return nSum;

}

...

//在别处调用该方法

sum(new Integer[] {12,13,20});

而在1.5版本中可以写为:

int sum(Integer... numbers)

{

int nSum = 0;

for(int i: numbers)

nSum += i;

return nSum;

}

...

//在别处调用该方法

sum(12,13,20);

显然,1.5版本的写法更为简易,也更为直观,尤其是方法的调用语句,不仅简化很多,而且更符合通常的思维方式,更易于理解。

1.5版本自身就有一个应用该特征的典型例子,即C风格的格式化输出方法――printf。

代码示例

输出一个加法算式,1.5版本以前的写法是:

int x = 5;

int y = 7;

int nSum = x + y;

System.out.println(x + " + " + y + " = " + nSum);

而在1.5版本中可以写为:

System.out.printf("%d + %d = %d"n", x, y, nSum);

以上两种写法的输出结构是一样的,即“5 + 7 = 12”。

这种改变不仅仅是形式上的,printf还可以提供更为灵活、强大的输出功能,比如限定按照两位整数的形式输出,可以写为 “System.out.printf("%02d + %02d = %02d"n", x, y, nSum);”,输出结果将是“05 + 07 = 12”。

4.枚举

代码示例

构建一个表示色彩的枚举,并赋值,在1.5版本中可以写为:

public enum MyColor{ Red, Yellow, Blue }

MyColor color = MyColor.Red;

for ( MyColor mycolor : MyColor.values() )

System.out.println( mycolor );

以往的Java版本中没有enum关键词,1.5版本中终于加入了进来,这确实是一个令人高兴的改进。此外,enum还提供了一个名为values() 的静态方法,用以返回枚举的所有值的集合。所以,以上程序的输出结果是把“Red”、“Yellow”、“Blue”分行输出。

而 enum提供的静态方法valueOf()则将以字符串的形式返回某一个具体枚举元素的值,比如“MyColor.valueOf(“Red”)”会返回 “Color.Red”。静态方法name()则返回某一个具体枚举元素的名字,比如“MyColor.Red.name()”会返回“Red”。类似的 方法还有不少。此外,enum自身还可以有构造方法。

5.静态引用

代码示例

当我们要获取一个随即数时,1.5版本以前的写法是:

import java.lang.Math; //程序开头处

...

double x = Math.random();

而在1.5版本中可以写为:

import static java.lang.Math.random; //程序开头处



double x = random();

静态引用使我们可以象调用本地方法一样调用一个引入的方法,当我们需要引入同一个类的多个方法时,只需写为“import static java.lang.Math.*”即可。这样的引用方式对于枚举也同样有效。

6.总结

以上对J2SE1.5的部分新特征做了一些简单的介绍。总而言之,1.5版本的Java确实给我们带来了很多令人激动的变革,如同以上介绍的那样,很多功能以前的版本也能实现,但是不能实现得这样简单、漂亮。相信这次变革会给Java带来更多的追随者。
本文来自:http://www.linuxpk.com/43860.html