V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Kaiv2
V2EX  ›  Java

对 Java 之泛型通配符 ?extends T 的认知 和 ? super T 一些理解

  •  
  •   Kaiv2 ·
    JavaHello · 2022-06-11 00:22:38 +08:00 · 1458 次点击
    这是一个创建于 895 天前的主题,其中的信息可能已经有所发展或是发生改变。
    
    import java.util.ArrayList;
    import java.util.List;
    
    public class App {
    
        class A {
    
        }
    
        class B extends A {
    
        }
    
        class C extends B {
    
        }
    
        class D extends C {
    
        }
    
        public static void main(String[] args) {
            List<A> al = new ArrayList<A>();
            // 无法修改泛型继承关系
            al = new ArrayList<B>(); // 编译错误
            al.add(new A());
            al.add(new B());
            al.add(new C());
            A a = al.get(0);
    
            // 声明 List<? extends A> , 实现可能是 继承 A 的任意类型
            List<? extends A> al1 = new ArrayList<A>() {
                {
                    // 放入子类
                    add(new B());
                }
            };
            al1 = new ArrayList<B>() {
    
                {
                    // 放入子类
                    add(new C());
                }
            };
            al1 = new ArrayList<C>() {
    
                {
                    // 无法放入 B
                    add(new B()); // 编译错误
                    // 放入子类
                    add(new D());
                }
            };
    
            // 虽然编译器知道放入数据一定是继承 A
            // List<? extends A> al1 实现类一定是 List<A> 或 List<A 的子类>
            // 但是用户指定的实现不确定 比如 ArrayList<C> 无法放入 B 类型,会有类型转换错误
            al1.add(new A()); // 编译错误
            al1.add(new B()); // 编译错误
    
            // 因为声明的 List<? extends A>, 编译器确定类型一定是 A
            A x = al1.get(0);
    
            // 声明 List<? super D> , 实现可能是 D 的任意父类, 兼容放入 D 以及子类
            List<? super D> bl1 = new ArrayList<Object>() {
                {
                    // 我放入和 D 类型无关的数据
                    add("");
                    add(new D());
                }
            };
            bl1 = new ArrayList<A>() {
                {
                    add(new A());
                    add(new D());
                }
            };
    
            // 编译器知道实现一定是 D 的父类
            // 支持放入任意 D 和 所有继承 D 的类
            // List<? super D> 声明了编译器只能放入 D 和 D 的实现类型
            bl1.add(new A()); // 编译失败
            bl1.add(new D());
    
            // 编译器无法获取确定实现类支持的数据类型,
            // 因为 List<? super D> bl1 可以是 List<D> 或 List<D 的父类> 的实现装载数据
            // 如果获取类型转换为 D 会有类型转换错误
            D b = bl1.get(0); // 编译错误
            Object o = bl1.get(0); // 所有类型的父类是 Object 所以支持
            // 需要人为强制转换, 有类型转换异常风险
            D b1 = (D) bl1.get(0);
    
        }
    }
    
    
    
    1 条回复    2022-06-11 23:13:33 +08:00
    WangYudi
        1
    WangYudi  
       2022-06-11 23:13:33 +08:00
    感觉可以理解成继承的范围
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5432 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 31ms · UTC 03:30 · PVG 11:30 · LAX 19:30 · JFK 22:30
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.