具有更一般类型参数的Java列表的只读视图

时间:2010-04-08 17:22:56

标签: java generics

假设我有类Foo扩展超类。我理解为什么我不能这样做:

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

但是,如果supList以某种方式“只读”,那对我来说似乎是合理的。然后,一切都会保持一致,因为objList中出现的所有东西都是Foo,这是一个超类。

我可能会编写一个List实现,它将获取一个基础列表和一个更通用的类型参数,然后将所有内容作为更一般的类型而不是特定类型返回。它会像Collections.unmodifiableList()的返回一样工作,除了类型会更加通用。

有更简单的方法吗?

我正在考虑这样做的原因是我正在实现一个接口,要求我返回一个(不可修改的)List&lt; Superclass&gt;,但在内部我需要使用Foos,所以我有一个List&lt; Foo&gt;。我不能只是演员。

4 个答案:

答案 0 :(得分:5)

扩展Kylar的回答:

如果修改了接口以返回List<? extends Superclass>,则返回的列表仍然是有效的只读(您可以通过强制转换来解决它,但编译器会发出警告)。并且您可以返回List的任何子类Superclass并仍然满足该接口。

实际代码:

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对其进行概括。

如果您将其用作生产者和消费者,遗憾的是您无法概括它。

另见:

答案 1 :(得分: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(){
    }

  }
}

答案 2 :(得分:1)

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

简而言之:在Java中,类型参数是不变的(既不是共同变体也不是变体)。你对不变性的观察是正确的,顺便说一下。 wiki article link

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

答案 3 :(得分:0)

你可以这样做,只是施展

List<Superclass> supList = (List) fooList;

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