Java泛型简明介绍

 Java知识

一、Java泛型由来的动机

  理解Java泛型最简单的方法是把它看成一种便捷语法,能节省你某些Java类型转换(casting)上的操作:

  List box = ...;

  Apple apple = box.get(0);

  上面的代码自身已表达的很清楚:box是一个装有Apple对象的List。get方法返回一个Apple对象实例,这个过程不需要进行类型转换。没有泛型,上面的代码需要写成这样:

  List box = ...;

  Apple apple = (Apple) box.get(0);

  很明显,泛型的主要好处就是让编译器保留参数的类型信息,执行类型检查,执行类型转换操作:编译器保证了这些类型转换的绝对无误。

  相对于依赖程序员来记住对象类型、执行类型转换导致的程序运行时失败,难以调试和解决,而编译器能够帮助程序员在编译时强制进行大量的类型检查,发现其中的错误。

  二、泛型的构成

  由泛型的构成引出了一个类型变量的概念。根据Java语言规范,类型变量是一种没有限制的标志符,产生于以下几种情况:

  1.泛型类声明

  2.泛型接口声明

  3.泛型方法声明

  4.泛型构造器(constructor)声明

  三、泛型类和接口

  如果一个类或接口上有一个或多个类型变量,那它就是泛型。类型变量由尖括号界定,放在类或接口名的后面:

  public interface List extends Collection {

  ...

  }

  简单的说,类型变量扮演的角色就如同一个参数,它提供给编译器用来类型检查的信息。

  Java类库里的很多类,例如整个Collection框架都做了泛型化的修改。我们在上面的第一段代码里用到的List接口就是一个泛型类。在那段代码里,box是一个List对象,它是一个带有一个Apple类型变量的List接口的类实现的实例。编译器使用这个类型变量参数在get方法被调用、返回一个Apple对象时自动对其进行类型转换。

  实际上,这新出现的泛型标记,或者说这个List接口里的get方法是这样的:

  T get(int index);

  get方法实际返回的是一个类型为T的对象,T是在List声明中的类型变量。

  四、泛型方法和构造器

  如果方法和构造器上声明了一个或多个类型变量,它们也可以泛型化。

  public static T getFirst(List list)

  这个方法将会接受一个List类型的参数,返回一个T类型的对象。

  五、使用foreach

  “for each”语法同样受益于泛型。前面的代码可以写出这样:

  for (String s: str) {

  System.out.print(s);

  }

  六、通配符

  在本文的前面的部分里已经说过了泛型类型的子类型的不相关性。但有些时候,我们希望能够像使用普通类型那样使用泛型类型:

  1、向上造型一个泛型对象的引用

  例如,假设我们有很多箱子,每个箱子里都装有不同的水果,我们需要找到一种方法能够通用的处理任何一箱水果。更通俗的说法,A是B的子类型,我们需要找到一种方法能够将C类型的实例赋给一个C类型的声明。

  为了完成这种操作,我们需要使用带有通配符的扩展声明,就像下面的例子里那样:

  List apples = new ArrayList();

  List<? extends Rruit> fruits = apples;

  “? extends”是泛型类型的子类型相关性成为现实:Apple是Fruit的子类型,List 是 List 的子类型。

  2、向下造型一个泛型对象的引用

  另外一种通配符:? super。如果类型B是类型A的超类型(父类型),那么C 是 C 的子类型:

  List fruits = new ArrayList();

  List = fruits;

  七、? super

  使用 ? super 通配符一般是什么情况?让我们先看看这个:

  List fruits = new ArrayList();

  List = fruits;

  我们看到fruits指向的是一个装有Apple的某种超类(supertype)的List。同样的,我们不知道究竟是什么超类,但我们知道Apple和任何Apple的子类都跟它的类型兼容。既然这个未知的类型即是Apple,也是GreenApple的超类,我们就可以写入:

  fruits.add(new Apple());

  fruits.add(new GreenApple());

  八、存取原则和PECS法则

  总结 ? extends 和 the ? super 通配符的特征,我们可以得出以下结论:

  如果你想从一个数据类型里获取数据,使用 ? extends 通配符

  如果你想把对象写入一个数据结构里,使用 ? super 通配符

posted @ 2017-03-06 15:27  风也不知道往哪吹  阅读(141)  评论(0编辑  收藏  举报