【问题标题】:Implementing Iterable by returning an Iterator over a sub-type通过在子类型上返回 Iterator 来实现 Iterable
【发布时间】:2014-12-19 12:52:41
【问题描述】:

在以下代码中:

public class Bar { ... }

public class Foo extends Bar { ... }

public class BarIterable implements Iterable<Bar> {

    List<Foo> foos = ...

    @Override
    public Iterator<Bar> iterator() {
        return foos.iterator();  // Error: Type mismatch ...
    }
}

由于foos.iterator() 返回的是Iterable&lt;Foo&gt; 而不是Iterable&lt;Bar&gt;,因此我在指定位置出现错误。不幸的是,简单的演员阵容是行不通的:

return (Iterator<Bar>) foos.iterator();  // Error: Cannot cast ...

Java 也不允许我将 BarIterable 的定义更改为

public class BarIterable implements Iterable<? extends Bar> { ...   // Error: A supertype may not specify any wildcard

涉及实现Iterable&lt;Foo&gt;(Iterable-implementation 来自另一个不了解 Foo 的接口)的解决此问题的好方法是什么?

我是否必须为自己编写一个“解包”每个值的包装迭代器类?

【问题讨论】:

  • 我不确定,但看起来您正在实现继承,并且这一行 public class BarIterable implements Iterable&lt;Bar&gt; 应该改为 public class BarIterable extends Iterable&lt;Bar&gt;,除非我弄错了。
  • @AlvinBunk Iterable 是一个接口,所以我肯定需要使用implements,而不是extends
  • 你是怎么得到foos的?
  • 好的,你能发布更多你的代码以便我在 Eclipse 中试用吗?
  • 你不能把你的foos改成List&lt;Bar&gt; foos吗?

标签: java generics iterable


【解决方案1】:

由于FooBar 的子类型,您可以只转换List

return ((List<Bar>)(List<? extends Bar>) foos).iterator(); 

并抑制警告。

由 Markus A. 编辑:

或者,您可以使用中间转换技巧直接转换迭代器:

return (Iterator<Bar>)(Iterator<? extends Bar>) foos.iterator();

结束编辑


使用 Java 8,您可以对元素进行流式传输并构造一个新的 List 类型为 Bar

@Override
public Iterator<Bar> iterator() {
    return foos.stream().<Bar>map((foo) -> foo /* considered a Bar */).collect(Collectors.toList()).iterator();  
}

但您执行大量中间操作只是为了从超类型的角度查看 List

【讨论】:

  • 我们去!惊人的!我正在尝试列表转换,但它没有让我这样做,但我不知道使用? extends 通过中间转换间接转换转换的技巧。好的!谢谢!
  • 其实你可以直接这样转换迭代器!
猜你喜欢
  • 2020-01-24
  • 2011-08-15
  • 1970-01-01
  • 2015-12-13
  • 2015-12-09
  • 1970-01-01
  • 1970-01-01
  • 2022-11-10
  • 1970-01-01
相关资源
最近更新 更多