【问题标题】:Why can't a method take a Collection<subClass> when the method's signature is defined as Collection<class>当方法的签名定义为 Collection<class> 时,为什么方法不能采用 Collection<subClass>
【发布时间】:2011-10-21 08:34:46
【问题描述】:

我有一个采用 SResource 对象列表的方法

public static List<STriple> listTriples(List<SResource> subjects){
//... do stuff
}

为什么我不能这样做

List<IndexResource> resultsAsList = new ArrayList<IndexResource>();
    resultsAsList.addAll(allResults.keySet()); // I could possible not use lists and just use sets and therefore get rid of this line, but that is a different issue
List<STriple> triples = new ArrayList<STriple>();
    triples = TriplesDao.listTriples(resultsAsList);

(编译器告诉我我必须让triples 使用 SResource 对象。)

当 IndexResource 是 SResource 的子类时

public class IndexResource extends SResource{ 
// .... class code here
}

我原以为这是可能的,所以也许我做错了什么。如果您建议,我可以发布更多代码。

【问题讨论】:

    标签: java inheritance collections


    【解决方案1】:

    你可以做到,使用wildcards:

    public static List<STriple> listTriples(List<? extends SResource> subjects){
        //... do stuff
    }
    

    新的声明使用了一个有界通配符,它表示泛型参数要么是SResource,要么是扩展它的类型。

    以这种方式接受List&lt;&gt; 作为交换,“做事”不能包括插入subjects。如果您只是从方法中的subjects 读取,那么此更改应该会为您提供所需的结果。

    编辑:要了解为什么需要通配符,请考虑以下代码(在 Java 中是非法的):

    List<String> strings = new ArrayList<String>();
    List<Object> objList = string; // Not actually legal, even though string "is an" object
    objList.add(new Integer(3)); // Oh no! We've put an Integer into an ArrayList<String>!
    

    这显然不是类型安全的。但是,使用通配符,您可以这样做:

    List<String> strings = new ArrayList<String>();
    string.add("Hello");
    List<? extends Object> objList = strings; // Works!
    objList.add(new Integer(3)); // Compile-time error due to the wildcard restriction
    

    【讨论】:

    • 它确实让我觉得这是一个基本的继承功能,应该内置在正常语法中,但我相信他们这样做是有原因的。
    • 我已经更新了我的答案,以说明如果您不使用通配符会发生什么。
    • 很遗憾,我们无法进行包含少于 6 个字符的更改的编辑
    【解决方案2】:

    您不能这样做,因为generics are not "covariant"List&lt;Integer&gt; 不是List&lt;Number&gt; 的子类,尽管IntegerNumber 的子类。

    【讨论】:

    • 但是你可以通过通配符获得一定程度的协方差。
    • 我明白了……这很有道理:)
    • @dlev: AFAIK,不,这不是协方差,因为在使用通配符时,您明确指定listTriples 可以接受任何扩展SResource 的类型的List,包括它。将其与不使用通配符显示真正协方差的 Java 数组进行比较和对比。
    • 这就是我写“在一定程度上”的原因。 Java 数组协方差通常被认为是损坏的,因为它们没有施加“禁止写入”的限制,因此仍然需要运行时检查以维护类型安全。
    • IMO 它并没有损坏,只是语言设计者出于实际目的必须做出的决定之一。如果 Java 出现时对数组没有写入限制,那么编写任何类型的通用“数组”处理方法将是一件非常痛苦的事情。
    【解决方案3】:

    对于那些无法添加通配符的人来说,这应该可以。

    List<Integer> list = new ArrayList<Integer>();
    new ArrayList<Number>(list);
    

    【讨论】:

      猜你喜欢
      • 2011-02-14
      • 2022-01-18
      • 1970-01-01
      • 2011-08-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-26
      • 2018-03-22
      相关资源
      最近更新 更多