1 使用背景
在使用泛型时,C<SuperA> 与 C<A> 是并列的两个类,没有子父类关系,也就不能相互赋值。如 ArrayList<Object> 与 ArrayList<String> 没有关系,这使得在给方法传参时,通用性很差。使用通配符C<?>能使得代码的兼容性更好。
2 类型通配符?的使用
当带上类型通配符?,如List<?>时,可以理解为集合内的数据类型是任何可能的类型,在继承关系上用区间表示就是(-∞,+∞),可以理解为所有明确类型List<>的父类。
2.1 带类型通配符数据的读写
a. 读带类型通配符的数据
由于?代表了任何可能的类型,所以在接收读取到的数据时,一般要用通用型的基类Object来接收,也可以将其强转为指定的类型。
public static void main(String[] args) {
List<String> list1 = new ArrayList<>();
list1.add("abc");
List<?> list= null;
list = list1;
Object o = list.get(0);
String str = (String)list.get(0);
}
b.将数据写入带类型通配符的结构
由于?代表了任何可能得类型,所以在写入数据时,我们要写入的任何数据类型都可能是其子类,而且因为不能把子类的数据直接赋给父类数据,所以不能写入任何数据。
唯一例外的是可以写入null,因为null是任何引用型数据变量的默认值。
2.2 类型通配符的使用环境
类型通配符主要就是应用在传参、赋值等的读取、接收数据的场合,其他的场景使用较少,而且如以下几类是语法所不允许的:
(1)不能声明一个带通配符?的泛型方法
public <?> void test(ArrayList<?> list){}
(2)不能声明一个带通配符?的泛型类
public class TestClass(){}
(3)不能定义一个带通配符?的集合
List<?> list = new ArrayList<?>();
2.3 有限制条件的通配符的使用
-
? super A ==> ? ≥ A
读取数据:List <? super A> :若B是A的父类,可以将List<A>或List<B>赋值给List<? extends A>。即A和A的父类的数据都可以被读取。
写数据:表示该泛型可能是较大的类型,这时B和B的子类一定是'?'类的子类,这时,可以往里面写入B和B的子类类型的数据。
-
? extends A ==> ? ≤ A
读取数据:List<? extends A> :若B是A的子类,可以将List<A>或List<B>赋值给List<? extends A>。即A或A的子类的数据都可以被读取。
写数据:表示该泛型可能是较小的类型,这时A和A的父类一定是'?'类的父类,这时,不能把父类的数据写入子类中,即不能写入除null外的数据。
-
? 可以理解为 (-∞, +∞') 这时除null外的任何类型的数据都不能写入。
-
通配符不能带双向限制条件,即同时有extends和super。
参考:尚硅谷-宋红康-Java基础:尚硅谷Java零基础全套视频教程(宋红康2023版,java入门自学必备)