文章目录
- 基本概念
- 通配符extends
- 通配符super
- 无限定通配符?
- 总结
基本概念
如果不使用通配符,那么我们在使用了泛型之后就不允许类型参数发生改变了,但是有了通配符就可以更加灵活的控制类型参数,类型参数可以发生改变。下面准备了3个类用于演示
public class A {
}
public class B extends A {
}
public class C extends B {
}
通配符extends
我们使用这个通配符可以限制类型参数是某个类(接口)或者是其子类。
public static <T extends AutoCloseable> void close(T t) {
try {
t.close();
} catch (Exception e) {
e.printStackTrace();
}
}
上面代码中我就限定了T是AutoCloseable的实现类,由于是它的实现类,那么AutoCloseable的方法当然也就可以调用了。
如果不需要用到T,那么就可以使用?代替,个数如下
public static void printList(List<? extends B> list) {
for (B b : list) {
System.out.println(b);
}
}
上面的List<? extends B>就代表传入的List只能是B类或其子类类型的集合
需要注意的是,对于extends,我们不能够填充元素,也就是写操作
public static void printList(List<? extends B> list) {
list.add(new B());
}
上面代码会出现错误
原因就是编译器知道要传入的参数是某个类型的子类型,但不知道具体是哪个子类型
通配符super
这个通配符可以限制参数类型为某个类或者为其父类
public static void downLimit(List<? super B> list) {
// list.add(new C());
// list.add(new B());
for (Object o : list) {
System.out.println(o);
}
}
List<? super B>就表示传入的类型为B或B的父类的集合。对于super,由于不知道具体传入的是什么,所以就只能使用Object接收了。
对于super,我们可以填充元素
public static void downLimit(List<? super B> list) {
list.add(new C());
list.add(new B());
}
对于这种情况,我的理解就是将父类转换为子类不会造成信息丢失,但是由子类转换为父类可能会造成信息丢失。
下面就是java核心卷中给出的总结
带有超类型限定的通配符允许你写入一个泛型对象,而带有子类型限定的通配符允许你读取一个泛型对象。
无限定通配符?
下面就来看一个例子分析一下一个Tool类
public class Tool<T> {
private T info;
public T getInfo() {
return info;
}
public void setInfo(T info) {
this.info = info;
}
}
对于Tool<?>会有以下2个方法
? getInf()
void setInfo(?)
对于getInfo,可以调用,返回值只能赋给Object。对于setInfo,根本不能调用(如果调用只能传入null),因为不知道?是什么。
对于?,通常都是为了避免使用泛型方法。<?>就表示匹配任意类型,和extends和super一起使用分别就表示上限和下限
总结
这一节感觉自己都有点模糊,java核心卷在泛型这章讲的真的是晦涩难懂,如果上面有说错的地方,欢迎大家私信或者评论区指出。
关于泛型的更多知识,参考以下内容
泛型程序设计基础
类型擦除、桥方法、泛型代码和虚拟机
泛型的限制及其继承规则
泛型的通配符(extends,super,?)