泛型2

一,数组类型的兼容性

假设Student继承自Person,Teacher也继承自Person,考虑一个问题

Person[] person = new Student[10];

person[0] = new Teacher(.....);

这个代码实际上在编译时都不会出错,可是Teacher并不继承于Student这就产生了类型混乱。由于其中不存在类型转换,运行时系统不会抛出ClassCastException异常。若果指定Student[]与Teacher[]数组不和Person[]数组兼容,这个问题就不存在了,但在Java中数组却是类型兼容的。

数组具有协变性,这叫做协变数组类型。如果将一个不兼容的类型插入到数组中,那么虚拟机将抛出一个ArrayStoreException异常。这使得Person[]数组中可以同时存放Student与Teacher两个元素。

二,简单的泛型类和接口

泛型类的声明包含一个或多个放在尖括号内的类型参数,在类的内部,我们可以声明泛型类型的域和使用泛型类型作为参数或者返回值的方法,例如:

public class Test<AnyType>{

  public Anytype read(){

    return storedValue;

  }

  public void write(Anytype x){

    storedValue = x;

  }

  private AnyType storedValue;

}

可以对Test<String>的write方法传入一个String类型的参数,传入其他类型的参数将产生编译错误。

也可以声明接口是泛型的。例如在Java 5 中Comparable接口是泛型的,这使得从前传递到compareTo的任何引用变量即使不合理的类型也会编译的现象消失。

泛型类和接口使得以前只有在运行时才能发现的错误如今在编译时就能发现。

菱形运算符:在实例化Test<AnyType>时需要写Test<String> test = new Test<String>(),这样会使实例化的代码复杂,但我们知道既然test是Test<String>的那么创建的对象也必然是Test<String>类型的,在Java 7中可以使用菱形运算符进行改写Test<String> test = new Test<>();

通配符:Java中数组是协变的但泛型集合不是协变的,这会出现一种现象,及当Collection<Person>作为参数时,若传入Collection<Student>会产生一个编译错误,泛型不是协变的体现了使用泛型的好处即会产生编译错误而不是运行时报错,但因为泛型缺乏协变性,在一些代码的编写上会缺乏灵活性,在Java 5中使用了通配符弥补了这个不足。例如使用Collection<? extends Person>替代Collection<Person>,此时传入Collection<Student>不会报错。

类型限界:在用泛型编写的方法中,有时会规定传入的参数必须拥有某些性质,例如使用compareTo()方法寻找最大值时,需要规定比较的项必须实现了Comparable接口,此时就出现了类型限界。类型限界在尖括号内指定,它指定参数类型必须具有的性质。例如public static <Anytype extends Comparable<Anytype>>当然,这句代码还可以进一步优化,假设Square继承Shape,Shape实现了Comparable<Shape>接口,那么Square也实现了Comparable<Shape>接口,但此时Square并未实现Comparable<Square>接口,所以可以将代码加上通配符继续优化即public static <Anytype extends Comparable<? super Anytype>>

原文地址:https://www.cnblogs.com/asiastic-wormwood/p/8436099.html