【问题标题】:Java: Can't to generic List<? extends Parent> mylistJava:不能通用 List<?扩展父> mylist
【发布时间】:2025-11-23 09:50:01
【问题描述】:

另一个示例非常复杂,我根本不明白,我的问题在某种程度上很相似,但正如我所说,它更简单,可能会产生更简单的答案

public List<? extends Parent> myfunction(List<? extends Parent> mylist){
       mylist.add(new Child())  ; //Doesn't Compile
}

【问题讨论】:

  • 向我们展示如何声明子类和父类。另外,我建议始终将第一个大写字母用于任何类名。

标签: java list generics inheritance collections


【解决方案1】:

我相信您正在寻找一种方法,该方法接受一个列表,向其中添加一些内容,然后返回该列表。该列表是通用的,您希望返回类型与参数的类型相匹配。

在一般情况下,您是这样做的:

public <T extends Parent> List<T> myfunction(List<T> myList) {
   ... // Add something to myList
   return myList;
} 

具体来说,您正在尝试将new Child() 添加到myList。这行不通。 myfunction() 可以用多种列表调用,而添加new Child() 只能在列表是List&lt;Parent&gt;List&lt;Child&gt; 时起作用。下面是一个不同类型列表的示例:

public static class Parent {}  
public static class Child extends Parent {}  
public static class OtherChild extends Parent {}

public <T extends Parent> List<T> myfunction(List<T> myList) {
  myList.add(new Child());
  return myList;
} 

myfunction(new ArrayList<OtherChild>());

在最后一行中,myfunction() 使用 OtherChild 对象的列表调用。显然,将Child 对象添加到这样的列表中是非法的。编译器通过拒绝 myfunction() 的定义来防止这种情况发生

附录

如果您希望myfunction() 能够将元素添加到myList,则需要使用工厂(因为Java 不允许new T() 其中T 是类型参数-由于type erasure)。 myfunction() 应该是这样的:

public interface Factory<T> {
  public T create();
}

public <T extends Parent> List<T> myfunction(List<T> myList, 
                                             Factory<? extends T> factory) {
  myList.add(factory.create());
  return myList;
} 

现在,它的用法:

public static class ChildOfOtherChild extends OtherChild {}

myfunction(new ArrayList<OtherChild>(), new Factory<ChildOfOtherChild>() {
    @Override public ChildOfOtherChild create() { return new ChildOfOtherChild(); }
  });
}

【讨论】:

  • 这样好多了,但是如何创建 T 类型的元素呢?
  • 这不能在 Java 中工作。您不能在 T 是类型参数的情况下执行 new T()。您可以使用工厂来克服这个问题(我正在为讨论这个问题的答案写一个附录)
【解决方案2】:

List&lt;? extends Parent&gt; 的意思是“一个列表,其中仅包含 Parent 的某个未知子类的实例” - 由于您不知道它是什么子类,因此您不能将除 null 之外的任何内容添加到列表(不过,您可以从中获取 Parent 实例)。

如果您有一个特定的子类Child 想要将其实例添加到列表中,那么您真正需要的是:

public List<Child> myfunction(List<Child> mylist)

【讨论】:

  • “不能添加任何东西”并不完全正确。您可以添加null
【解决方案3】:

按照 Jon Skeet 在 other question 中的示例,假设您使用过

public List<? extends Fruit> myfunction(List<? extends Fruit> mylist){
       mylist.add(new Apple())  ; //Doesn't Compile
       return myList;
}

然后用

调用它
List<Banana> bananas = new ArrayList<Banana>();
bananas = myfunction(bananas);

您不能将苹果添加到香蕉列表中。

可以做的是

public List<Fruit> addApple(List<Fruit> mylist){
       mylist.add(new Apple())  ; 
       return myList;
}

public List<Fruit> addBanana(List<Fruit> mylist){
       mylist.add(new Banana())  ; 
       return myList;
}

【讨论】:

    【解决方案4】:

    添加return语句怎么样,或者声明返回void的方法...

    【讨论】:

    • 这个例子是为了解释而写的,你可以看到我使用了父子类比,可以随意编辑
    • 是的,这也是这里的问题。
    • 你在说什么?
    • 我指出(6 年前)这段代码无法编译的最明显原因(函数有返回类型但没有返回语句)。