【问题标题】:Read-only view of a Java list with more general type parameter具有更通用类型参数的 Java 列表的只读视图
【发布时间】:2011-02-05 19:40:53
【问题描述】:

假设我有类 Foo 扩展了超类。我明白为什么我不能这样做:

List<Foo> fooList = getFooList();
List<Superclass> supList = fooList;

但是,如果 supList 以某种方式“只读”,我这样做似乎是合理的。然后,一切都将是一致的,因为从 objList 中出来的一切都是 Foo,它是一个超类。

我可能会编写一个 List 实现,它接受一个底层列表和一个更通用的类型参数,然后将所有内容作为更通用的类型而不是特定类型返回。它的作用类似于Collections.unmodifiableList() 的返回,只是类型会更通用。

有没有更简单的方法?

我正在考虑这样做的原因是我正在实现一个接口,该接口要求我返回一个(不可修改的)List,但在内部我需要使用 Foos,所以我有一个 List。我不能只是投射。

【问题讨论】:

  • 能否修改界面返回List&lt;? extends Superclass&gt;?然后它就可以工作了,你不能将东西添加到 ? extends X 列表中。
  • @mmyers:是的,我能做到。如此简单,但不知何故,它从未在我的脑海中出现。如果你想要信用,写下来作为答案,我会选择它。

标签: java generics


【解决方案1】:

扩展 Kylar 的答案:

如果接口被修改为返回List&lt;? extends Superclass&gt;,则返回的列表实际上仍然是只读的(您可以通过强制转换绕过它,但编译器会发出警告)。您可以返回Superclass 的任何子类的List 并且仍然满足接口。

实际代码:

public interface MyInterface {
    List<? extends Superclass> getList();
}

public class Superclass {}
public class Subclass {}

public class MyClass implements MyInterface {
    public List<? extends Superclass> getList() {
        return new ArrayList<SubClass>();
    }
}

现在,我怎么知道应该是? extends Superclass?我记得Josh Bloch's mnemonic

PECS:生产者扩展,消费者超级。

因此,如果您返回的列表是一个生产者(即,您正在从中取出东西但没有放入东西),您可以使用? extends 来概括它。

相反,如果它是一个消费者(即您向其中添加东西但没有将它们拉出),您可以使用? super 来概括它。

如果您将它同时用作生产者和消费者,那么很遗憾您无法概括它。

另见:

【讨论】:

    【解决方案2】:
    List<? extends Superclass> 
    

    可以使用。然后,您可以返回扩展超类的任何项目的列表,如下所示:

    public class MoreGeneric {
    
      public static void main(String[] args) {
    
        List<? extends MyClass> someList;
        someList = new ArrayList<MyClass2>();
    
       }
    
      abstract public static class MyClass{
        abstract void doSomething();
      }
      public static class MyClass2 extends MyClass{
        public void doSomething(){
        }
    
      }
    }
    

    【讨论】:

      【解决方案3】:

      我推荐您参考this 维基百科文章以供进一步阅读。

      简而言之:在 Java 中,类型参数是不变的(既不是协变也不是逆变)。顺便说一句,您对不变性等的观察是正确的。 wiki article link

      附: 如果您对在 JVM 上运行的具有更灵活类型系统的语言感兴趣,您可能需要查看 Scala。

      【讨论】:

        【解决方案4】:

        你可以这样做,只需投射

        List<Superclass> supList = (List) fooList;
        

        当你这样做时要小心,因为如果 Foo 不是 Superclass 的子类,那么你会得到一个运行时强制转换异常

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-02-16
          • 1970-01-01
          • 2012-07-25
          • 1970-01-01
          • 2019-01-08
          • 1970-01-01
          • 2020-11-16
          • 1970-01-01
          相关资源
          最近更新 更多