可继承的继承

时间:2014-05-29 01:18:01

标签: java

我有一个班级Super和班级Sub,其中Sub extends Super

我试图编写一个包含Sub列表但必须实现Iterable<Super>的类。我试图做的是:

class Bag implements Iterable<Super> {
     List<Sub> list;

     public Iterator<Super> iterator() {
          return list.iterator();
     }
 }

这不编译(错误消息为Cannot cast from Iterator<Sub> to Iterator<Super>)。我试过在几个地方投掷,在其他地方试过通配符,但我不知道问题是什么。我当然不明白为什么

public Iterator<Super> iterator() {
    return (Iterator<Super>)list.iterator();
}

不会施展。这有可能 java iterator/iterable subinterface有解决方案,但我不理解。

/////更新

我设法这样做了:

Iterator<? extends Super> iterator = ((List<? extends Super>)list).iterator();
return (Iterator<Super>)iterator;

(发出警告,Type safety: Unchecked cast from Iterator<capture#4-of ? extends Super> to Iterator<Super>。我可以忍受它,但为什么会发出警告?)

2 个答案:

答案 0 :(得分:2)

如果你正在使用java 8,一个简单的方法是:

class Bag implements Iterable<Super> {
    List<Sub> list;

    public Iterator<Super> iterator() {
        return list.stream().map(s -> (Super)s).iterator();
    }
}

答案 1 :(得分:0)

  

我当然不明白为什么

List<Sub> list;

public Iterator<Super> iterator() {
    return (Iterator<Super>)sections.iterator();
}
     

不会施放。

考虑您有班级Fruit Apple Banana的情况。您有Fruit s

列表
List<Fruit> list = new ArrayList<>();

因此您可以添加任何类型的水果,例如AppleBanana

list.add(new Apple());
list.add(new Banana());

现在将这样的列表转换为更多指定的类型是安全的,让我们说Apple的列表?没有为什么?请考虑以下示例:

List<Apple> apples = (List<Apple>)list; //lets assume for now that this is OK
for (Apple ap : apples){
    //do something with apple
}

list不仅包含Apple s,还包含Banana,这不是for循环中代码的正确参数。

您可以通过多种方式解决此问题,例如,您可以尝试使用List<? extends Super>之类的通配符。这一切都取决于你实际想要实现的目标。

对您的更新的回应

List<Sub> list;

public Iterator<Super> iterator() {
    Iterator<? extends Super> iterator = ((List<? extends Super>)list).iterator();
    return (Iterator<Super>)iterator;
}

相同
public Iterator<Super> iterator() {
    List<? extends Super> tmp = list;                     //1
    Iterator<? extends Super> iterator = tmp.iterator();  //2
    return (Iterator<Super>) iterator;                    //3
}

在标记为//1的行中,您正在创建List<? extends Super>类型的临时引用,并使用它来处理类型为list的{​​{1}},这是完全正常的,因为{{1 }}意味着保持类型扩展List<Sub>,就像在这种情况下<? extends Super>

在行Super中,您正在使用Sub引用创建迭代器,因此您将获得与此引用具有相同泛型类型的迭代器,因此它是//2

现在问题可能发生在这里

tmp

考虑情况:
您有Iterator<? extends Super>,并希望将其投放到return (Iterator<Super>) iterator; //3 。那会安全吗?不是真的,因为通过List<? extends Super>您可以添加List<Super>类型及其子类型的任何实例,例如List<Super>Super。这意味着如果SubFoo保留SubBar,您就可以添加到此列表中,不仅需要List<? extends Super>,还需要List<SubBar>,这有潜在危险。这就是编译器将告知您潜在危险的原因。

有趣的是,这次你不会看到编译错误,而是警告。这可能是因为明确地将SubBar强制转换为SubFoo是一个很大的捷径,这可能会导致误解,因为程序员可能会忘记可能发生的错误。

使用通配符中的强制转换可能表明你理解泛型足以说“OK编译器,我知道你想要保护我的可能问题,但我知道我在做什么”,这就是为什么你会看到警告而不是编译错误。