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

Java Generic实践中易犯的5个错误

2019年04月11日 ⁄ 综合 ⁄ 共 2139字 ⁄ 字号 评论关闭

Java Generic实践中易犯的5个错误

Java 版本5.0开始添加了Generic支持,用于增强编译时间的类型安全(type safety)。但是出于与之前版本的非Generic JVM字节代码兼容的考虑,Java的Generic代码被编译器处理后,会擦除通用类型信息(该过程叫做Erasure),虽然这样仍然保证源代码级别的类型安全,但是因此也可能让程序员容易犯一些错误(这也是Java被许多人批评的一个原因:-))。下面列出一些常见的错误。

1. 类型T在static成员(包括方法和成员变量)中使用

例如:

 

原因:通用类型T只能在非static方法中使用,不能用于static方法。如果一定要在static方法中用通用类型,可以采用generic method:


注意这里class中的T和static方法中的T不是同一个东西。

2.  类继承通用interface类型的书写错误:

例如:

 

原因: 在类Gen的定义中,T是未知类型, 不能用于Sorter接口的类型。下面是一种正确写法:

 

或者也可以这样:
 

这是T在类Gen是已知类型,可以作为Sorter的类型。

3. 方法定义模糊:

例如:

 

原因: 这里两个方法set的参数T和V可能是同一个类型,在Erasure过程后,两个方法的参数在字节代码中对应都是Object类型。

4.  认为可以调用通用类型的构造方法:

例如:
 

原因: T的类型可能是int,char等primitive类型,也可能是用户定义的Class类型,而运行时间的类型是Object,没有具体的T类型,从而没法构造具体类型的对象。

解决办法是使用Class<T>的实例方法newInstance(), 同时需要处理checked异常:

 

5. 通用类型数组的使用错误情形:

例如下面的代码有两处错误:

 

原因:Gen<Integer>[] gs = new Gen<Integer>[5];  错误是因为Erasure之后gs数组的元素类型都是Gen<Object>,可是Java中的数组都是covariant的(例如可以这样赋值Number[] ns = new Integer[2])。如果用特定类型(如Integer), 会在字节代码中丢失类型信息。可是如果用Gen<?>[] gs = new Gen<?>[5]; 就不会有这个危险,因为它不指定具体类型。同时注意,如果用Gen<? extends Integer>[] gs = new Gen<? extends Integer>[5]; 也会出错。

另外,通用类型数组不能用new, 原因是运行时T的具体类型未知,可以用下面的办法来解决:

 

以上5个常见错误,根本原因是Java Generic本身的实现机制造成的(这与C++ template不一样)。

抱歉!评论已关闭.