对类型参数做出假设?

时间:2013-08-07 22:50:48

标签: java generics

我想将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.

我只会用一个带有构造函数的E来使用它。有没有办法向编译器“证明”这个,或者如果E没有合适的构造函数就抛出运行时错误?

或者我可能只是没有在这里使用正确的设计模式?我最近做了很多C ++,我觉得我可能会以错误的方式接近它。

4 个答案:

答案 0 :(得分:3)

这是一种有点复杂的方法但它可以工作并且类型安全(使用反射的解决方案不会)。它主要包括将E的构造从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);
    }
}

答案 1 :(得分: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;
}

P.S:一般来说,你应该做一个比我在这里使用的更好的异常处理。为简洁起见,我刚刚在Exception中捕获了所有异常。在实践中,您应该为每个特定的异常设置catch块。

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

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

答案 2 :(得分:0)

这感觉有些笨拙,但是通过一个简单构建自己的界面和方法,你可以这样做:

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;
}

答案 3 :(得分: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;
}