java泛型通配符

1.边界

边界,如果使用泛型没有设置其边界的,那么其默认边界就是Object(向上转型),由于java泛型的机制,那些边界为object的方法只能调用Object的方法,如果要想泛型做更多的事,就必须设置其边界。使其转为更具体的类型,从而表现更多的行为。

1.1上界

<? extends MyClass> 表示继承自myClass这个类的类型。
?号表示某种特定的类型通配符,这个我们后面介绍,这是指定上界常用一种方式,MyClass表示具体的类。下面我通过一个例子了解这个上边界的用法。

<? extends Fruit> 可以让变量相对泛话,如下,集合泛型参数是确定的,即使fruit和app存在继承关系,但要是把apple的list赋给fruit list变量还是会报错,因为fruit list并不是apple list,但是使用? extends Fruit list变量接受,可以解决这个问题

//List<Fruit> fruitList = new ArrayList<Apple>(); error 参数类型不匹配
List<? extends Fruit> fruits = new ArrayList<Apple>();
class Fruit{
	private static int count=0;
	public String toString(){
		return this.getClass().getSimpleName() + " " +count++;
	}
}

class Apple extends Fruit{
	
}

class Orange extends Fruit{
	
}

class Banana extends Fruit{
	
}

class Pear extends Fruit{
	
}
public class GeneratorBound{
	public static void main(String[] args){
		List<Fruit> list = new ArrayList<Fruit>();
		List<? extends Fruit> list1 = list;
		//list1.add(new Fruit()) //error
		//list1.add(new Apple())// error
		//list1.add(new Object())//error
		Fruit f = list1.get(0);
	}
}

这有个Apple,pear等类的父类是Fruit类,
我们实例化了一个Fruit类型的集合list,又声明了一个引用变量list1,这个集合的类型使用来上面的表达式,表示继承自Fruit的集合,并将其指向list。但是这里list1的add方法,却不能添加Fruit或Fruit的子类,按理来说向上转型,应该是可以添加的,这是为什么呢?原因是java的泛型是由"擦除实现",编译器在编译期就必须确定这个集合的类型,对于list1来说,由于并不知道Fruit的子类型到底有哪些,相当于向下开了一个口子,为了保证添加类型的安全,所以add方法只能添加null,那这样的类型有什么用呢,所以使用了**<? extends Fruit>,只适合拿来获取元素,不适合设置元素** 。

Fruit f = list1.get(0);

list1适合用来取元素。因为向上转型是安全的。

1.2下界(逆变)

<? super MyClass> 也可以使用类型参数<? super T>,前者表示Myclass的超类,后者表示泛型参数超类。我们还是通过刚才那个例子来看看

public class GeneratorBound{
	public static void main(String[] args){
		List<Fruit> list = new ArrayList<Fruit>();
		List<? super Fruit> list1 = list;
		list1.add(new Fruit());
		list1.add(new Apple());
		//list1.add(new Object()); Type mismatch: cannot convert from capture#3-of ? super Fruit to Fruit
		// Fruit f = list1.get(0);
	}
}

list1表示Fruit父类的集合,但是我们确发现list1可以添加Fruit的子类,但却不能添加Fruit的父类,这不是和我们上面的描述矛盾?,因为list1并不知道Fruit的父类有哪些,相当于向上开了一个口子,如果可以添加Fruit或Fruit的父类,将无法安全的添加元素,而添加子类向上转型为Fruit,是安全的。和<? extends Fruit>是相反的。所以向集合添加元素可以使用<? super MyClass>,而取元素使用<? extends Fruit>更为方便。造成这些原因都是因为java的泛型是由”擦除“实现的。这也是java泛型不够强大的原因。

1.3?(通配符)

表示某个特定类型的非原生类型,例如List表示持有任何类型的非原生List,而List<?>表示某种特定类型的非原生List,在很多情况下2者可以表现出相同的性质。使用?会导致确切的类型信息丢失,从而表现出足够泛话,要使用特定类型则需要强转。

public class GeneratorBound{
	public static void main(String[] args){
		List<Fruit> list = new ArrayList<Fruit>();
		List<?> list2 = list;
		//list2.add(new Object()); error 不知道是什么类型,所以即使是Object类型也无法添加进容器。
		Object obj = list2.get(0);//取出来向上转型为Object类型
		
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值