java泛型中extends和super的区别

有些疑惑的点在这篇文章中再详细解决一下。

  1. :上界通配符

要点1:实例化时的类只能是定义时类本身或其子类,也就是说T是它的上界。

import java.util.*;

class Food{
	String name = "Food";
}
class Fruit extends Food{
	String name = "Fruit";
}
class Apple extends Fruit {
	String name = "Apple";
}

// 定义时指定T为Fruit
List list;

// 实例化时类只能是T本身或它的子类
list= new ArrayList(); //可以
list= new ArrayList(); //可以
list= new ArrayList();  //报错

要点2:上界通配符add失效(只能add null),可以get

list = new ArrayList();
list.add(new Fruit()); //报错
list.add(null);  //可以
list.get(0); //可以

既然不能add,那里面没东西又get什么呢?所以需要在实例化的时候就把东西都放进去:

list = new ArrayList(){{
	    	add(new Fruit()); // Fruit及其子类都可以放进去
	    	add(new Apple()); // Fruit及其子类都可以放进去
	    	}};

要点3:能放进去的对象类型其上界为实例化时指定的T:

List list list= new ArrayList(){{
	    	add(new Fruit()); // 实例化时指定的T为Apple,放入Fruit对象会报错
	    	add(new Apple()); // Apple及其子类都可以放进去
	    	}};

所以能放进去的对象不是看定义时T指定的类,而是看实例化时T指定的类。

2. :下界通配符

要点1:实例化时的类只能是定义时类本身或其父类,也就是说T是它的下界。

// 定义时指定T为Fruit
List list2;

// 实例化时只能是T本身或它的父类
list2 = new ArrayList(); // 可以
list2 = new ArrayList(); // 可以
list2 = new ArrayList();  // 报错

要点2:添加对象时,在实例化时添加和实例化后添加的对象限制不同(特别注意!):

1. 在实例化时添加的对象只有一个限制:上界为实例化时指定的T。来看一个有趣的现象,即使定义时指定的T是Fruit,但实例化时可以用Fruit的邻居类:

class Food{
	String name = "Food";
}
// 新定义一个Meat类,和Fruit都继承Food
class Meat extends Food{
	String name = "Meat";
}
class Fruit extends Food{
	String name = "Fruit";
}
class Apple extends Fruit {
	String name = "Apple";
}

List list2 = new ArrayList(){{
	    	add(new Object()); // 报错,上界为Food
	    	add(new Meat()); // 可以,是Food的子类,即使不是Fruit
	    	add(new Food()); // 可以
	    	add(new Fruit()); // 可以,是Food的子类
	    	add(new Apple()); // 可以,是Food的子类
	    	}};

2. 在实例化后添加的对象,其上界是定义时指定的T:

list2.add(new Meat());   // 报错,不是Fruit或其子类
list2.add(new Food());   // 报错,不是Fruit或其子类
list2.add(new Fruit());  // 可以
list2.add(new Apple());  // 可以

要点3:上界通配符get出来的对象默认是Object类型,可以做强制类型转换,可以add

Object object = list2.get(0);
Meat meat = (Meat)list2.get(0); // 如果不是Object,需要强制类型转换
System.out.println(meat.name); // 输出meat

你可能感兴趣的:(java,java)