Javagenerics:非法的前向引用
给定一个通用接口
interface Foo { }
我想编写一个实现,要求A成为B的子类。所以我想这样做
class Bar implements Foo { } // --> Syntax error
要么
class Bar implements Foo { } // --> illegal forward reference
但似乎有效的唯一解决方案是:
class Bar implements Foo { }
这有点难看,因为它颠倒了通用参数的顺序。
这个问题有什么解决方案或解决方法吗?
由于这在Java中是不可能的,因此尝试以不同的方式考虑Bar
。
为Bar
声明变量时,首先指定父类,然后指定子类。 这就是Bar
工作方式。 不要认为它是倒退 – 认为它是前锋。 父母应该自然地在孩子面前指定。 您添加的这个附加关系是驱动参数顺序的因素,而不是底层接口。
在看到这个问题之后,我花了一些时间尝试了一些我认为可行的不同技术。 例如,构建一个通用接口ISuper
然后让Bar implements ISuper
(和一个类似的技术与子类和扩展而不是实现)但这只是导致类型错误, Bar.java:1: type parameter A is not within its bound
。 同样,我尝试创建一个方法private Bar foo() { return this; };
private Bar foo() { return this; };
并从构造函数中调用它,但这只会导致有趣的类型错误消息Bar.java:2: incompatible types found : Bar required: Bar
所以,我认为不幸的是,答案是否定的。 显然,这不是你所希望的答案,但似乎正确的答案是,这是不可能的。
已经指出既没有解决方案也没有很好的解决方法。 这是我最终做的。 它只适用于我的特殊情况,但如果你遇到类似的问题,你可以把它作为灵感。 (这也解释了我遇到这个问题的原因)
首先,有这个类(只显示相关的接口):
class Pipe { boolean hasNext(); Input getNext(); void setNext(Output o); }
实际上是Foo
界面
interface Processor { process(Pipe p); }
Bar
类应该像这样工作
class JustCopyIt implements Processor { process(Pipe p) { while (p.hasNext()) p.setNext(p.getNext()); } }
最简单的方法是抛出这样的值: p.setNext((Output) p.getNext())
。 但这很糟糕,因为它允许创建JustCopyIt
的实例。 调用此对象会在某些时候神秘地失败,但不会在发生实际错误的位置失败。
做class JustCopyIt
在这里也行不通,因为那时我无法处理Pipe
。
所以我最终做的是将界面更改为:
interface Processor { process(Pipe extends Input, ? super Output> p); }
这样, JustCopyIt
就能够处理Pipe
。
虽然这在技术上似乎是唯一有效的解决方案,但它仍然很糟糕,因为它1)仅适用于这种特殊情况,2)要求我更改接口(这并不总是可行)和3)制作另一个的代码处理器丑陋。
编辑:
阅读Keiths的回答再次启发了我的另一个解决方案:
public abstract class Bar implements Foo { public static Bar newInstance() { return new BarImpl(); } private static class BarImpl extends Bar { // code goes here } } // clean code without visible reversed parameters Bar bar1 = Bar.newInstance(); Bar