6、通配符的使用

通配符的使用:

类型通配符:? 
 比如: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());

    }
}
posted @ 2020-08-31 22:41  kehuaihan  阅读(543)  评论(0编辑  收藏  举报