由泛型数组列表引入
ArrayList是一个有类型参数(type parameter)的泛型类(generic class),可自适应大小,取代Vector类。
但也存在缺点:增加了访问元素语法的复杂度,需要使用set()和get()。
Collections可实现集合的泛型算法。
//声明
ArrayList<Employee> staff = new ArrayList<Employee>();
ArrayList<Employee> staff = new ArrayList<>(100);
ArrayList<Employee> staff = new ArrayList<>();
//Java10中最好使用var关键字避免重复写类名
var staff = new ArrayList<Employee>();
//分配大小
staff.ensureCapacity(100);
//添加元素
staff.add(new Employee("Harry Hacker",...));
//返回元素个数
staff.size();
//设置第1个元素为harry
staff.set(2,harry);
staff.get(2);
staff.remove(2);
staff1.addAll(staff);
Collections.sort();
泛型程序设计
泛型类产生的一个原因就是为了创造容器类。由ArrayList可见,该代码可以对多种不同类型的对象重用,容器类算得上最具重用性的类库之一了。泛型的出现也可将一组对象直接打包存储于单一对象一并返回,即一次方法调用就返回多个对象。
定义泛型类
public class Pai<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; }
}
//实例化
Pair<String>();
泛型接口
工厂方法设计模式的一种应用。
定义泛型方法
class ArrayAlg{
public static <T> T getMiddle(T...a){
return a[a.length / 2];
}
public static <T extends Comparable> Pair<T> minmax(T[] a){
...
return new Pair<>(min,max);
}
//Java可implements多个接口,但只能extends一个类
<T extends Comparable & Serializable>
}
String middle = ArrayAlg.<String>getMiddle("John","Q.","Public");
String middle = ArrayAlg.getMiddle("John","Q.","Public");
泛型代码与虚拟机
虚拟机中没有泛型类对象,都是普通类对象,因为编译器会擦除类型参数,类型参数会替换为它们的限定类型,如用Object替换<T>,用合成桥方法保持多态。为保持类型安全性,必要时在结果字节码中插入强制类型转换。而C++则会为每个模板实例化产生不同的类型,形成“模板代码膨胀”。
public static <T extends Comparable>T min(T[] a)
//擦除类型后只剩一个方法
public static Comparable min(Comparable[] a)
//桥方法
public void setSecond(Object second) { setSecond((LocalDate) second);}
限制与局限性
1.不能使用基本类型实例化类型参数
2.运行时类型查询只适用于原始类型:getClass()总是返回原始类型。
Pair<String> sringPair = ...;
Pair<Employee> employeePair = ...;
if(stringPair.getClass() == employeePair.getClass())
//true,都是Pair.class,并不比较String和Employee
3.不能创建参数化类型的数组,应直接使用ArrayList。
var table = new Pair<String>[10];//ERROR
//擦除后
Object[] objarray = table;
objarray[0] = "Hello";//ERROR
//不过对于泛型类型,擦除会使以下机制无效
objarray[0] = new Pair<Employee>();
//可声明但不可初始化,会产生ClassCastException异常
4.Varargs警告
S:向参数个数可变的方法传递一个泛型类型的实例。
Collection<Pair<String>> table = ...;
Pair<String> pair1 = ...;
Pair<String> pair2 = ...;
addAll(table,pair1,pair2);
JVM会建立Pair<String>数组,会发出警告,不抛出错误。可用@SuppressWarnings("unchecked")或@SafeVarargs直接注解addAll()。
@SafeVarargs只能用于声明为static、final或Java9中private的构造器和方法。
5.不能实例化类型变量(不可new T(),会擦除为Object)
6.泛型类的静态上下文中类型变量无效。
7.不能抛出或捕获泛型类的实例。
8.子类父类的<T>Pair两个实例无关系。
通配符
<? super/extends Manager>