【问题标题】:Java Generics & Inheritance: Unable to add to ListJava 泛型和继承:无法添加到列表
【发布时间】:2014-10-09 14:21:12
【问题描述】:

假设我有一个 List 定义如下。

private List<? extends GeneralBudgetYearBean> budgetYearBeans;

// + Getters/setters...

为什么我不能在这个类之外普遍引用这个列表如下:

GeneralBudgetYearBean gbyb;
getBudgetYearBeans().add(bgyb);

错误是:

The method add(capture#6-of ? extends GeneralBudgetYearBean) in the type List<capture#6-of ? extends GeneralBudgetYearBean> is not applicable for the arguments (GeneralBudgetYearBean)

这没有意义。是不是因为“?extends T”和“T”不一样,这里不能用“T”代替?

我需要能够在没有具体细节的情况下一般地操作这个类。在某些时候,会在扩展类中构造一个“SUBGeneralBudgetYearBeans”的ArrayList,这就是为什么我需要使用“? extends GeneralBudgetYearBean”表示法。

【问题讨论】:

  • List&lt;GeneralBudgetYearBean&gt; 呢?
  • @sp00m 我不能使用它。正如我所说,会在某个时候构造一个 ArrayList,而“? extends”符号是实现这一目标的唯一方法。
  • @geneb。那不是问题。您仍然可以将SubBudgetYearBeans 添加到List&lt;GeneralBudgetYearBean&gt;

标签: java generics inheritance


【解决方案1】:

根据PESC原则:

只需要获取对象时使用extends,只需要添加对象时使用super。

在你的情况下,

private List<? extends GeneralBudgetYearBean> budgetYearBeans;

是一个producer,这意味着列表将只能produce元素。原因是在编译时编译器不知道 GeneralBudgetYearBean 的子类型,这就是它不允许你添加元素的原因,因为它不能完全确定是否允许。

由于您将(在某些时候)还添加SubBudgetYearBean 对象(我相信它们是GeneralBudgetYearBean 的子类),因此您必须将列表创建为消费者。因此,这对你有用:

private List<? super SubBudgetYearBean> budgetYearBeans;

在这种情况下,您将能够将budgetYearBean 实例化为:

budgetYearBeans = new ArrayList<Object>();
budgetYearBeans = new ArrayList<GeneralBudgetYearBean>();

在这两种情况下,您都可以添加 GeneralBudgetYearBeanSubBudgetYearBean 对象。

【讨论】:

    【解决方案2】:

    当您使用表达式List&lt;? extends GeneralBudgetYearBean&gt; budgetYearBeans; 时,您告诉编译器该变量稍后将收到一个列表,其中X 将扩展GeneralBudgetYearBean。但它不知道它将是什么类,因此 if 不允许您向其中添加任何内容。

    你可以使当前类通用:

    class xxx<T extends GeneralBudgetYearBean> {
        private List<T> budgetYearBeans; // getter and setter
    

    那么你就可以这样做了:

    T gbyb;
    getBudgetYearBeans().add(bgyb);
    

    因为现在你告诉编译器:你不知道它会是什么,但它会是一样的。

    【讨论】:

      【解决方案3】:

      去掉通配符,在这种情况下它们不会真正帮助你,它们只会使事情复杂化,除非你真的知道自己在做什么。

      private List<GeneralBudgetYearBean> budgetYearBeans = ...
      
      public List<GeneralBudgetYearBean> getBudgetYearBeans() {
          return budgetYearBeans;
      }
      

      因为SUBGeneralBudgetYearBean扩展了GeneralBudgetYearBean,所以将它们添加到列表中没有问题...

      SUBGeneralBudgetYearBean sgyb = ...
      getBudgetYearBeans().add(sgyb);
      

      ...或作为列表...

      List<SUBGeneralBudgetYearBean> sgybs = ...
      getBudgetYearBeans().addAll(sgybs);
      

      看到了吗?实际上不需要通配符。 :)

      【讨论】:

      • 不,不是这样。在扩展类中,我必须这样做:setBudgetYearBeans(new ArrayList())。这给出了一个错误。
      • 那么不要在列表中使用 setter。只需使用getBudgetYearBeans().clear(),然后使用getBudgetYearBeans().addAll(subBudgetBeans)
      猜你喜欢
      • 2016-07-03
      • 1970-01-01
      • 2011-03-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多