通配符的使用:
类型通配符:?
比如:List<?>,Map<?,?> List<?> 是 List<String>、List<Object> 等各种泛型 List 的父类。
读取 List<?> 的对象list中的元素时,永远是安全的,因为不管list的真实类型是什么,它包含的都是Object。
写入list中的元素时,不行。因为我们不知道真正的元素类型,我们不能向其中添加对象。唯一的例外是null,它是所有类型的成员。
通配符使用的注意点:
1、不能用在泛型方法声明上,返回值类型前面<>中不能使用?
2、编译错误:不能用在泛型类的声明上
3、不能用在创建对象上,右边属于创建集合对象
有限制的通配符:
1、<?>:
允许所有泛型的引用调用
2、通配符指定上限
上限extends:使用时指定的类型必须是继承某个类,或者实现某个接口,即<=;
<? extends Number>,(无穷小 , Number]:只允许泛型为 Number 及 Number 子类的引用调用;
3、通配符指定下限
下限super:使用时指定的类型不能小于操作的类,即>=;
<? super Number>,[Number , 无穷大):只允许泛型为 Number 及 Number 父类的引用调用;
实例1:
public class GenericTest {
@Test
public void test3() {
List<Object> list1 = null;
List<String> list2 = null;
List<?> list = null;
// 编译通过
list = list1;
list = list2;
}
}
实例2:
public class GenericTest {
@Test
public void test3() {
List<?> list = null;
// 编译报错,不能添加(写入)数据
list.add("123");
list.add(123);
List<String> list2 = new ArrayList<>();
list = list2;
// 还是编译报错,不能添加(写入)数据
list.add("123");
list.add(123);
// 这个是可以的
list.add(null);
}
@Test
public void test3() {
List<?> list = null;
List<String> list2 = new ArrayList<>();
list2.add("AA");
list2.add("BB");
list2.add("CC");
list = list2;
// 获取(读取):允许读取数据,读取的数据类型为 Object。
Object o = list.get(0);
}
}
实例3:
// 注意点1:编译错误:不能用在泛型方法声明上,返回值类型前面<>中不能使用?
public static <?> void test(ArrayList<?> list) {
}
//注意点2:编译错误:不能用在泛型类的声明上
class GenericTypeClass<?> {
}
// 注意点3:编译错误:不能用在创建对象上,右边属于创建集合对象
ArrayList<?> list2 = new ArrayList<?>();
实例4:
public class Person {
}
public class Student extends Person {
}
public class GenericTest {
@Test
public void test4(){
List<? extends Person> list1 = null;
List<? super Person> list2 = null;
List<Student> list3 = new ArrayList<Student>();
List<Person> list4 = new ArrayList<Person>();
List<Object> list5 = new ArrayList<Object>();
// 下面两个编译通过
list1 = list3;
list1 = list4;
// 编译不通过
// list1 = list5;
// 编译不通过
// list2 = list3;
// 下面两个编译通过
list2 = list4;
list2 = list5;
}
@Test
public void test4(){
List<? extends Person> list1 = null;
List<? super Person> list2 = null;
List<Student> list3 = new ArrayList<Student>();
List<Person> list4 = new ArrayList<Person>();
List<Object> list5 = new ArrayList<Object>();
// 读取数据:
list1 = list3;
Object o = list1.get(0);
Person p = list1.get(0);
// 下面这行不可以
// Student s = list1.get(0);
list1 = list4;
Person p = list1.get(0);
Object o = list1.get(0);
// 下面这行不可以
// Student s = list1.get(0);
// 总结:最小要使用 Person 接收
System.out.println("======================================");
list2 = list4;
Object o = list2.get(0);
// 下面两行编译不通过
// Person p = list2.get(0);
// Student s = list2.get(0);
// 总结:最小要使用 Person 的父类来接收
System.out.println("======================================");
//写入数据:
//编译不通过
// list1.add(new Student());
//编译通过
list2.add(new Person());
list2.add(new Student());
}
@Test
public void test4(){
List<? extends Person> list1 = null;
List<? super Person> list2 = null;
List<Student> list3 = new ArrayList<Student>();
List<Person> list4 = new ArrayList<Person>();
List<Object> list5 = new ArrayList<Object>();
// 写入数据:
// 编译不通过
// list1.add(new Student());
// list1.add(new Person());
// 编译通过
list2.add(new Person());
list2.add(new Student());
}
}