1

我想将 Iterator 子类化为我称之为 FooIterator 的东西。我的代码看起来像这样:

public class FooIterator<E> implements Iterator<E> {
  public FooIterator(Collection<Bar> bars) {
    innerIterator = bars.iterator();
  }

  @Override
  public boolean hasNext() {
    return innerIterator.hasNext();
  }

  @SuppressWarnings("unchecked")
  @Override
  public E next() {
    Bar bar = innerIterator.next();
    return new E(bar);
  }

  @Override
  public void remove() {
    throw new UnsupportedOperationException("Don't remove from FooIterator!");
  }

  private Iterator<Bar> innerIterator;
}

...除了,当然,这不起作用,因为我不能从 Bar 实例化一个新的 E。

我只会将它与具有带 Bar 的构造函数的 E 一起使用。有什么方法可以向编译器“证明”这一点,或者如果 E 没有适当的构造函数则只抛出运行时错误?

或者也许我只是没有在这里使用正确的设计模式?我最近一直在做很多 C++,我觉得我可能以错误的方式处理这个问题。

4

4 回答 4

3

这是一种有点复杂的方法,但它可以工作并且类型安全(使用反射的解决方案不会)。E它基本上包括将a的构造委托Bar给一个单独的类。你可以有一个BarConverter界面:

interface BarConverter<E> {
    E convert (Bar bar);
}

那么你的班级可能会变成:

public class FooIterator<E> implements Iterator<E> {

    public FooIterator(Collection<Bar> bars, BarConverter<E> converter) {
        innerIterator = bars.iterator();
        this.converter = converter;
    }

    @Override
    public E next() {
        Bar bar = innerIterator.next();
        return converter(bar);
    }
}
于 2013-08-07T23:06:01.580 回答
1

不可能像这样实例化类型参数。

一种解决方法是在构造函数中传递Class<E>类型参数,以及Collection<Bar>

private Class<E> clazz;

public FooIterator(Collection<Bar> bars, Class<E> clazz) {
    this.clazz = clazz;
    innerIterator = bars.iterator();
}

然后在next()方法中,您可以利用反射来创建以下实例E

@SuppressWarnings("unchecked")
@Override
public E next() {
    Bar bar = innerIterator.next();

    E instance = null;
    try {
        instance = clazz.getConstructor(Bar.class).newInstance(bar);

    } catch (Exception e) {  
        e.printStackTrace();
    }

    if (instance == null) {
        // throw an unchecked exception    
    }

    return instance;
}

PS:通常,您应该比我在这里使用的更好的异常处理。为简洁起见,我刚刚捕获了所有异常Exception。在实践中,您应该为每个特定异常设置 catch 块。

e.printStackTrace()此外,您可以记录一些有用的消息,而不是使用。

在实例化FooIterator时,您需要传递一个额外的参数 - 您正在为其创建迭代器的类。

于 2013-08-07T23:02:59.363 回答
0

这感觉有点 hacky,但是使用一个接口和一个简单地构造自己的方法,你可以这样做:

interface Barable
{
    Barable construct(Barable bar);
}

class Bar implements Barable
{
    Bar(Barable bar)
    {
        //Do stuff
    }

    @Override
    public Barable construct(Barable bar)
    {
        return new Bar(bar);
    }
}

class FooIterator<E extends Barable> implements Iterator<E>
{
    public FooIterator(Collection<Bar> bars)
    {
        innerIterator = bars.iterator();
    }

    @Override
    public boolean hasNext()
    {
        return innerIterator.hasNext();
    }

    @SuppressWarnings("unchecked")
    @Override
    public E next()
    {
        Bar bar = innerIterator.next();
        return (E) bar.construct(bar);
    }

    @Override
    public void remove()
    {
        throw new UnsupportedOperationException("Don't remove from FooIterator!");
    }
    private Iterator<Bar> innerIterator;
}
于 2013-08-07T23:04:14.863 回答
0

一种可能的解决方案是参数化Bar并向其添加方法以创建新的E. 像这样的东西:

class Bar<E> {

    // ... more implementation ...

    public E build() {
        // create your `E` object here
    }

}

然后你的代码会做这样的事情:

public class FooIterator<E> implements Iterator<E> {

    public FooIterator(Collection<Bar<E>> bars) {
        innerIterator = bars.iterator();
    }

    @Override
    public boolean hasNext() {
        return innerIterator.hasNext();
    }

    @SuppressWarnings("unchecked")
    @Override
    public E next() {
        Bar<E> bar = innerIterator.next();
        return bar.build();
    }

    @Override
    public void remove() {
        throw new UnsupportedOperationException("Don't remove from FooIterator!");
    }

    private Iterator<Bar<E>> innerIterator;
}
于 2013-08-07T23:06:34.663 回答