当我有一个界面
public interface Foo<T> {
T someMethod();
}
Run Code Online (Sandbox Code Playgroud)
有没有办法确保当某个类实现此接口时,泛型类型是相同的实现类.
例如:
public class Bar implements Foo<Bar> {
Bar someMethod() {
return new Bar();
}
}
Run Code Online (Sandbox Code Playgroud)
Chr*_*ung 23
是的,这可以做到(有点;见下文).(在C++世界中,这被称为" 奇怪的重复模板模式 ",但它也适用于Java):
public interface Recur<T extends Recur<T>> {
// ...
}
Run Code Online (Sandbox Code Playgroud)
(注意第二次提到T.这是CRTP的一个重要部分.)
此外,这是如何java.util.Enum定义的,因此调用的枚举类型Foo必须派生自Enum<Foo>,因此它在Java中也不是一种不常见的模式.
我想说上面是故事的结尾,但是Tangens在他们的修订版中正确指出它并不完全健壮,而且与他们的回答并没有完全不同.
Recur<T>我所拥有的Recur<?>解决方案与tangens 的解决方案之间存在一个区别(我能想到):
public interface Recur<T extends Recur<T>> {
T foo();
}
class A implements Recur<B> {
@Override
public B foo() {
return new B();
}
}
class B implements Recur<A> {
@Override
public A foo() {
return new A();
}
}
Run Code Online (Sandbox Code Playgroud)
有了<T>,上面就不会编译; 有<?>,它会.但那只是分裂的头发; 它不会改变tangens的中心点,即给定已经有效的Recur实现,您可以使后续实现使用已经有效的类型,而不是自身.我仍然说这是有价值的东西,但这不仅仅是一个比tangens的答案更值得的东西.
最后,如果可以的话,继续并提出tangens的回答.(tangens,你应该触摸你的帖子,这样我也可以投票给你.)他们有一个非常好的观点,我很抱歉,我第一次错过了它.谢谢,tangens!
tan*_*ens 14
不,你不能参考实现类.你能做的最好的事情是:
public interface Foo<T extends Foo<?> > {
T someMethod();
}
Run Code Online (Sandbox Code Playgroud)
这样做,您可以确保someMethod()返回实现的对象Foo.
编辑:
即使使用这样的接口定义:
public interface Foo<T extends Foo<T > > {
T someMethod();
}
Run Code Online (Sandbox Code Playgroud)
您可以定义一个类 Bar2
public class Bar2 implements Foo<Bar2 > {
@Override
public Bar2 someMethod() {
return new Bar2();
}
}
Run Code Online (Sandbox Code Playgroud)
然后你可以定义一个Bar实现Foo但不返回的类,Bar但是Bar2:
public class Bar implements Foo<Bar2 > {
@Override
public Bar2 someMethod() {
return new Bar2();
}
}
Run Code Online (Sandbox Code Playgroud)
最初的问题是,你是否可以像对待那样准备使用界面Bar.
答案是:不.
编辑:
Angelika Langer给出了一个很好的解释,我如何解密"Enum <E extends Enum <E >>"?