zoukankan      html  css  js  c++  java
  • Java 泛型通配符详解

      1 package com.wenhui.arithmetic.pecs;
      2 
      3 /**
      4  * Created by wenhui.yu on 2019/4/18.
      5  */
      6 public class Problem {
      7     static class Fruit {
      8     }
      9 
     10     static class Apple extends Fruit {
     11     }
     12 
     13     static class Banana extends Fruit {
     14     }
     15 
     16     static class GreenApple extends Apple{
     17     }
     18 
     19     public static void main(String[] args) {
     20 //        shouldRight();
     21         shouldDo();
     22     }
     23 
     24     /**
     25      * 逻辑上应该是这样玩的
     26      */
     27     public static void shouldRight() {
     28         Apple apple = new Apple();
     29         /**
     30          * 定义一个果盘,逻辑上果盘内是可以放苹果的,看似操作没有问题
     31          *
     32          * 编译器报错
     33          * 不兼容的类型:
     34          * com.wenhui.arithmetic.pecs.Plate<com.wenhui.arithmetic.pecs.Apple>无法转换为
     35          *      com.wenhui.arithmetic.pecs.Plate<com.wenhui.arithmetic.pecs.Fruit>
     36          *
     37          * 原因:
     38          *   泛型不符合里氏替换原则,或者说不是协变的
     39          * 编译器认为:
     40          *  苹果 is a 水果
     41          *  装苹果的盘子 not is a 装水果的盘子
     42          */
     43         Plate<Fruit> fruitPlate = new Plate<Apple>(apple);
     44 
     45         /**
     46          * 非泛型(如数组)是支持合里氏替换原则,或者说协变的
     47          *
     48          * 支持插入子类的子类
     49          */
     50         Fruit[] fruits = new Apple[]{apple, new GreenApple()};
     51 
     52     }
     53 
     54     /**
     55      * 实际上是要这样玩的
     56      */
     57     public static void shouldDo() {
     58         /**
     59          * 一个能放水果及其子类的盘子
     60          *
     61          * 副作用:
     62          *  set方法失效
     63          */
     64         Plate<? extends Fruit> fruitPlate1 = new Plate<Apple>(new Apple());
     65 //        放子类的子类(苹果的子类青苹果)同样支持
     66         Plate<? extends Fruit> fruitPlate2 = new Plate<Apple>(new GreenApple());
     67 
     68         /**
     69          * 编译器报错:
     70          *  Error:(30, 35) java: 不兼容的类型: com.wenhui.arithmetic.pecs.Plate<com.wenhui.arithmetic.pecs.Apple>无法转换为
     71          *      com.wenhui.arithmetic.pecs.Plate<com.wenhui.arithmetic.pecs.Fruit>
     72          *  Error:(54, 29) java: 不兼容的类型:
     73          *      com.wenhui.arithmetic.pecs.Apple无法转换为capture#1, 共 ? extends com.wenhui.arithmetic.pecs.Fruit
     74          *  解析:
     75          *  原因是编译器只知道容器内是Fruit或者它的派生类,但具体是什么类型不知道。
     76          *  可能是Fruit?可能是Apple?也可能是Banana,GreenApple或者其他
     77          *  编译器在看到后面用new Plate赋值以后,盘子里没有被标上Apple,而是标上一个占位符(capture#1),来表示捕获Fruit类或其子类
     78          *  所以无论是想插入Apple或者其他,编译器都不知道能不能和capture#1匹配
     79          *  为了类型安全,所以阻止想其中加入任何子类
     80          */
     81         fruitPlate1.setItem(new Apple());
     82 //        get方法正常
     83         Fruit item = fruitPlate1.getItem();
     84 
     85         /**
     86          * 一个能放苹果及其父类的盘子
     87          *
     88          * 副作用:
     89          *  get方法失效
     90          */
     91         Plate<? super Apple> fruitPlate3 = new Plate<Fruit>(new Fruit());
     92 //        set 方法正常
     93         fruitPlate3.setItem(new Apple());
     94         /**
     95          * 同理:
     96          *  因为允许放苹果及其所有父类,所以get 的时候,不能确认到底是那个父类,所以只有Object对象能接收
     97          */
     98         Object item1 = fruitPlate3.getItem();
     99         System.out.println(item1);
    100 
    101         /**
    102          * 总结:
    103          *  1: 如果要从集合中读取类型T的数据,并且不能写入,可以使用 ? extends T;(Producer Extends)
    104          *  2: 如果要从集合中写入类型T的数据,并且不需要读取,可以使用 ? super T;(Consumer Super)
    105          *  3: 没事不要用泛型通配符
    106          */
    107     }
    108 }

    容器类(Plate)

     1 package com.wenhui.arithmetic.pecs;
     2 
     3 /**
     4  * 盘子
     5  * @param T 盘子中放的物品
     6  * Created by wenhui.yu on 2019/4/18.
     7  */
     8 public class Plate<T> {
     9     private T item;
    10 
    11     public T getItem() {
    12         return item;
    13     }
    14 
    15     public void setItem(T item) {
    16         this.item = item;
    17     }
    18 
    19     public Plate(T item) {
    20         this.item = item;
    21     }
    22 }
  • 相关阅读:
    java课程之团队开发冲刺阶段1.10
    java课程之团队开发冲刺阶段1.9
    java课程之团队开发之用户模板和用户场景
    大二第二学期周学习进度总结(八)
    java课程之团队开发冲刺阶段1.8
    java课程课后作业190425之一维数组最大子数组—功能扩展(界面实现)
    java课程之团队开发冲刺阶段1.7
    java课程之团队开发冲刺阶段1.6
    Python函数-高级(闭包/装饰器)
    Python之函数
  • 原文地址:https://www.cnblogs.com/yuwenhui/p/10729237.html
Copyright © 2011-2022 走看看