将数据添加到通用?扩展列表

时间:2013-01-06 12:31:44

标签: java generics

  

可能重复:
  Java ArrayList of ? extends Interface

有这段代码:

public static class B1 {}
public static class B2 extends B1 {}
public void fun() {
    List<? extends B1> l3 = new ArrayList<>();
    l3.add(new B2());
}

编译错误:

java: no suitable method found for add(Main.B2)
    method java.util.List.add(int,capture#1 of ? extends Main.B1) is not applicable
      (actual and formal argument lists differ in length)
    method java.util.List.add(capture#1 of ? extends Main.B1) is not applicable
      (actual argument Main.B2 cannot be converted to capture#1 of ? extends Main.B1 by method invocation conversion)

我想? extends B1表示从B1 延伸的任何类型。似乎B2类型从B1扩展,那么为什么这种类型的对象不能添加到列表中以及如何使它可以添加呢?

5 个答案:

答案 0 :(得分:7)

  

我想? extends B1表示从B1 延伸的任何类型。

没有。它意味着“从B1延伸的特定但未知的类型”。由于特定类型未知,编译器无法强制执行,因此add之类的操作不起作用。 *

请参阅tutorial on wildcards

  

如何制作它以便可以添加?

基本上,不要使用通配符。你可能想要这个:

List<B1> l3 = new ArrayList<B1>();

<小时/> *嗯,它们确实有效,但仅适用于null(以及其他一些案例,请参阅下面的@Marko评论)。

答案 1 :(得分:2)

? extends B1表示:某种类型正在或延伸B1,但我们不知道哪一个。因此列表可以是List<B1>,或List<B2>List<B3>(假设B3也扩展为B1)。并且您不希望将B2添加到List<B3>,因此编译器禁止它。

您可能需要List<B1>

答案 2 :(得分:1)

所以我想要一个B1类型的元素列表。 B1的每个孩子都可以保存在B1列表中,如下所示:

public static class B1 {}
public static class B2 extends B1 {}
public void fun() {
    List<B1> l3 = new ArrayList<>();
    l3.add(new B2());
}

答案 3 :(得分:0)

使B1和B2实现相同的接口,例如B(甚至可以为空),然后声明列表&lt; B&gt;代替。您可以毫无问题地添加和删除成员。

直接继承的主要问题可归纳为:

class B1 {};
class B2 extends B1{};

ArrayList<B2> list;

addMembers(list); // Error here

void addMembers(ArrayList<B1> list) {
  list.add(new B1());
}

这里我们声明一个B2的列表,并将其作为参数传递给期望B1列表的方法。因为每个B2也是B1,所以它应该是直观的。但是现在,在这种方法中,将B1添加到传递的列表中也是合法的。方法返回时,集合将被破坏,包含声明不允许的成员B1。

为防止这种情况,编译器不允许使用“兼容的继承类型”集合调用addMembers。我发现这是一个非常讨厌的限制,可以通过使用所提出的接口轻松解决。使用通配符来实现这一点非常复杂。你认为你可以写? extends B1

void test() {
    ArrayList<? extends B1> list = new ArrayList();
    list.add(new B1()); // Error here
    list.add(new B2()); // Error here
    test2(list);
}

void test2(ArrayList<? extends B1> list) {
    list.add(new B1()); // Error here, the collection is read only.
}

这就是我说的,这些通配符不值得所涉及的痛苦。你也可以写ArrayList<? extends java.lang.Object> 甚至ArrayList< ? > ,但没有帮助,这样的声明仍然使这个集合只读。

因此,我会说,更好

interface B {};
class B1 implements B {};
class B2 extends B1 implements B {};  

ArrayList<B> list = new ArrayList<B>();
list.add(new B1());
list.add(new B2());
test2(list);

void test2(ArrayList<B> list) {
    list.add(new B1());
}

答案 4 :(得分:0)

由于这个问题已经得到解答,但我还想在这里添加一些有价值的东西。正如大家所建议做的那样

List<B1> l3 = new ArrayList<B1>();

多数民众赞成。但是为了理解你应该在下面尝试的逻辑,它不会给出任何错误。

public void fun() {
    List<? extends B1> l3 = new ArrayList<>();
    List list1= new ArrayList();
    list1.add(Element1 extending B1);
    list1.add(Element2 extending B1);
    l3=list1;
}

 or you can also try
public void fun() {
        List<? extends B1> l3 = new ArrayList<>();
        List<B1> list1= new ArrayList();
        list1.add(B1 element);
        l3=list1;
    }

所以你的下面的陈述是真实的,但是对于赋值不是为了添加方法。简而言之,对于添加操作,它必须是非常未知的类型(如null),但

  

? extends B1表示从B1扩展的任何类型。