假设我有这个界面:
interface Foo<T extends Foo<T>> { // ... }
以及以下三个实现它的类:
class TrueFoo implements Foo<TrueFoo > { // ... }
class FalseFoo implements Foo<FalseFoo> { // ... }
class WrongFoo implements Foo<FalseFoo> { // ... }
// ^^^^^^^^ this here is wrong, only
// Foo<WrongFoo> should be allowed
以下方法的方法签名需要什么来强制我可以返回 TrueFoo 或 FalseFoo 类型的对象,但不能返回 WrongFoo...
public ???? getFoo(boolean which) {
return which ? new TrueFoo() : new FalseFoo();
}
以下不起作用:
这使我还可以返回一个新的 WrongFoo():
public Foo<?> getFoo(boolean which) { return which ? new TrueFoo() : new FalseFoo(); }
这不允许我返回任何东西(解释如下):
public <FooType extends Foo<FooType>> FooType getFoo(boolean which) { return which ? new TrueFoo() : new FalseFoo(); }
问题是 FooType 的类型是由我调用函数的上下文决定的,
getFoo()
而不是由我实际尝试返回的对象决定的。
顺便说一句,在调用方法时强制执行此签名很容易:
public <FooType extends Foo<FooType>> void test(FooType foo) {
// Do something with foo
}
如果您尝试使用 WrongFoo 的实例调用它,这将给您一个绑定不匹配错误。
让我认为应该有一种方法可以对方法返回类型执行此操作。
或者有没有办法在 Foo 的接口定义中强制执行这个签名?
编辑:
为了帮助可视化这个界面应该做什么,你可以考虑这个版本:
interface CanCopy<Type extends CanCopy<Type>> {
public Type copy();
}
显然, like 类Foo implements CanCopy<Bar>
没有任何意义,只有Foo implements CanCopy<Foo>
or Bar implements CanCopy<Bar>
。
编辑2:
正如存在解决方案的概念验证一样,我可以为自己定义以下帮助程序类:
class FooResult {
private final Foo<?> foo;
public <FooType extends Foo<FooType>> FooResult(FooType foo) {
this.foo = foo;
}
@SuppressWarnings("unchecked")
public <FooType extends Foo<FooType>> FooType getFoo() {
return (FooType) foo;
}
}
然后我可以要求我的 getFoo 方法是这种类型:
public FooResult getFoo(boolean which) {
return which ? new FooResult(new TrueFoo()) : new FooResult(new WrongFoo());
}
这样,我将无法从我的 get 方法返回 WrongFoo。
但是,很明显,这有点太复杂了,不能像 Java 泛型通常倾向于编写代码那样优雅(根据我的经验)......那么,这可以以某种方式缩短吗?
编辑 3:
我找到了另一种方法来为实现接口的人提供检查,方法是这样定义:
interface Foo<FooType extends Foo<FooType>> {
// Other interface definitions
/**
* Please implement with just this line in it:<br/><br/>
* <code>return this;</code>
* @return <code>this</code>
*/
public FooType returnThis();
}
现在,如果有人试图实现上述 WrongFoo 类,他将必须提供该方法FalseFoo returnThis()
,如果他只是return this
按照 doctype 中的要求实现它,该行将引发错误。
这不是保证,但它是一个非常好的虚拟检查,可以防止因粗心复制类而产生的错误......而且在无论如何都需要带有此签名的消息的情况下,这将是一个很好的解决方案。
还有什么想法吗?