Think in java P478
因为擦除移除了类型信息,所以,可以用无界泛型参数调用的方法只是那些可以用Object调用的方法,如果能将这个参数限制为某个类型的子集,那么你就可以使用这个类型调用方法。
interface HasColor { java.awt.Color getColor(); } class Colored<T extends HasColor> { T item; Colored(T item) { this.item = item; } T getItem() { return item; } java.awt.Color color() { return item.getColor(); } } class Dimension { public int x, y, z; }
//extends 类应该先放在前面,接口随后 class ColoredDimension<T extends Dimension & HasColor> { T item; ColoredDimension(T item) { this.item = item; } T getItem() { return item; } java.awt.Color color() { return item.getColor(); } int getX() { return item.x; } int getY() { return item.y; } int getZ() { return item.z; } }
特殊行为:可以向导出类型的数组赋予基类型数组的引用。
class Fruit {} class Apple extends Fruit {} class Jonathan extends Apple {} class Orange extends Fruit {} public class CovariantArrays { public static void main(String[] args) { Fruit[] fruit = new Apple[10]; fruit[0] = new Apple(); // OK fruit[1] = new Jonathan(); // OK // Runtime type is Apple[], not Fruit[] or Orange[]: try { // Compiler allows you to add Fruit: fruit[0] = new Fruit(); // ArrayStoreException } catch(Exception e) { e.printStackTrace(); } try { // Compiler allows you to add Oranges: fruit[0] = new Orange(); // ArrayStoreException } catch(Exception e) { e.printStackTrace(); } } }
但是实际上的数组类型是Apple[],你应该智能在其中放置Apple和Apple的子类,所以当你放置Fruit时,程序会报错ArrayStoreException。
泛型的主要目标之一是将这种错误检测移入到编译期。
List< Fruit> flist = new ArrayList<Apple>();
这句话编译错误,将这种错误提前到了编译期。
public static void main(String[] args) { List< ? extends Fruit> flist = new ArrayList<Apple>(); flist.add(new Apple());//报错 flist.add(new Fruit());//报错
flist.add(new Obeject());//报错 flist.add(null); Fruit fruit = flist.get(0); }
List<? extends Fruit> flist 表示“具有任何从Fruit基础的类型的列表",但是,这实际上并不意味着这个List将持有任何类型的Fruit,这样这个flist唯一的限制是要持有某种的Fruit或Fruit的子类型,但你实际上并不关心它是什么,那么你能用这样的List做什么呢。
List< ? super Fruit> flist = new ArrayList<Fruit>(); flist.add(new Fruit()); flist.add(new Apple()); flist.add(new Object());//报错 flist.indexOf(new Apple()); Fruit fruit = flist.get(0);//报错
List<? super Fruit> flist 表示”持有从Fruit导出的某种具体类型“,向其中添加Fruit和Fruit的子类型是安全的。Fruit是下界,添加Object不是安全的。