Java 5.0新特性研究(一)
DreamHead计划使用"Java 5.0 Tiger"来开发我们的Dominoo,理由是:2-3年后"Tiger" will be mature。
我们对刚刚发布不久的"Tiger"了解的不多,晚上我们几个group member坐了下来,听DreamHead讲解"Tiger"的新特性。回到寝室自己做了些实验,有了些体会。
通过对"Tiger"的讨论和研究,得知Sun推出"Tiger"目的就是为了简化Java程序员的开发工作。在下面的详细解释及代码例子中你会深刻的体会到这一点。
1、Auto-boxing and auto-unboxing conversion
Problem:
─ Conversion between primitive types and wrapper objects (and vice-versa)
─ Needed when adding primitives to a collection
Java 5.0给我们的解决方案就是:Let the compiler(Javac) do it。事实上javac真的是这么做的么,耳听为虚,眼见为实,看代码吧!
我使用IntelliJ-Idea4.5.2写的代码(现在IntelliJ4.5已经可以支持jdk5.0的语法了,今早看了一下Eclipse的网站,Eclipse要到3.1才支持jdk5.0新加入的特性)[注]:在IntelliJ4.5中"File"—〉"Setting"—〉左下角"Classic View"最下面的"Language level for project"选择5.0即可。
/*
* test auto-boxing and auto-unboxing
*/
//old 1.4 style
Integer intObj1 = new Integer(22);
int i = intObj1.intValue();
System.out.println(i); //output: 22
//new 1.5 style
Integer intObj2 = 23; //auto-boxing
int j = intObj2; //auto-unboxing
System.out.println(j); //output: 23
//old 1.4 style
ArrayList al1 = new ArrayList();
al1.add(new Integer(24)); //or al1.add(Integer.valueOf(24))
//new 1.5 style
ArrayList al2 = new ArrayList();
al2.add(24); // auto-boxing conversion
编译为.class模块后,我们使用DJ Java Decompiler重新反编译得到以下代码(只写出对应上面代码的):
Integer intObj1 = new Integer(22);
int i = intObj1.intValue();
System.out.println(i);
Integer intObj2 = Integer.valueOf(23);
int j = intObj2.intValue();
System.out.println(j);
ArrayList al1 = new ArrayList();
al1.add(new Integer(24));
ArrayList al2 = new ArrayList();
al2.add(Integer.valueOf(24));
从上面代码中我们也可以看出,javac的确帮了我们的忙,它把繁重的活都揽去了,给我们留下了清闲,哦,忘说了,俺也是懒人^_^。
2、Generics in java
Problem: Collection element types
– Can not be checked at compile time
– Assignment must use cast
– Can cause runtime exception or errors(ClassCastException)
解决方案:
–Tell the compiler what type your collection is
– Compiler can fill in casts for you
还是那个原则,告诉编译器你的collection中需要什么类型,编译器为你完成一切(类型检查,转型等)。看代码:
ArrayList strArrayList = new ArrayList();
strArrayList.add("Hello");
System.out.println(strArrayList.iterator().next()); //output:Hello
System.out.println(strArrayList.getClass()); //output:class java.util.ArrayList
反编译后代码:
ArrayList strArrayList = new ArrayList();
strArrayList.add("Hello");
System.out.println((String)strArrayList.iterator().next());
System.out.println(strArrayList.getClass());
实际上包括转型等都是javac帮我们做了。 从上面的代码中我们还能看出问题:看紫色标记的代码,我们打印strArrayList的类型,该变量在声明的时候是ArrayList类型的,我们的头脑里会认为打印出的应该是"class java.util.ArrayList",可实际打印出的信息告诉我们collection中的元素的类型信息被丢弃了。也就是说ArrayList和ArrayList本不该是同一类型,不过我们看到的实际情况却是他们是同一类型。由于java中的generic只是在compiler一级得到支持,在jvm一级是不知道有generic这回事的,也许sun可能在不久的将来修正这一缺陷,别忘了java的强大的竞争对手C# 在2.0中已经在vm中加入对generic的支持。
这里要提一下DreamHead对java模板的理解,挺逗的,蛮有启发性。DreamHead用 "剧本 电影版本"来理解java generic:
射雕剧本 83版射雕 = new 射雕剧本();
射雕剧本 03版射雕 = new 射雕剧本();
Java generic与其他预言generic的简单比较,Java在compiler一级加入generic,导致的后果就是丢掉了类型信息,我们知道C++模板是不会丢掉类型信息的,但是会使可执行文件大小发生膨胀。C#2.0由于有VM的支持,所以既拥有类型信息,又不会使可执行文件的体积膨胀,但是总体来言,C++的generic最强大,也最成熟,当然和它支持的比较早也不无关系。
[注] 在《Adding Generics to the Java Programming Language:Participant Draft Specification》一文中关于上述问题有以下说明:
A parameterized class or interface declaration defines a set of types, one for each possible instantiation of the type parameter section. All parameterized types share the same class or interface at runtime.
For instance, the code:
Vector x = new Vector();
Vector y = new Vector();
return x.getClass() == y.getClass();
will yield true.
3、Enhanced for loop(foreach)
C#早已引入foreach这个关键字,C++也提供foreach算法(如果要弄懂这个需要学习的东西就比较多了^_^),java从jdk5.0开始引入这种高级for-loop机制,不过java的设计者还是很聪明的,java并没有引入新的关键字,因为要是这样做的话,需要进行的改动工作就太多了。Java利用原有的for关键字和一个":"就把这个完成了,不过java引入这一机制也只是方便程序员开发,这一机制也都是由javac来支持的,jvm一级并不知道foreach这一机制的存在。我们看看代码吧!
Vector strVec = new Vector();
strVec.add("Hello");
strVec.add("Tiger");
strVec.add("!");
//old 1.4 style – dynamic container
for (Iterator i = strVec.iterator(); i.hasNext(); ){
System.out.println(i.next());
}
//new 1.5 style – dynamic container
for ( String str1 : strVec ){
System.out.println(str1);
}
String [] strArray = {
"Java 2",
"Platform",
"Standard",
"Edition",
"1.5"};
//old 1.4 style – static container
for(int i = 0 ; i < strArray.length ; ++i){
System.out.println(strArray[i]);
}
//new 1.5 style – static container
for(String str2 : strArray){
System.out.println(str2);
}
我们还是来看看反编译后的代码:
for(Iterator iterator1 = vector.iterator(); iterator1.hasNext(); System.out.println(s))
s = (String)iterator1.next();
String args2[] = args1;
int j = args2.length;
for(int k = 0; k < j; k++)
{
String s1 = args2[k];
System.out.println(s1);
}
注:上面对应颜色的代码相对应。
可以看出javac又在帮我们的忙。紫色部分我们看到仅用3行代码就搞定,而编译器得辛苦生成那么多代码。
4、Type safe Enumerations
Java不支持enum是java程序员抱怨较多的,这次sun终于在java5.0中加入了对enum的支持,不过还是如上面几个new features一样,只是在java compiler一级支持。
我们看看enum类型被javac转换成什么了?
//Color.java
public enum Color {
RED,
GREEN,
BLUE
};
上面是一个很简单的enum声明,下面是反编译器输出的代码:
public final class Color extends Enum
{
public static final Color[] values()
{
return (Color[])$VALUES.clone();
}
public static Color valueOf(String s)
{
Color acolor[] = $VALUES;
int i = acolor.length;
for(int j = 0; j < i; j++)
{
Color color = acolor[j];
if(color.name().equals(s))
return color;
}
throw new IllegalArgumentException(s);
}
private Color(String s, int i)
{
super(s, i);
}
public static final Color RED;
public static final Color GREEN;
public static final Color BLUE;
private static final Color $VALUES[];
static
{
RED = new Color("RED", 0);
GREEN = new Color("GREEN", 1);
BLUE = new Color("BLUE", 2);
$VALUES = (new Color[] {
RED, GREEN, BLUE
});
}
}
在sun公司的一份培训材料中写到:
Problem:
—-Variable needs to hold limited set of values e.g. card suit can only be spade, diamond, club, heart
Solution:
—New type of class declaration Enum type has public, self-typed members for each enum constant
—New keyword, enum Works with switch statement
下面我们根据上面的叙述来使用一下enum:
public class TestEnum{
public enum Color {
RED,
GREEN,
BLUE
};
public static void main(String[] args) {
for (Color clr : Color.values() ){
System.out.println(clr);
/*output:
RED
GREEN
BLUE
*/
}
}
}
反编译后我们会看到如下的代码:
public static void main(String args[])
{
Color acolor[] = Color.values();
int i = acolor.length;
for(int j = 0; j < i; j++)
{
Color color = acolor[j];
System.out.println(color);
}
}
通过这两个例子也可以看出enum不过是从Enum继承下来的类罢了,只是javac将相关的变换细节隐藏了。不过却给我们带来了极大的便利。
5、Varargs
Problem:
— To have a method that takes a variable number of parameters
— Can be done with an array, but not nice
— Look at java.text.MessageFormat
Solution: Let the compiler do it for you
— New syntax:
— public static String format (String fmt , Object… args);
— Java. gets printf !
例子:
public static void myPrintf(Object… args){
for(Object obj : args){
System.out.println(obj);
}
}
public static void main(String[] args) {
int i = 6;
myPrintf("Hello" , "Tiger" , "Java 5.0");
myPrintf("Harbin" ,"Beijing","Shenyang" ,"Changchun");
myPrintf("The number is :" , i);
}
我们看一下反编译器输出的代码:
public static transient void myPrintf(Object aobj[])
{
Object aobj1[] = aobj;
int i = aobj1.length;
for(int j = 0; j < i; j++)
{
Object obj = aobj1[j];
System.out.println(obj);
}
}
byte byte0 = 6;
myPrintf(new Object[] {
"Hello", "Tiger", "Java 5.0"
});
myPrintf(new Object[] {
"Harbin", "Beijing", "Shenyang", "Changchun"
});
myPrintf(new Object[] {
"The number is :", Integer.valueOf(byte0)
});
从反编译的代码可以看出javac内部使用了数组来完成对变参数的支持。
6、Static imports
Problem:
—Having to fully qualify every static referenced from external classes
Solution: New import syntax
—import static TypeName.Identifier;
—import static Typename.*;
—Also works for static methods and enums e.g Math.sin(x) becomes sin(x)
上面是引用sun那个ppt中的一些东东,这个我就不想详细写了,今天较累,看看电影轻松一下吧!
Java5.0第一部分就写到这。
评论