我遇到了我正在制作的程序中的接口问题。我想创建一个接口,它的一个方法接收/返回对自己对象类型的引用。它类似于:
public interface I {
? getSelf();
}
public class A implements I {
A getSelf() {
return this;
}
}
public class B implements I {
B getSelf() {
return this;
}
}
我不能使用“I”,它是“?”,因为我不想返回对接口的引用,而是类。我搜索并发现Java中没有办法“自我引用”,所以我不能只用“?”来代替它。在“自”关键字的示例中或类似的东西。实际上,我找到了一个像
这样的解决方案public interface I<SELF> {
SELF getSelf();
}
public class A implements I<A> {
A getSelf() {
return this;
}
}
public class B implements I<B> {
B getSelf() {
return this;
}
}
但它看起来似乎是一种解决方法或类似的东西。还有另一种方法吗?
答案 0 :(得分:10)
在扩展接口时,有一种方法可以强制使用自己的类作为参数:
interface I<SELF extends I<SELF>> {
SELF getSelf();
}
class A implements I<A> {
A getSelf() {
return this;
}
}
class B implements I<A> { // illegal: Bound mismatch
A getSelf() {
return this;
}
}
这甚至可以在编写泛型类时起作用。唯一的缺点:必须将 this
投射到SELF
。
正如安德烈·马卡罗夫在a comment below中指出的那样,在编写泛型类时,不可靠地工作。
class A<SELF extends A<SELF>> {
SELF getSelf() {
return (SELF)this;
}
}
class C extends A<B> {} // Does not fail.
// C myC = new C();
// B myB = myC.getSelf(); // <-- ClassCastException
答案 1 :(得分:5)
Java支持协变返回类型,因此这是一个选项。利用A
和B
来自Object
的事实:
public interface I {
Object getSelf(); // or I, see below
}
public class A implements I {
A getSelf() { return this; }
}
public class B implements I {
B getSelf() { return this; }
}
关键是A.getSelf()
和B.getSelf()
都是I.getSelf()
的合法覆盖,即使它们的返回类型不同。这是因为每个A
都可以被视为,如和Object
,因此返回类型与基本函数的兼容。 (这称为“协方差”。)
事实上,由于A
和B
也来自I
,因此出于同样的原因,您可以将Object
替换为I
。< / p>
协方差通常是一件好事:拥有I
类型接口对象的人可以调用getSelf()
并获得另一个界面,这就是她需要知道的全部内容。另一方面,已经知道他有A
个对象的人可以调用getSelf()
并实际获得另一个A
个对象。附加信息可用于获取更具体的派生类型,但缺少该信息的人仍可获得接口基类规定的所有内容:
I x = new A();
A y = new A();
I a = x.foo(); // generic
A b = y.foo(); // we have more information, but b also "is-an" I
A c = (A)x.foo(); // "cheating" (we know the actual type)
答案 2 :(得分:2)
我想知道是否有其他方法可以这样做?
你可以按如下方式编写它:
public interface I {
I getSelf();
}
然后将结果转换为您想要的类型。您现有的A
和B
课程将按原样运作。
(这是返回类型协方差的一个例子。在Java 5中添加了对返回类型协方差的支持。这种方法会在旧的JDK中产生编译错误。)
使用泛型的替代版本(您称之为解决方法,但事实并非如此)允许您避免显式类型转换。但是,生成的代码中存在隐式类型转换,并且在运行时...除非JIT编译器可以对其进行优化。
没有更好的选择,AFAIK。
答案 3 :(得分:1)
正如其他人所说,你可以覆盖实现类中的返回类型:
public interface I {
public I getSelf();
}
public class A implements I {
@Override
public A getSelf() {
return this;
}
}
但是,我有两个'为什么'的问题:
1:为什么要接口返回实现对象?它似乎违背了接口和继承的一般思想。你能举例说明如何使用它吗?
2:无论如何,你为什么要这个功能?如果a.getSelf()== a,为什么不使用?