package com.rq.util.module.exercise.capture;
/**
* 频繁读取内容的使用 上界(extends)
* 频繁插入的,用下界(skuper)
* @author rq
*
*/
public class TestCapture2 {
@SuppressWarnings("unused")
public static void main(String[] args) {
Plate<Fruit> fruitPlate = new Plate<Fruit>(new Apple());
Fruit apple = new Apple(); // 元素之间的转型没有问题
// Plate<Fruit> applePlate = new Plate<Apple>(new Apple()); // Apple类型的plate, 无法转成 Fruit类型的plate,,容器之前不能转型
// 不能存、只能取
Plate<? extends Fruit> applePlate = new Plate<Apple>(new Apple()); // 允许Fruit及其子类的容器创建
Fruit a1 = applePlate.get(); // 1*** 本质是一个强制转换,?的类型一定是泛型的子类(或等于泛型本身),因此此处是一个向上转型,不用强制转换,类型安全** 但是调用方法只能是父类的,子类未重写的方法全部丢失 **
Object a2 = applePlate.get();
// Apple a3 = applePlate.get(); // 编译器只知道容器内饰Fruit或其派生类(子类),具体不知道,可能是Apple、Banana、GreenApple...
// applePlate.put(new Apple()); // 无论插入什么类型的值,编译器都不知道能不能和泛型匹配,所以都不允许插入 <capture#3-of ? extends Fruit> is not applicable for the arguments (Apple)
// <?> 表示任意内容,区分 <? extends ??>
applePlate.put(null);
Plate<? super Fruit> superFruitPlate1 = new Plate<Fruit>(new Apple()); // Fruit及其基类(父类)的容器创建
Plate<? super Fruit> superFruitPlate2 = new Plate<Food>(new Apple());
superFruitPlate1.put(new Fruit());
superFruitPlate1.put(new Apple());
// Apple a3 = superFruitPlate1.get(); // 既然元素是Fruit的基类,那么往里存的数据比Fruit小的都可以,但是取值就麻烦了,只有所有类的基类Object才能装
// Fruit a4 = superFruitPlate1.get();
Object a5 = superFruitPlate1.get(); // 2*** 本质依然是强制转化,不过此处?是泛型的父类(或泛型本身),父类转子类需要强制转换,类型不安全,可调用方法可从子类中找,父类中不一定有,会有异常
}
}
/**
* declare a container
* @author rq
*
* @param <T>
*/
class Plate<T>{
private T item;
public Plate(T t){
this.item = t;
}
public T get(){return this.item;}
public void put(T t){this.item = t;}
}
class Food{}
class Meat extends Food{}
class Fruit extends Food{}
class Apple extends Fruit{}
class Banana extends Fruit{}
class Pork extends Meat{}
class Beef extends Meat{}
class RedApple extends Apple{}
class GreenApple extends Apple{}
向上转型: 子类转父类,即父类的引用指向子类的实现。这种情况需要注意:引用能调用的内容是以父类为框架的,如果子类重写了父类的方法,那么调用子类本身的方法,如果没有则会调用父类方法(本质上还是子类方法,因为子类已经拥有了父类的特性),多态的一种重要实现手段。
乡下转型: 即父类转子类。需要强制转换,这种操作必须能知道父类中每个元素的类型才能保证安全,使用过程是,先子类向上转型,然后再向下转型。常用于容器,例如一个List<Animal>中装有Dog、Cat、Duck。。。,取出对象时进行强转,然后调用对应的方法。