分享

J2SE(TM)5.0新特性

 ljjzlm 2006-08-01
J2SE(TM)5.0新特性

准备工作

 

如下一些名称,它们指的基本上是同一个东西:

Tiger

Java(TM) 2 Platform Standard Edition 5.0

J2SE(TM) 5.0

Java version 1.5.0

.....

Java下一个版本6.0的代号是"Mustang"野马,再下一个版本7.0的代号是"Dolphin"海豚。

 

概述

 

J2SE(TM) 5.0引入了很多激进的语言元素变化,这些变化或多或少减轻了我们开发人员的一些编码负担,其中的大部分也必然会被应用到即将发布的J2EE(TM) 5.0中。主要的新特性包括:

 

1-      泛型

2-      增强的for循环

3-      自动装箱和自动拆箱

4-      类型安全的枚举

5-      可变长度参数

6-      静态引入

7-      元数据(注解)

8-      C风格的格式化输出

  

泛型

 

泛型这个题目相当大,大到完全可以就这个话题写一本书。 

首先我们来看一个简单的使用泛型类的例子:

 

    ArrayList<Integer> aList = new ArrayList<Integer>();

    aList.add(new Integer(1));

    // ...

    Integer myInteger = aList.get(0);

 

那么泛型是怎样定义的呢?看看下面这一段示例代码:(其中用E代替在实际中将会使用的类名,当然你也可以使用别的名称,习惯上在这里使用大写的E,表示Collection的元素。)

 

    public class TestGenerics<E> {

        Collection<E> col;

        public void doSth(E elem) {

            col.add(elem);

            // ...

        }

    }

 

 泛型方法的定义类似下面的例子:

 

    public static <T extends SomeClass> void add (Collection<T> c, T elem) {

        c.add(elem);

    }

 

其中T代表了我们这个方法期待的那个最终的具体的类,相关的声明必须放在方法签名的紧靠返回类型说明之前。在本例中,它可以是SomeClass或者SomeClass的任何子类,其说明<T entends SomeClass>放在void关键字之前(只能放在这里)。这样我们就可以让编译器确信当我们试图添加一个元素到泛型的ArrayList实例中时,可以保证类型安全。

 

增强的for循环

 

5.0中,我们可以这样写:

 

public void showAll (Collection c) {

    for (Object obj : c) {

        System.out.println((String) obj);

    }

}

 

public void showAll (String[] sa) {

    for (String str : sa) {

        System.out.println(str);

    }

}

 

 

public void showAll (Collection<String> cs) {

    for (String str : cs) {

        System.out.println(str);

    }

} 

 

自动装箱/自动拆箱

 

public static void manualBoxingUnboxing(int i) {

    ArrayList<Integer> aList = new ArrayList<Integer>();

    aList.add(0, new Integer(i));

    int a = aList.get(0).intValue();

    System.out.println("The value of i is " + a);

}

 

public static void autoBoxingUnboxing(int i) {

    ArrayList<Integer> aList = new ArrayList<Integer>();

    aList.add(0, i);

    int a = aList.get(0);

    System.out.println("The value of i is " + a);

}

 

当然,你需要足够重视的是:一方面,对于值类型和引用类型,在资源的占用上有相当大的区别;另一方面,装箱和拆箱会带来额外的开销。在使用这一方便特性的同时,请不要简单的忘记了背后隐藏的这些也许会影响性能的因素。

 

类型安全的枚举

 

借用Java官网上的例子:

 

public enum Operation {

    PLUS   { double eval(double x, double y) { return x + y; } },

    MINUS  { double eval(double x, double y) { return x - y; } },

    TIMES  { double eval(double x, double y) { return x * y; } },

    DIVIDE { double eval(double x, double y) { return x / y; } };

 

    // Do arithmetic op represented by this constant

    abstract double eval(double x, double y);

}

 

我们可以通过下面的代码来试验上面这个枚举类:

 

public static void main(String args[]) {

    double x = Double.parseDouble(args[0]);

    double y = Double.parseDouble(args[1]);

    for (Operation op : Operation.values()) {

        System.out.println(x + " " + op + " " + y + " = " + op.eval(x, y));

    }

}

 

可变长度参数

 

public String testVararg(String... args) {

    StringBuilder sb = new StringBuilder();

    for (String str : args) {

        sb.append(str);

    }

    return sb.toString();

}

 

这样的方法签名跟你写成testVararg(String[] args)的区别在于:在调用时,你不再需要传入一个包装好的String数组,你只需要简单的写一连串String参数,以逗号隔开即可,就如同这个方法正好有一个重载的版本是接受那么多个String参数一样。

 

静态引入

 

所谓静态引入就是指除了引入类之外,我们现在又多了一种选择:引入某个类的静态字段。如:

 import static java.lang.Math.PI;或者import static java.lang.Math.*;

 

这样我们在接下来的代码中,当我们需要使用某个被引入的静态字段时,就不用再写上前面的类名了。当然,出现名字冲突时,跟原来的类引入一样,还是需要前缀以示区分。我个人认为这个新语言元素意义不大。当引入太多静态字段后,代码会变得难以阅读和维护。由于静态字段的名字通常不如类名那么具有描述性,我认为原先在静态字段前写上类名才是更好的选择。不过,毕竟每个人的喜好和需求不同,如果你觉得它对你有用,既然提供了,那么就用咯。

 

元数据(注解)

   

@interface MyAnnotationForMethods {

    int index();

    String info();

    String developer() default "Sean GAO";

}

 

在使用时,我们需要在注解名称前面写上@,然后()中指定参数值,如:

 

@MyAnnotationForMethods (

        index = 1,

        info = "This is a method to test MyAnnotation.",

        developer = "Somebody else"

)

public void testMethod1() {

    // ...

}

 

注解的最大作用在于它在源代码的基础上增加了有用的信息,使得源代码的描述性更强。这些信息可以被代码之外的工具识别,从而可以很方便的增加外部功能,以及减少不必要的相关代码/文件维护。这里我想简单提一个超出J2SE(TM) 5.0范畴的话题:在未来的EJB 3.0规范中会有相当多的对注解的应用,让我们预览一下将来的无状态会话bean用注解来定义会是什么样子:

 

@Stateless public class BookShelfManagerBean {

    public void addBook(Book aBook) {

        // business logic goes here...

    }

    public Collection getAllBooks() {

        // business logic goes here...

    }

    // ...

}

 

我们甚至不用写任何接口和部署描述符,这些工作将完全由外部工具通过读取注解加上反射来完成,这不是很好吗?

 

 

C风格格式化输出

 

Java总算也有类似Cprintf()风格的方法了,方法名同样叫作printf(),这一特性依赖于前边提到的可变长度参数。举个例子来说,我们现在可以写:

 

System.out.printf("%s has a value of %d.%n", someString, a);

 

怎么样,看上去还不错吧?需要注意的是Java为了支持多平台,新增了%n标示符,作为对\n的补充。有关Java格式化输出的具体语法,请参考java.util.FormatterAPI文档。

 

结语

 

其实不只是语言元素,J2SE(TM) 5.0的发布在其他很多方面都作了不小的改进,包括虚拟机、新的API类库等等,性能和功能上都有大幅提升。

 

对于主要靠J2EE吃饭的朋友来讲,也许真正意义上要在工作中充分利用这些新的元素,恐怕要等主流的J2EE服务器都支持J2EE(TM) 5.0的那一天了,对此我充满期待。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多