泛型

关于泛型的几点:

  1. 尖括号里的每个元素都代表一种未知类型
  2. 尖括号只能出现在类名之后(作用于类的泛型)或者方法返回值之前(方法泛型)

使用泛型的好处:

  1. 类型安全 避免粗心导致的类转换异常
  2. 提升代码可读性 编码阶段即可知道对象类型
  3. 提升了代码的复用率

泛型类

class Map<K>{
    // 修饰成员变量
    private K key;

    // 修饰参数
    public Map(K key){}

    // 修饰返回值
    public K get(){
        // 修饰局部变量
        K key1 = key;
        return key1;
    }
}

泛型方法

// <T> 声明的是这个方法的泛型参数 后面的T声明的是方法的返回类型
public static <T> T run(T obj){
    return obj;
}

泛型限定

// 约定T必须是Comparable的子类
<T extends Comparable> 
// 可同时指定多个父接口
<T extends Comparable&Serializable> 

通配符

// 只能接受S的自身或子类
<? extends S>
// 能接收S自身及其超类
<? super S>
// 不限制类型,只能使用object接收
<?>

PESC原则

Producer Extends Consumer Super

List<Apple> apples = new ArrayList<>();
apples.add(new Apple());
List<? extends Fruit> basket = apples;//按上一个例子,这个是可行的
for (Fruit fruit : basket)
{
    System.out.println(fruit);
}

//basket.add(new Apple()); //编译错误
//basket.add(new Fruit()); //编译错误
List<Apple> apples = new ArrayList<>();
apples.add(new Apple());
List<? super Apple> basket = apples;//这里使用了super

basket.add(new Apple());
basket.add(new RedApple());
//basket.add(new Fruit()); //编译错误

Object object = basket.get(0);//正确
//Fruit fruit =basket.get(0);//编译错误
//Apple apple = basket.get(0);//编译错误
//RedApple redApple = basket.get(0);//编译错误

出现这个原则的原因是因为 List<Apple>List<Fruit> 没有任何关系

如Java API中对集合的复制:

public static <T> void copy(List<? super T> dest, List<? extends T> src) {
  ...
}

泛型擦除

补救:

如果想要在运行时获取泛型的类型 那就必须通过某种手段记录泛型的 Class 对象

类型变化关系

批注 2019-10-30 131946