java—将实现接口的泛型列表分配给同一接口的列表

oxalkeyp  于 2021-07-04  发布在  Java
关注(0)|答案(2)|浏览(227)

这个问题是关于接口与实现接口的类之间的关系。我看不出这个或这个如何回答这个问题。
我创建了一个接口 Boxed 和一个抽象泛型类 Box ,实现接口。然后我创建了两个具体的类 IntegerBox 以及 StringBox . 然后我创建了一个元素列表 Box 带着一个 IntegerBox 值和a StringBox 价值观。到现在为止,一直都还不错。
现在我要分配 List<? extends Box>List<Boxed> . 我的期望是,这应该是有效的,因为无论什么 Box 工具也 Boxed . 但是编译器不允许我。这是错误:

main.java:29: error: incompatible types: List<CAP#1> cannot be converted to List<Boxed>
    List<Boxed> lb2 = laeb; // does not compile, although every value which extends Box implements Boxed
                      ^
  where CAP#1 is a fresh type-variable:
    CAP#1 extends Box from capture of ? extends Box
1 error

我可以复制列表:

List<? extends Box> laeb = List.of (new IntegerBox(42), new StringBox("answer"));
List<Boxed> lb1 = new ArrayList<> (laeb);

类型的每个元素 ? extends Box 如果类型 Boxed . 但分配报告的类型不兼容。为什么?

import java.util.List;
import java.util.ArrayList;

public class main
{
  static interface Boxed { }

  static abstract class Box<T> implements Boxed
  {
    T content;
    Box (T content) { this.content = content; }
  }

  static class IntegerBox extends Box<Integer> { IntegerBox (Integer content) { super (content); } }
  static class StringBox  extends Box<String>  { StringBox  (String content)  { super (content); } }

  public static void main (String ...arguments) throws Exception
  {
    IntegerBox i = new IntegerBox(42);
    StringBox  s = new StringBox("answer");

    List<? extends Box> laeb = List.of (i, s);

    Boxed b0 = i;  // => IntegerBox is compatible with Boxed
    Boxed b1 = s;  // => StringBox  is compatible with Boxed

    List<Boxed> lb1 = new ArrayList<> (laeb); // List<Boxed> can be created by values of "? extends Box"

    List<Boxed> lb2 = laeb; // does not compile, although every value which extends Box implements Boxed
  }
}
kmbjn2e3

kmbjn2e31#

考虑一下:

List<StringBox> stringBoxList = new ArrayList<StringBox>();
List<? extends Box> boxList = stringBoxList; // works, StringBox extends Box

List<Boxed> boxedList = boxList; // suppose this *did* work
boxedList.add(new IntegerBox(42)); // this line definitely compiles, what does it do?

在最后一行之后, stringBoxList 将包含一个 IntegerBox ,尽管最初是 ArrayList<StringBox> . 那太糟糕了。
这就是编译器正在阻止的。
解决这个问题很简单

List<? extends Boxed> boxedList = boxList;

boxedList.add(new IntegerBox(42));
// forbidden by the compiler, because IntegerBox is not necessarily the _same_ subclass    
// of Boxed as boxedList's elements

或者,你也可以写

List<Boxed> boxedList = Collections.unmodifiableList(boxList);

…因为如果你不能修改列表,问题就会消失。
(但是,坦率地说,list是list的一个子类吗?为什么java泛型不是隐式多态的?涵盖了这一点,但不是 ? extends .)

xxhby3vn

xxhby3vn2#

现在我要分配 List<? extends Box>List<Boxed> .
你不能那样做,因为 List<Boxed> 不是上界通配符的超类型 <? extends Box> .
更改:

List<Boxed> lb2 = laeb;

使用:

List<? extends Boxed> lb2 = laeb;
``` `List<Boxed>` 可以通过以下值创建“ `? extends Box` "
使用:

List lb1 = new ArrayList<>(laeb);

你并不是真的在用 `<? extends Box>` 类型,但您需要使用上面创建的已定义的不可变列表填充新列表- `List.of(i, s);` 请注意: `extends` 具有以下两种语义- `extends` 以及 `implements` 在java泛型中。
注意,在这个上下文中,extends在一般意义上是指“extends”(在类中)或“implements”(在接口中)。
类型擦除同样适用于接口。请参阅docs.oracle中的以下引用:
因此,生成的字节码只包含普通类、接口和方法。

相关问题