面向对象的一个重要目标就是对代码的重用,支持这个目标的重要机制就是泛型;
1:使用接口类型表示泛型
例如 考虑由一些项组成的数组中找出最大项的问题,基本的代码是与类型无关的,但是它必须有一种能力来比较任意两个对象的大小,并且确定哪一个是大的,哪一个是小的,因此我们不能直接找出Object数组中的最大元,我们需要更多的信息,最简单的就是比较Comparable的数组中的最大元,我们可以使用CompareTo来确定顺序,它对于所有实现Comparable接口的类都是可用的,但是这样并不是总会行的通的,因为有些类库中的类 去实现接口是不可能的,例如一个类可能是库中的类,但是接口却是用户自定义的接口,并且一个类如果是一个final类,那么我们是不可能扩展它来创建一个新的类,所以这种方式的局限性太大,
2:数组类型的兼容性
语言设计中的困难之一就是如何处理集合类型的继承关系,假设Employee iS-A Person ,那么这是不是也就意味着 Employee [] IS-A Person[] 呢?换句话说,如果一个例程可以允许 Person[] 作为参数传递,那么 Employee[] 可不可以当做参数传入例程呢?
乍一看,这应该不是一个问题,似乎Employee[] 和 Person[] 就应该是兼容的,但是这个问题要比我们想象的要复杂,假设除了Employee外,我们还有Student IS-A Person,此时考虑下面两条语句
//测试数组的协变形 /** * 在声明一个数组的类型为超类 它可以应用任意类型的它的子类 * 编译的时候 Employee 是一个Person类 是通过编译的 * 但在运行的时候 会抛出运行时异常的错误 * java.lang.ArrayStorexception * 数组的协变性导致了 编译的通过 但是却导致了后面运行时异常的错误 * 使用泛型的全部意义就是在于 产生编译错误而不是运行时的异常错误 * ,所以泛型集合是不会协变得 */ public void test(){ Person [] p = new Employee[5]; p[0] = new Student("学生"); p[1] = new Employee("职员"); System.out.println(p[0].toString()); System.out.println(p[1].toString()); }
协变: