0%

corejava基础知识(3)-泛型

本文是对 java 泛型的总结

泛型

泛型类与方法的一般格式

泛型类:

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; }
}

泛型方法:

class ArrayAlg
{
public static <T> T getMiddle(T... a)
{
return a[a.length / 2];
}
}

该方法是在普通类定义的泛型方法,调用时:

String middle = ArrayAlg.<String>getMiddle("]ohnM, "Q.n, "Public");

术语:

  • ArrayList<E> – 泛型类型
  • ArrayList – 原始类型
  • E – 类型参数(变量)
  • <> – 读作”typeof”
  • ArrayList<Integer> – 参数化的类型
  • Integer – 实际类型参数

类型变量的限定

我们可以对类型变量加以约束,毕竟我们很难适用每种泛型。可以通过对类型变量 T 设置限定(bound) 实现这一点,格式如下:

<T extends BoundingType>

BoundingType 可以是

  • :T 是它的子类型(subtype)
  • 接口: T 是实现了该接口的类

可以有多个接口,当然至多有一个类,用 “&” 分隔。

ps: 由于类型擦除机制,为了提高效率,应该将标签(tagging) 接口 (即没有方法的接口)放在边界列表的末尾。

泛型转化的内部

  • 虚拟机中没有泛型, 只有普通的类和方法;所有的类型参数都用它们的限定类型替换。
  • 编译器在调用泛型方法时会自动插入强制类型转换。
  • 桥方法被合成来保持多态。

约束与局限性

  • 不能用基本类型实例化类型参数

即没有Pair<double>,只有Pair<Double>。原因是类型擦出后,Object不能存储double值,毕竟它不是对象

  • 运行时类型查询只适用于原始类型

所有的类型查询只产生原始类型,例子:

Pair<String> stringPair = ...;
Pair<Employee> employeePair = ...;
if(stringPir.getClass() == employeePair.getClass()) // they are equal
  • 不能创建参数化类型的数组

Pair<String>[] table是错的;

只能使用AllayList: ArrayList<Pair<String>> table

  • Varargs警告

向参数个数可变的方法传递一个泛型类型的实例时,为了调用这个方法,Java 虚拟机必须建立一个参数化类型的数组,可是这违反了前一个规则。

我们可以用 @SafeVarargs 直接标注该方法,这样就能正常运行。

  • 不能实例化类型变量

例如:

public Pair() { first = new T(); second = new T(); } // Error

  • 不能构造泛型数组

  • 泛型类的静态上下文中类型变量无效

也就是不能在静态域或方法中引用类型变量。

  • 不能抛出或捕获泛型类的实例
  • 可以消除对受查异常的检查