[软件构造心得2] 集合类使用泛型通配符的问题

集合类使用通配符的问题

在实验3中,设计可复用的API时,由于我的接口PlanningEntryAPIs要同时复用于航班管理、高铁车次管理、学习日程管理三个APP,而这3个APP的传给我API中的方法的类型都不同。例如,对于判断资源冲突的方法,我需要传一个含有计划项的List,而不同的APPList存储的计划项类型不同(航班是PlaneEntry、高铁是TrainEntry、学习日程是ActEntry),但是这三个计划项类型都是继承父类PlanningEntry的,因此我考虑使用含有通配符的List<? extends PlanningEntry>来进行传递参数,但是在具体使用中却遇到了问题。

1、什么是通配符

对于集合类的泛型T,在具体使用时,实际上会产生类型擦除的状况,也就是说无论向集合类传入什么参数,在运行时都会把泛型T给擦除成Object。具体实现可参照下面的代码
擦除之前:

public class Node<T> {
private T data;
private Node<T> next;

public Node(T data, Node<T> next) {
	this.data = data;
	this.next = next;
	}
	public T getData() { return data; }
	//...
}

擦除之后

public class Node {
private Object data;
private Node next;

public Node(Object data, Node next) {
	this.data = data;
	this.next = next;
	}
	public Object getData() { return data; }
	//...
}

因此,因为类型擦除的存在,像List<String>List<Integer>等就不是List<Object>的子类型。我们知道对一个方法进行传参,是可以将子类型传给父类型的,但是如果我们的参数定义成List<Object>,却不能将List<String>List<Integer>等传给它,这造成了很大的困扰。

于是就有了泛型统配符的存在,我们参数写了List<?>,这个参数就可以接受List<String>List<Integer>了。
更进一步,除了无界通配符,还有上界和下界通配符
1、上界通配符: < ? extends E>,它表示参数化的类型可能是所指定的类型,或者是此类型的子类。
2、下届通配符: < ? super E>,它表示参数化的类型可能是所指定的类型,或者是此类型的父类型,直至 Object

顺带一提,尽管在传参时List<String>List<Object>是两个完全没关系的类型,但是判断overload时候是相等的,所以父类是List<Object>,子类是List<String>,或者父类是List<String>,子类是List<Object>,那么仍然不是overload(因为参数列表相同)。

2、集合类使用泛型通配符时调用add方法

对于集合类,调用add方法时有比较严格的限制,用简单的两句话来概括:
1、无界通配符?,只能add空对象null
2、上界通配符< ? extends E>,同样只能add空对象null
3、下界通配符< ? super E>,能够addE本身和E的子类型
举几个简单的例子
1、无界通配符?

List<?> list = new ArrayList<Number>();
Number a = 1;
list.add(null);//编译没有问题
list.add(a);//编译错误不兼容的类型: java.lang.Number无法转换为capture#1, 共 ?

2、上界通配符< ? extends E>

List<? extends Number> list1 = new ArrayList<>();
Integer a = 1;
list1.add(null);//编译没有问题
list1.add(a);//编译错误,不兼容的类型: java.lang.Integer无法转换为capture#1, 共 ? extends java.lang.Number
List<? extends Integer> list2 = new ArrayList<>();
Number b = 1;
list2.add(null);//编译没有问题
list1.add(b);//编译错误,不兼容的类型: java.lang.Number无法转换为capture#1, 共 ? extends java.lang.Integer

3、下界通配符< ? super E>

List<? super Number> list1 = new ArrayList<>();
Integer a = 1;
Double b = 2.5;
list1.add(null);//编译没有问题
list1.add(a);//编译没有问题
list2.add(b);//编译没有问题
List<? super Integer> list1 = new ArrayList<>();
Number c = 1;
list2.add(c);//编译错误,不兼容的类型: java.lang.Number无法转换为capture#1, 共 ? super java.lang.Integer

那么为什么只有< ? super E>能addE本身和E的子类型,而< ? extends E>?却只能add空对象null呢?

这是因为对于集合内的类型E,是可以调用add方法添加EE的子类型的。
< ? super E>代表的是EE的父类型,而E本身和E的子类型必然是< ? super E>的子类型,所以可以正常调用add方法添加。

但是< ? extends E>?代表的类型可能是E的子类型,对于这样一个未知的E的子类型(不妨记作R),没法确保我们add的类型是R的子类型,所以不能调用add方法添加。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值