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的父类。