我有一个班级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>
。我可以忍受它,但为什么会发出警告?)
答案 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<>();
因此您可以添加任何类型的水果,例如Apple
或Banana
。
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编译器,我知道你想要保护我的可能问题,但我知道我在做什么”,这就是为什么你会看到警告而不是编译错误。