(14)Java 中,泛型通配符 <?> 的使用,<? extend X> 和 <? super X> 的使用区别和使用场景?

结论:

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、提出需求
  1. 实现一个方法,可以处理 List<Dog> 和 List<Cat> 参数,但是不能够处理 List<Person> 类型的参数?

  2. 在需求 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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值