类型通配符

1.什么是类型通配符

  • 类型通配符一般是使用"?"代替具体的类型实参。

  • 所以,类型通配符是类型实参,而不是类型形参。

小案例:

package com.genericity.demo2;

/**
 * 创建泛型类
 * @param <T>
 */
public class Box<T> {
    private T first;

    public T getFirst() {
        return first;
    }

    public void setFirst(T first) {
        this.first = first;
    }
}
类型通配符
 1 package com.genericity.demo2;
 2 
 3 public class MainClass {
 4     public static void main(String[] args) {
 5         //进行测试
 6         Box<Number> box1 = new Box<>();
 7         box1.setFirst(100);
 8         showBox(box1);//运行结果:100
 9 
10 //        Box<Integer> box2 = new Box<>();
11 //        box2.setFirst(200);
12 //        showBox(box2);//我们都知道Integer继承至Number,但是我的定义的方法是public static void showBox(Box<Number> box){ 他是不支持的,即使这样public static void showBox(Box<Integer> box){ 也是不行的。
13         //我们可以使用类型通配符的方式  public static void showBox(Box<?> box){
14 
15         Box<Integer> box2 = new Box<>();
16         box2.setFirst(200);
17         showBox(box2);//运行结果:200
18 
19 
20     }
21 //    public static void showBox(Box<Number> box){
22 //        Number first = box.getFirst();
23 //        System.out.println(first);
24 //    }
25 
26     /**
27      * 使用类型通配符的方式
28      *
29      * @param box
30      */
31     public static void showBox(Box<?> box) {
32         Object first = box.getFirst();
33         System.out.println(first);
34     }
35 
36     /**
37      * 这样也是不行的
38      * @param box
39      */
40 //    public static void showBox(Box<Integer> box){
41 //        Integer first = box.getFirst();
42 //        System.out.println(first);
43 //    }
44 }
View Code

2.类型通配符的上限(接上文)

  • 语法:类/接口

  • 要求该泛型的类型,只能是实参类型,或实参类型的子类类型。

    上面的代码我们看着是不是十分的不爽,既然是?通配符了,但是返回的还是Object类型的。

类型通配符
1 /**
2      * 使用类型通配符的方式
3      *
4      * @param box
5      */
6     public static void showBox(Box<?> box) {
7         Object first = box.getFirst();
8         System.out.println(first);
9     }
View Code

对上面的代码使用类型通配符的上限的方式进行改造

类型通配符
 1 package com.genericity.demo3;
 2 
 3 public class MainClass {
 4     public static void main(String[] args) {
 5         //进行测试
 6         Box<Number> box1 = new Box<>();
 7         box1.setFirst(100);
 8         showBox(box1);//运行结果:100
 9 
10         Box<Integer> box2 = new Box<>();
11         box2.setFirst(200);
12         showBox(box2);
13 
14     }
15 
16     /**
17      * 使用类型通配符的方式
18      * 使用类型通配符的上限,这样我们在传值的时候,就可以传Number类型或者是Number类型的子类
19      * @param box
20      */
21     public static void showBox(Box<? extends Number> box) {
22         Number first = box.getFirst();
23         System.out.println(first);
24     }
25 
26 }
View Code

小案例:

类型通配符
1 package com.genericity.demo3;
2 
3 public class Animal {
4 }
View Code 类型通配符
1 package com.genericity.demo3;
2 
3 public class Cat extends Animal {
4 }
View Code 类型通配符
1 package com.genericity.demo3;
2 
3 public class MiniCat extends Cat {
4 }
View Code 类型通配符
 1 package com.genericity.demo3;
 2 
 3 import java.util.ArrayList;
 4 
 5 /**
 6  * 类型通配符上限方式
 7  */
 8 public class Test {
 9     public static void main(String[] args) {
10         ArrayList<Animal> animals= new ArrayList<>();
11         ArrayList<Cat> cats= new ArrayList<>();
12         ArrayList<MiniCat> miniCats= new ArrayList<>();
13 
14 //        showAnimal(animals); Animal类不是Cat类型或者Cat类型的子类
15         showAnimal(cats);
16         showAnimal(miniCats);
17 
18         /**
19          * 源码:
20          * public boolean addAll(Collection<? extends E> c) {
21          *         Object[] a = c.toArray();
22          *         int numNew = a.length;
23          *         ensureCapacityInternal(size + numNew);  // Increments modCount
24          *         System.arraycopy(a, 0, elementData, size, numNew);
25          *         size += numNew;
26          *         return numNew != 0;
27          *     }
28          */
29 
30         cats.addAll(miniCats);//输入的时候提示:addAll(Collection<? extends Cat>
31     }
32 
33     /**
34      * 泛型上限通配符,传递的集合类型,只能是Cat或者Cat的子类类型
35      * @param list
36      */
37     public static void showAnimal(ArrayList<? extends Cat> list){
38         //注意:使用类型通配符上限的这种方式是不能添加元素的,因为你不能确定?号代表的是什类型,是Cat类还是MiniCat类,如果是MiniCat类的话,就会报错,所以是不行的。
39 //        list.add(new Animal());
40 //        list.add(new Cat());
41 //        list.add(new MiniCat());
42         for (int i = 0; i < list.size(); i++) {
43             Cat cat = list.get(i);
44             System.out.println(cat);
45         }
46     }
47 }
View Code

3.类型通配符的下限

语法:

类/接口

要求该泛型的类型,只能是实参类型,或实参类型的父类类型。

小案例:

类型通配符
 1 package com.genericity.demo3;
 2 
 3 import java.util.ArrayList;
 4 
 5 /**
 6  * 类型通配符下限方式
 7  */
 8 public class TestDown {
 9     public static void main(String[] args) {
10         ArrayList<Animal> animals= new ArrayList<>();
11         ArrayList<Cat> cats= new ArrayList<>();
12         ArrayList<MiniCat> miniCats= new ArrayList<>();
13 
14         showAnimal(animals);
15         showAnimal(cats);
16 //        showAnimal(miniCats) miniCats类不是Cat类型或者Cat类型的父类
17 
18     }
19 
20     /**
21      * 泛型下限通配符,传递的集合类型,只能是Cat或者Cat的子类类型
22      * @param list
23      */
24     public static void showAnimal(ArrayList<? super Cat> list){
25         //注意:使用类型通配符下限的这种方式是能添加元素的
26 //        list.add(new Animal()); Cat的父类元素是不能添加的,是能添加子类对象的
27         list.add(new Cat());
28         list.add(new MiniCat());
29         /**
30          * 注意:使用类型通配符下限的这种方式,返回值类型是Object类型,因为所有类的父类都是Object
31          */
32         for (int i = 0; i < list.size(); i++) {
33             Object object = list.get(i);
34             System.out.println(object);
35         }
36     }
37 }
View Code

小案例:通过对TreeSet的讲解,进一步加深对类型通配符上下限的理解

类型通配符
 1 package com.genericity.demo4;
 2 
 3 public class Animal {
 4     public String name;
 5 
 6     public Animal(String name) {
 7         this.name = name;
 8     }
 9 
10     @Override
11     public String toString() {
12         return "Animal{" +
13                 "name='" + name + '\'' +
14                 '}';
15     }
16 }
View Code 类型通配符
 1 package com.genericity.demo4;
 2 
 3 public class Cat extends Animal {
 4     public int age;
 5 
 6     public Cat(String name, int age) {
 7         super(name);
 8         this.age = age;
 9     }
10 
11     @Override
12     public String toString() {
13         return "Cat{" +
14                 "age=" + age +
15                 ", name='" + name + '\'' +
16                 '}';
17     }
18 }
View Code 类型通配符
 1 package com.genericity.demo4;
 2 
 3 public class MiniCat extends Cat {
 4     public int level;
 5 
 6     public MiniCat(String name, int age, int level) {
 7         super(name, age);
 8         this.level = level;
 9     }
10 
11     @Override
12     public String toString() {
13         return "MiniCat{" +
14                 "level=" + level +
15                 ", age=" + age +
16                 ", name='" + name + '\'' +
17                 '}';
18     }
19 }
View Code 类型通配符
 1 package com.genericity.demo4;
 2 
 3 import java.util.Comparator;
 4 import java.util.TreeSet;
 5 
 6 /**
 7  * 讲解TreeSet 类型上下限通配符的使用
 8  */
 9 public class Test {
10     public static void main(String[] args) {
11         /**
12          * 分别传入自己定义的不同的比较器Comparator1 Comparator2 Comparator3
13          */
14         TreeSet<Cat> treeSet=new TreeSet<>(new Comparator1());
15         treeSet.add(new Cat("jerry",20));
16         treeSet.add(new Cat("amy",22));
17         treeSet.add(new Cat("frank",35));
18         treeSet.add(new Cat("jim",15));
19         for (Cat cat : treeSet) {
20             System.out.println(cat);
21         }
22     }
23 }
24 
25 class Comparator1 implements Comparator<Animal>{
26 
27     @Override
28     public int compare(Animal o1, Animal o2) {
29         return o1.name.compareTo(o2.name);
30     }
31 }
32 class Comparator2 implements Comparator<Cat>{
33 
34     @Override
35     public int compare(Cat o1, Cat o2) {
36         return o1.age-o2.age;
37     }
38 }
39 class Comparator3 implements Comparator<MiniCat>{
40 
41     @Override
42     public int compare(MiniCat o1, MiniCat o2) {
43         return o1.level-o2.level;
44     }
45 }
View Code
使用Comparator1 运行结果:

Cat{age=22, name='amy'}
Cat{age=35, name='frank'}
Cat{age=20, name='jerry'}
Cat{age=15, name='jim'}   

由此可以看出是按照  a   f   je  ji 排列的

使用Comparator2 运行结果:

Cat{age=15, name='jim'}
Cat{age=20, name='jerry'}
Cat{age=22, name='amy'}
Cat{age=35, name='frank'}

由此可以看出是按照 10  20  22  35由小到大 排列的

使用Comparator3 会出现编译错误:

原因:(使用源码分析)
public TreeSet(Comparator<? super E> comparator) {
    this(new TreeMap<>(comparator));
}
由此可以看出:这里要传入的比较器必须得是Cat或者Cat的父类才行,而MiNiCat不是Cat的父类。

 

上一篇:Echelon/艾美捷——抗体、分析检测试剂盒、抑制剂等


下一篇:python期末大作业-图形化爬虫