代码之家  ›  专栏  ›  技术社区  ›  Kent

Java泛型<?扩展a>v.s<a>vs<?超级A>[副本]

  •  1
  • Kent  · 技术社区  · 6 年前

    这可能是一个非常愚蠢的问题,但是我不明白为什么编译器会抱怨和编译。

    我有两个非常简单的课程:

    class A {
    }
    
    class B extends A {
    }
    

    现在代码:

    //block1
    List<A> list = new ArrayList<>();
    list.add(new A()); //ok
    list.add(new B()); //ok 
    
    //block2
    List<? extends A> extendList= new ArrayList<>();
    extendList.add(new A()); //not ok, why?
    extendList.add(new B()); //not ok, why?
    
    //block3
    List<? super A> superList = new ArrayList<>();
    superList.add(new A()); //ok
    superList.add(new B()); //ok. why?
    

    我知道它为什么起作用。

    街区2,我有 <? extends A> ,据我所知,列表将接受类型为 A 或其子类型 ,例如 B . 为什么两者 add() 线路故障?错误:

    Error: no suitable method found for add(A)
    method java.util.Collection.add(capture#1 of ? extends A) is not applicable
      (argument mismatch; A cannot be converted to capture#1 of ? extends A)
    method java.util.List.add(capture#1 of ? extends A) is not applicable
      (argument mismatch; A cannot be converted to capture#1 of ? extends A)
    

    3号街区,我有 <? super A> ,据我所知,列表将接受类型为 或超类型 , 是一个 亚型 属于 为什么 add(new B()) 编译?

    我想我可能误解了 super extends 关键词,我做了一些谷歌,但我的怀疑仍然存在。

    甲骨文通用教程中的一句话:( https://docs.oracle.com/javase/tutorial/java/generics/upperBounded.html )

    The term List<Number> is more restrictive than List<? extends Number>
    because the former matches a list of type Number only, whereas the 
    latter matches a list of type Number or any of its subclasses.
    
    3 回复  |  直到 6 年前
        1
  •  4
  •   luk2302    6 年前

    方块2: 据我所知,列表将接受A类型或A子类型的对象,例如B -不!思考一下 ? ,例如,它可能是 class C extends A { } 也就是说 A 也不 B 匹配约束。不能添加 进入具有泛型类型的列表 C .

    区块3:再次思考 ? 现在它可以 或者它的任何一个超级类,所以 Object (或两者之间的任何东西)。自从 当然,它是 也。每个 List 接受 将接受 也。

        2
  •  1
  •   ernest_k Petronella    6 年前

    这里有一个场景来说明这一点。考虑第三类:

    class C extends A {
    }
    
    List<C> cList = new ArrayList<>();
    List<? extends A> extendList = cList; //this is valid. Right? Yes
    

    这样,失败的原因就清楚了。如果 extendList.add(new A()) 如果允许,以下内容也必须合法:

    extendList.add(new B());
    

    但是我们会加上一个 不相容的 类型( B )列在 C )

    原因是边界: <? super A> 保证与 A . 然而, <? extends B> 允许的子类型 这可能是不相容的。

        3
  •  0
  •   Shadov    6 年前

    List<? extends A> extendList= new ArrayList<>(); extendList.add(new A()); //not ok, why? extendList.add(new B()); //not ok, why?

    想象一下你的 A Animal . 现在你有了 List<? extends Animal> 所以你有一个动物列表,它可以是一个列表。 Dog , Cat ,甚至 动物 ,但你不知道是哪一个。你试图插入一些东西(不可能的方式),你不能这样做,因为就像我说的,你不知道列表里是什么。它可能是 List<Cat> 你试图插入一个 进入它。你甚至不能插入 动物 -因为 动物 可以是 谁知道呢。

    你可以 get 从那个列表中,因为你知道从列表中挑选出的任何东西都可以被分配给 动物 ,所以没有问题。注意,在方块3中,你不能从列表中得到任何东西,但是你可以插入——这是另一种方式。

    你可以插入 List<? super Animal> ,因为你知道里面有什么动物或更高的。所以你可以插入 , 动物 ,因为它们都是动物。注意,你不能从列表中得到任何东西。这是一份清单 动物 名单 LivingBeing 例如(动物、人等)。你会把它分配给什么? Human human = list.get(0) -如果那个物体不是人而是动物呢? LivingBeing livingBeing = list.get(0) -如果它不是一个生命的列表,而是一个更高或根本不同的东西,但仍然是 动物 ?

    看一看 Effective Java 3rd edition Koltin in Action -是的,Kotlin,它有一个稍微不同的方法,可以帮助你更好地理解它。科特林语言将所有这些都纳入了干净的规则。