通配符?的详细介绍~

为啥要有通配符?
通配符是用来 解决泛型无法协变的问题 的。
协变指的就是如果 Student是Person的子类,那么 List<Student> 也应该是 List<Person> 的子类。但是泛型是不支持这样的父子类关系。

通配符和泛型的区别?

1、运用泛型:
public static <T> void print1(ArrayList<T> list){//此时传入T后就知道T是什么类型的
        for (T x:list) {//再遍历的时候就知道了list里的类型,直接用T接收就行
            System.out.println(x);
        }
    }

2、运用通配符:

public static void print2(ArrayList<?> list){//此时也可以传一个任意类型,但传完之后也不知道传的是啥类型的
        for (Object x:list) {//由于不知道传了啥类型,所以用Object接收               System.out.println(x);

      }
  }


 通配符上界(extends)

语法:
<? extends 上界>
<? extends Number>//可以传入的实参类型是Number或者Number的子类

示例:
public static void printAll(MyArrayList<? extends Number> list) {
...
}
// 以下调用都是正确的
printAll(new MyArrayList<Integer>());
printAll(new MyArrayList<Double>());
printAll(new MyArrayList<Number>());
// 以下调用是编译错误的
printAll(new MyArrayList<String>());
printAll(new MyArrayList<Object>());

通配符的上界-父子类关系

MyArrayList <? extends Number >MyArrayList < Integer > 或者 MyArrayList < Double > 的父类类型
MyArrayList <?> 是 MyArrayList <? extends Number > 的父类型
MyArrayList <?> 默认上界是Object

如何解决协变问题? 让父类类型能够接收子类

假设有如下关系
Animal
Cat extends Animal
Dog extends Animal
根据以上的关系,写一个方法,打印一个存储了Animal或者Animal子类的list

法一:(错误方法)

public static void print(List<Animal> list) {//用泛型
}
不可以解决问题,因为泛型里 List<Cat> list 不是List<Animal> list 的子类
法二:
public static <T extends Animal> void print2(List<T> list) {//用有约束的泛型
        for (T animal : list) {
        System.out.println(animal);
        }
}
此时约定好了要传的类型一定是Animal的子类,此时用泛型也可以
法三:
public static void print3(List<? extends Animal> list) {//用通配符实现
        for (Animal ani : list) {
        System.out.println(ani);
        }
}

这样做的好处是不管传的是啥,传过去都让它变成Animal的子类,传哪个并不知道,因此后面要用Animal;

与法二的区别,法二假设要传Dog,后面就知道了传的是Dog,后面直接用Dog(T)接受 


 通配符的上界的特点

ArrayList<Integer> arrayList1 = new ArrayList<>();
ArrayList<Double> arrayList2 = new ArrayList<>();
List<? extends Number> list1 = arrayList1;//因为list可以引用Number或者Number的子类
List<? extends Number> list2 = arrayList1;
list1.add(0,1);//会报错,因为此时既可以引用Integer的list,又可以引用Double的list,此时就不知道现在引用的是哪个了
list1.add(1,10,9);//会报错 
Number o=list1.get(0);//可以用Number来接收

总结:

对于通配符的上界,不适合写入数据,适合读取数据(读取数据时,使用父类来接收)


 通配符下界(super)

语法:
<? super 下界>
<? super Integer>//代表 可以传入的实参的类型是Integer或者Integer的父类类型

示例
public static void printAll(MyArrayList<? super Integer> list) {
...
}
// 以下调用都是正确的
printAll(new MyArrayList<Integer>());
printAll(new MyArrayList<Number>());
printAll(new MyArrayList<Object>());
// 以下调用是编译错误的
printAll(new MyArrayList<String>());
printAll(new MyArrayList<Double>());

 通配符下界的父子类关系

MyArrayList <? super Integer > MyArrayList < Integer > 的父类类型
MyArrayList <?> MyArrayList <? super Integer > 的父类类型

通配符下界的 特点
class Person{
}
class Student extends Person{
}
public static void main(String[] args) {
        ArrayList<? super Person> arrayList1=new ArrayList<>();//arrayList1引用的一定是Person的父类
        arrayList1.add(new Person());//此时在往里面添加元素时可以添加Person或者Person的子类
        arrayList1.add(new Student());
        Person person=arrayList1.get(0);//会报错,因为当前不知道读取的是哪个子类
        Object o=arrayList1.get(0);//此时要想获取元素,必须用Object接收
}

总结:对于通配符的上界,适合写入数据,不适合读取数据

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值