我想将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 ++,我觉得我可能会以错误的方式接近它。
答案 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;
}