泛型的使用

泛型的使用

声明中具有一个或者多个类型参数的类或者接口,就是泛型类或者接口。例如,从Java 1.5发行版本起,List接口就只有单个类型参数E,表示列表的元素类型。从技术的角度来看,这个接口的名称应该是指现在的List<E>(读作“E的列表”),但是人们经常把它简称为List。泛型类和接口统称为泛型。

每种泛型定义一组参数化的类型,构成格式为:先是类或者接口的名称,接着用尖括号(< >)把对应于泛型形式的参数的实际类型参数列表括起来。例如,List<String>("读作字符串列表")是一个参数化的类型,表示元素类型为String的列表。(String是与形式类型参数E相对应的实际类型参数。)

最后一点,每个泛型都定义一个原生态类型,即不带任何实际类型参数的泛型名称。例如,与List<E>相对应的原生态类型List。原生态类型就是像从类型声明中删除了所有泛型信息一样。实际上,原声类型List与Java平台没有泛型之前的接口List完全一样。

如果不提供类型参数,使用集合类型和其他泛型也仍然是合法的,但是不应该这么做。如果使用原生态类型,就失掉了泛型在安全性和表达性方面的所有优势。

泛型出现的时候,Java平台即将进入第二个10年,已经存在大量没有使用泛型的Java代码。所以人们认为让所有的这些代码保持合法,并且能够与新使用泛型的新代码互用。它必须合法,才能将参数化类型的实例传递给那些设计成使用普通类形的方法,反之亦然。这种需求被称为移植兼容性,促成了支持原生态类型的决定。

虽然使用原生态类型是允许的,但是如果使用像List这样的原生态类型,就会失掉类型安全性,但是如果使用像List<Object>这样的参数化类型,则不会。

从Java 1.5发行版本开始,Java提供一种安全的方法,称作无限制的通配符类型。如果要使用泛型,但是不确定或者不关心实际的类型参数,就可以使用一个问号代替。例如,泛型Set<E>的无限制通配符类型Set<?>(读作“某类型的集合”)。这是最普通的参数化Set类型,可以持有任何集合。

在无限制通配符类型Set<?>和原生态类型Set之间有什么区别呢?通配符类型是安全的,原生态类型则不安全。由于可以将任何元素放进使用原生态类型的集合中,因此很容易破坏该集合的约束条件;但不能将任何元素(除了null之外)放到Collection<?>中。如果尝试这样做,将会产生编译错误。

不要在新代码中使用原生态类型,这条规则有两个小小的例外,两者都是源于“泛型信息都可以在运行时被擦除”。在类文字中必须使用原生态类型。规范不允许使用参数化类型。换句话说,List.class,String[].class和int.class都是合法的,但是List<String.class>List<?>.class则不合法。

这条规则的第二个例外与instanceof操作符有关。由于泛型信息可以在运行时被擦除,因此在参数化类型非无限制通配符类型上使用instanceof操作符是非法的。用无限制通配符类型代替原生态类型,对instanceof操作符不会产生任何影响。在这种情况下,尖括号(<>)和问号(?)就显的多余了。下面是利用泛型来使用instanceof操作符的首选方法:

//Legitimate use of raw type - instanceof operator
if(o instanceof Set){
  Set<?> = (Set<?>) o;
  ...
}

注意,一旦确定这个o是个Set,就必须转换成通配符类型Set<?>,而不是转换成原生态类型Set。这是个受检的转换,因此不会导致编译错误。

总之,使用原生态类型会在运行时导致异常,因此不要再新代码中使用。原生态类型只是为了与引用泛型之前遗留代码进行兼容性和互用而提供的。

回顾:

Set<Object>是个参数化类型,表示包含任何对象的一个集合;Set<?>则是一个通配符类型,表示只包含某种未知对象类型的一个集合;Set则是原生态类型,它脱离了泛型系统。前两种是安全的,最后一种不安全。

posted @ 2016-08-23 19:58  Mr-cc  阅读(515)  评论(1编辑  收藏  举报