现在的位置: 首页 > 综合 > 正文

《Java Generics and Collections》读书笔记一:java泛型基本问题

2013年03月22日 ⁄ 综合 ⁄ 共 1673字 ⁄ 字号 评论关闭

参考资料: 《Java Generics and Collections》

1. Java的泛型实现采用"擦除法".
编译器为我们完成类型擦除和必要的类型转换, 在运行时,每个泛型类只有一种类型. 具体地说, List<Integer>, List<String> 和 List<List<String>> 在运行时都将具有相同的类型: List

2. Boxing and Unboxing 自动装箱 和 自动拆箱
特别注意在 == 比较时, 自动装箱和自动拆箱所造成的影响, 如下面代码:

public static int sum(List<Integer> ints) {
  
int s = 0;
  
for (int n : ints) { s += n; }
  
return s;
}

public static Integer sumInteger(List<Integer> ints) {
  Integer s 
= 0;
  
for (Integer n : ints) { s += n; }
  
return s;
}

上面两个方法实现相同的功能, 前者采用Java 5的新特性, 相比下效率会比后者快大概一倍.

List<Integer> bigs = Arrays.asList(100,200,300);
assert sumInteger(bigs) == sum(bigs);  // 应用自动拆箱, 比较两个int, 结果为true
assert sumInteger(bigs) != sumInteger(bigs);  // 比较Integer对象, 结果为false

上面代码还比较好理解, Java在实现装箱时采用了缓存机制, 缓存-128 ~ 127之间的整数, '/u0000' ~ '/u007f'之间的char类型, byte类型, 以及boolean可以提高效率. 对其它范围的数据, Java标准也允许对其进行缓存, 所以上面的第二个断言有可能会失败.

List<Integer> smalls = Arrays.asList(1,2,3);
assert sumInteger(smalls) == sum(smalls);  // 比较int, 结果肯定为true
assert sumInteger(smalls) == sumInteger(smalls);  // 由于缓存, 两个Integer其实是同一个对象, 所以结果也为true

结论: 不要依赖于自动装箱和自动拆箱的缓存机制, 对于对象的比较, 任何时候都应该使用equals方法而不是==.

3. 泛型方法和可变参数方法(Varargs)

class Lists {
  
public static <T> List<T> toList(T... arr) {
    List
<T> list = new ArrayList<T>();
    
for (T elt : arr) list.add(elt);
    
return list;
  }
}

上面是使用泛型和可变参数的一个简单例子, 调用该方法时, 我们可以传入连续的几个参数, 也可以传入一个参数的数组. 其实可变参数方法唯一的好处就是方便, 它让我们不用自己把实参打包到一个数组中. Java编译器为我们完成这一工作, 实际上, 在运行时, 上面方法其实就是使用参数的数组来实现.

调用泛型方法时, 如果参数类型不明确, 我们就需要明确地指出类型信息, 否则就会引起"未检查的警告消息", 使用如下的格式:

List<Integer> ints = Lists.<Integer>toList();
List
<Object> objs = Lists.<Object>toList(1"two");

另外, Java的语法要求: 在使用明确的类型调用方法时, 必需使用带有 "." 的格式. 以上面Lists类为例, 即使是在Lists类内部的方法中, 也不可以使用 List<Integer> ints = <Integer>toList(); 而必需使用 List<Integer> ints = Lists.<Integer>toList();
 

抱歉!评论已关闭.