JDK5.0新特性
来源:互联网 发布:输出变压器数据 编辑:程序博客网 时间:2024/05/13 18:57
jdk5.0重要的语言变化:泛型(Generics)、循环增强(Enhanced for Loop)、自动封箱(Autoboxing)和解箱(Unboxing)、类型安全的枚举(Typesafe Enums)、可变参数(Varargs)、静态导入(Static Import)、注解(Annotations)。
1. 泛型(Generics)
没有使用泛型的问题:
(1)从集合中获得元素时,必须进行类型转换,这个类型转换过程比较麻烦。
(2)类型转换是不安全的,可能在运行时发生类型转换失败。
鉴于以上问题,如果能够告诉编译器集合中的类型,让编译器加入类型转换功能,编译器会保证类型转换的成功。这里值得注意的是:泛型是提供给Javac编译器使用的。编译器在编译带泛型的集合时会去掉“类型”信息,使程序运行效率不受影响,也就是说编译生成的字节码不会带有泛型的类型信息。
未使用泛型的例子:
// Removes 4-letter words from c; elements must be stringsstatic void expurgate(Collection c) { for (Iterator i = c.iterator(); i.hasNext();) { String s = (String) i.next(); if (s.length() == 4) { i.remove(); } }}使用泛型的例子:
// Removes 4-letter words from cstatic void expurgate(Collection<String> c) { for (Iterator<String> i = c.iterator(); i.hasNext();) { if (i.next().length() == 4) { i.remove(); } }}使用泛型后好处:
(1)更加清晰和安全。
(2)没有类型转换、额外的括号和临时变量。
(3)提供编译时的类型检查和消除类型转换。
2. 循环增强(Enhanced for Loop)
没有使用循环增强的问题:(1)遍历集合比较麻烦。
(2)Iterator通常只有在获取元素时才会用到。
(3)使用Iterator容易产生错误:Iterator变量在循环中会出现3次、通常的拷贝粘贴错误。
鉴于以上问题:如果能让编译器来处理Iterator,隐藏Iterator背后的细节。
一般访问集合的例子:
void cancelAll(Collection c) { for (Iterator i = c.iterator(); i.hasNext();) { TimerTask tt = (TimerTask) i.next(); tt.cancel(); }}使用循环增强的例子:
void cancelAll(Collection c) { for (Object o : c) { ((TimerTask) o).cancel(); }}结合泛型的例子:
void cancelAll(Collection<TimerTask> c) { for (TimerTask task : c) { task.cancel(); }}对数组使用循环增强:
//Returns the sum of the elements of aint sum(int[] a) { int result = 0; for (int i : a) { result += i; } return result;}使用循环增强后的好处:
(1)代码更加简洁、清晰和安全。
(2)和Iterator无关,不可能使用错误的Iterator。
(3)消除使用数组索引的错误。
(4)代码准确表达它所要做的。
3. 自动封箱(Autoboxing)和解箱(Unboxing)
没有使用Autoboxing/Unboxing的问题:(1)不能将int放入集合,必须使用Integer。
(2)在获取时转换回来比较麻烦。
鉴于以上问题:如果能够让编译器做这些事不是更好?
一般的方法:
public class Freq { private static final Integer ONE = new Integer(1); public static void main(String[] args) { // Maps word (String) to frequency (Integer) Map m = new TreeMap(); for (int i = 0; i < args.length; i++) { Integer freq = (Integer) m.get(args[i]); m.put(args[i], (freq == null ? ONE : new Integer( freq.intValue() + 1))); } System.out.println(m); }}结合自动封箱、泛型和增强循环的例子:
public class Freq { public static void main(String[] args) { Map<String, Integer> m = new TreeMap<String, Integer>(); for (String word : args) { Integer freq = m.get(word); m.put(word, (freq == null ? 1 : freq + 1)); } System.out.println(m); }}使用Autoboxing/Unboxing的好处:
(1)Autoboxing:需要一种类型的对象时,这种基本类型就自动地封装到与它相同类型的包装中。
(2)Unboxing:需要一个值时,被装箱对象中的值就被自动地提取出来,不需要调用intValue()和doubleValue()等方法。
4. 类型安全的枚举(Typesafe Enums)
在之前的版本中,表示int枚举类型的标准方式:// int Enum Pattern - has severe problems!public static final int SEASON_WINTER = 0;public static final int SEASON_SPRING = 1;public static final int SEASON_SUMMER = 2;public static final int SEASON_FALL = 3;这样的方式存在的问题:
(1)不是类型安全的,你必须确保它是int。
(2)没有命名空间,没有常量字符串前缀来避免与其他int枚举类型冲突。
(3)脆弱性:常量被编译到客户程序中,如果常量改变,客户必须重新编译。
(4)打印出的值不提供详细信息,打印出来的值都是一个数字。
安全类型的Enum模式的例子:
import java.io.Serializable;import java.util.Arrays;import java.util.Collections;import java.util.List;public final class Season implements Comparable, Serializable { private final String name; public String toString() { return name; } private Season(String name) { this.name = name; } public static final Season WINTER = new Season("winter"); public static final Season SPRING = new Season("spring"); public static final Season SUMMER = new Season("summer"); public static final Season FALL = new Season("fall"); private static int nextOrdinal = 0; private final int ordinal = nextOrdinal++; public int compareTo(Object o) { return ordinal - ((Season) o).ordinal; } private static final Season[] PRIVATE_VALUES = { WINTER, SPRING, SUMMER, FALL }; public static final List VALUES = Collections.unmodifiableList(Arrays.asList(PRIVATE_VALUES)); private Object readResolve() { // Canonicalize return PRIVATE_VALUES[ordinal]; }}以上方法的基本想法是:使用导出自定义类型的常量,不提供public构造方法,这样可以修正前面所有的缺点,还能够添加任意的方法、域变量,能够实现接口。缺点是代码冗余过长,容易出现错误:每个常量出现3次,不能在switch语句中使用。
鉴于以上问题:这些事情由编译器来处理。
安全类型的Enum结构:
(1)编译器支持安全类型的Enum模式.
(2)类似典型的Enum --> enum Season { WINTER, SPRING, SUMMER, FALL }
(3)能够在switch语句中使用。
(4)安全类型的Enum模式的所有优点。
结合泛型和增强循环的Enum例子:
import java.util.*;public class Card { public enum Rank { DEUCE, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, JACK, QUEEN, KING, ACE } public enum Suit { CLUBS, DIAMONDS, HEARTS, SPADES } private final Rank rank; private final Suit suit; private Card(Rank rank, Suit suit) { this.rank = rank; this.suit = suit; } public Rank rank() { return rank; } public Suit suit() { return suit; } public String toString() { return rank + " of " + suit; } private static final List<Card> protoDeck = new ArrayList<Card>(); // Initialize prototype deck static { for (Suit suit : Suit.values()) for (Rank rank : Rank.values()) protoDeck.add(new Card(rank, suit)); } public static ArrayList<Card> newDeck() { return new ArrayList<Card>(protoDeck); // Return copy of prototype deck }}
5. 可变参数(Varargs)
在之前的版本中,编写具有任意数量的参数的方法,必须使用数组:Object[] arguments = { new Integer(7), new Date(), "a disturbance in the Force"};String result = MessageFormat.format("At {1,time} on {1,date}, there was {2} on planet {0,number,integer}.", arguments);创建和初始化数组是件麻烦的事情,鉴于以上问题:如果由编译器来实现不是更好?
使用可变参数(Varargs)的例子:
public static String format(String pattern, Object... arguments);String result = MessageFormat.format("At {1,time} on {1,date}, there was {2} on planet {0,number,integer}.", 7, new Date(), "a disturbance in the Force");
6. 静态导入(Static Import)
在之前版本中,为了访问静态成员,必须导入来自的类的引用。例如:double r = Math.cos(Math.PI * theta);现在你只需在静态导入,然后就可以直接在代码中使用静态方法和静态字段,例如:import static java.lang.Math.PI; 或者 import static java.lang.Math.*;就可以使用它们了:
double r = cos(PI * theta);
7. 注解(Annotations)
注解(Annotations),也叫元数据。代码级别的说明。与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。使用自定义的注解类型:
/** * Describes the Request-For-Enhancement(RFE) that led * to the presence of the annotated API element. */@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.METHOD)@Inherited@Documentedpublic @interface RequestForEnhancement { int id(); String synopsis(); String engineer() default "[unassigned]"; String date() default "[unimplemented]"; }一旦定义了注解类型,就可以使用该注解了。我们可以看到这个注解类型本身也被注解了,这种注解叫做元注释。
@Retention(RetentionPolicy.RUNTIME)表示这种类型的注解被JVM保留从而使其能够通过反射在运行时读取。
@Target(ElementType.METHOD)表示这种注解只能用来注解在方法上。
@Inherited表示该注解可以被子类继承,默认不可继承。
@Documented表示javadoc自动生成文档时,也包含该注解,默认不包含。
按照惯例,注解应该写在其他修饰符的前面,例如:
@RequestForEnhancement(id = 2868724, synopsis = "Enable time-travel", engineer = "Mr. Peabody", date = "4/1/3007")public static void travelThroughTime(Date destination) { //... }
0 0
- jdk5.0新特性
- jdk5.0新特性
- JDK5.0新特性
- JDK5.0新特性:
- jdk5.0新特性
- JDK5.0 新特性
- jdk5.0新特性
- jdk5.0新特性
- JDK5.0新特性
- JDK5.0 新特性
- jdk5.0新特性
- JDK5.0新特性
- JDK5.0新特性
- JDK5.0新特性
- Jdk5.0新特性
- jdk5.0新特性
- jdk5.0新特性
- JDK5.0新特性
- migrate android code解决办法
- cortex_m3_stm32嵌入式学习笔记(四):外部中断实验
- 关于批处理中的变量
- Good Bye 2014 B. New Year Permutation
- 十分钟接入WO+能力共享平台
- JDK5.0新特性
- 小忆“MVC”
- select * from (select * from tablename) 不可以 问题解决
- Android中的Fragment使用详解之生命周期
- Basic shell scripting questions
- 05-2
- 图解classloader加载class的流程及自定义ClassLoader
- poj 3254 Corn Fields
- C#深入学习:泛型修饰符in,out、逆变委托类型和协变委托类型