结论:
1、<?> 和 表示通配符,类型可以是任何类型,数据只能读不能写,例如 List<?> list;list.add("") 是会报错的。
2、<? extend X> 存储的数据可以是 X 或者 X 的子类,依然只能读取数据不能修改数据。
3、 <? super X> 存储的数据可以 X 或者 X 的子类,并且也可以修改数据。如下代码,在调用 ope2 方法时,传入的真实参数 List 中的类型可以是 Animal 或者 Animal 的父类;但是在 ope2 方法里面修改参数 list 的数据时,存储的数据只能是 Animal 或者 Animal 的子类。
public static void ope2(List<? super Animal> list){
// list.add(new Person("",2));
list.add(new Cat("",Color.BLUE));
}
1、提前准备
给定以下几个类,Animal、Cat、Dog 和 Person。其中 Cat 和 Dog 是 Animal 的子类。
/**
* @author zjj_admin
*/
public class Animal {
}
/**
* @author zjj_admin
*/
public class Cat extends Animal{
private String name;
private Color color;
public Cat(String name, Color color) {
this.name = name;
this.color = color;
}
@Override
public String toString() {
return "Cat{" +
"name=" + name +
", color=" + color +
'}';
}
}
/**
* @author zjj_admin
*/
public class Dog extends Animal{
private String name;
private Color color;
public Dog(String name, Color color) {
this.name = name;
this.color = color;
}
@Override
public String toString() {
return "Dog{" +
"name=" + name +
", color=" + color +
'}';
}
}
/**
* 人
*
* @author zjj_admin
*/
public class Person {
private String name;
private Integer age;
public Person(String name, Integer age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
/**
* 动物的颜色
*
* @author zjj_admin
*/
public enum Color {
RED,
BLACK,
WHITE,
YELLOW,
BLUE;
}
2、提出需求
-
实现一个方法,可以处理 List<Dog> 和 List<Cat> 参数,但是不能够处理 List<Person> 类型的参数?
-
在需求 1 的基础上,给方法提供一个 Consumer 参数,能够将参数 1 的集合,按照对象打印或者按照动物打印?
给出几个方法,分别返回 Dog、Cat 和 Person 数据集合。
public static List<Dog> getDogs() {
return List.of(
new Dog("旺财", Color.BLACK),
new Dog("来福", Color.RED)
);
}
public static List<Cat> getCats() {
return List.of(
new Cat("大橘", Color.YELLOW),
new Cat("肥瞄", Color.BLUE)
);
}
public static List<Person> getPersons() {
return List.of(
new Person("小美", 16),
new Person("李科", 23)
);
}
3、问题解决
3.1、实现一个方法,可以处理 List<Dog> 和 List<Cat> 参数,但是不能够处理 List<Person> 类型的参数?
public static void ope(List<? extends Animal> list) {
for (Animal animal : list) {
System.out.println(animal);
}
}
使用 List<? extends Animal> 表示集合中的数据类型为 Animal的子类 或者 Animal 本身,而不能够是 List<Person>,因为 Person 和 Animal 没有关系。
若参数格式是 List<?> ,那么所有的类型就都可以进行匹配,就不满足需求了。
若参数不指定类型,就直接使用 List ,效果和使用 List<?> 是一样的。
3.2、在需求 1 的基础上,给方法提供一个 Consumer 参数,能够将参数 1 的集合,按照对象打印或者按照动物打印?
/**
* ? super Animal 表示外部容器可以执行写操作
* ? super Animal 里面的数据类型是 Animal 或者 Animal 的父类
*
* @param list
* @param consumer
*/
public static void opeC(List<? extends Animal> list, Consumer<? super Animal> consumer) {
for (Animal animal : list) {
consumer.accept(animal);
}
}
给出两个 Consumer 方法,如下,功能是当 Consumer 中的类型是 Object 或者 Animal 类型就按照不同的格式打印数据
public static void main(String[] args) {
Consumer<Object> c1 = obj -> System.out.println(obj.getClass().getName() + "@" + obj.hashCode());
Consumer<Animal> c2 = animal -> System.out.println(animal.toString());
opeC(getDogs(), c1);
opeC(getCats(), c2);
}
//运行结果
com.zjj.learn.mls.s2.day13.Dog@1480010240
com.zjj.learn.mls.s2.day13.Dog@793589513
Cat{name=大橘, color=YELLOW}
Cat{name=肥瞄, color=BLUE}
Process finished with exit code 0