类型变量使用大写形式,且比较短, 这是很常见的。在 Java 库中, 使用变量 E 表示集合的元素类型, K 和 V 分别表示表的关键字与值的类型。T ( 需要时还可以用临近的字母 U 和 S) 表示“ 任意类型”。
1.简单的泛型类
public class Pair<T>
{
private T first;
private T second;
public Pair() { first = null; second = null; }
public Pair(T first, T second) { this.first = first; this.second = second; }
public T getFirst() { return first; }
public T getSecond() { return second; }
public void setFirst(T newValue) { first = newValue; }
public void setSecond(T newValue) { second = newValue; }
}
2.简单的泛型方法
public static <T> T getMiddle(T... a)
{
System.out.println(a.length);
return a[a.length / 2];
}
3.将T 限制为实现了 Comparable 接口的类,
public static <T extends Comparable> Pair<T> minmax(T[] a)
{
if (a == null || a.length == 0) return null;
T min = a[0];
T max = a[0];
for (int i = 1; i < a.length; i++)
{
if (min.compareTo(a[i]) > 0) min = a[i];
if (max.compareTo(a[i]) < 0) max = a[i];
}
return new Pair<>(min, max);
}
这里限定了 T 一定要实现Comparable接口,如果使用该方法时没有实现 Comparable 接口, 编译时将会报错。
LocalDate 有实现Comparable.
这里我自定义了一个没有实现Comparable的Pair。
。
一个类型变量或通配符可以有多个限定。
例:T extends Comparable & Serializable
泛型与虚拟机
虚拟机没有泛型类型对象—所有对象都属于普通类。
无论何时定义一个泛型类型, 都自动提供了一个相应的原始类型 ( raw type )。原始类型
的名字就是删去类型参数后的泛型类型名。擦除( erased) 类型变M, 并替换为限定类型(无
限定的变量用 Object)。
总之,需要记住有关 Java 泛型转换的事实:
•虚拟机中没有泛型,只有普通的类和方法。
•所有的类型参数都用它们的限定类型替换。
•桥方法被合成来保持多态。
•为保持类型安全性,必要时插人强制类型转。
约束与局限
由于擦除的原因,泛型的使用有一些约束与局限。大部分都是应该这些阶段需要再编译期确定下来。而对于虚拟机而言,并没有所谓泛型。
- 不能用基本类型实例化类型参数。没有 Pair<double>, 只 有 Pair<Double>
- 运行时类型查询只适用于原始类型。eg: if (a instanceof Pair<String>) // Error
- 不能创建参数化类型的数组。 Pair<String>[] table = new Pair<String>[10]; // Error 擦除之后, table 的类型是 Pair[]。
- 不能实例化类型变置 不能使用像 new T(...,) newT[...] 或 T.class 这样的表达式中的类型变量。
- 不能构造泛型数组,数组本身也有类型,用来监控存储在虚拟机中的数组。这个类型会被擦除。eg:public static <T extends Comparable〉T[] minmax(T[] a) { T:D 刪 = new T[2]; . . . } // Error
- 泛型类的静态上下文中类型变量无效。 private static T singlelnstance; // Error
- 不能抛出或捕获泛型类的实例,甚至泛型类扩展 Throwable 都是不合法的。eg:public class Problem<T> extends Exception { /* . . . */ } // Error can't extend Throwable
java泛型中的通配符 extends与super
1. ? 表示通配符类型
2. <? extends T> 既然是extends,就是表示泛型参数类型的上界,说明参数的类型应该是T或者T的子类。
3. <? super T> 既然是super,表示的则是类型的下界,说明参数的类型应该是T类型的父类,一直到object。
public class GenericClass {
static class Animal {}
static class FlyAnimal extends Animal {}
static class Bird extends FlyAnimal {}
public void testExtend() {
List<? extends FlyAnimal> list = new ArrayList<Bird>();
//无法安全添加任何具有实际意义的元素
//list.add(new Bird());
//list.add(new FlyAnimal());
list.add(null);
Animal animal = list.get(0);
Bird bird = (Bird)list.get(0);
}
public void testSuper() {
List<? super FlyAnimal> list = new ArrayList<FlyAnimal>();
list.add(new FlyAnimal());
list.add(new Bird());
//list.add(new Animal());
//List<? super FlyAnimal> list2 = new ArrayList<Bird>();
//FlyAnimal flyAnimal = list.get(0); 不能确定返回类型
}