如何引用接口在Java中实现的类类型?

时间:2011-11-17 03:21:06

标签: java generics interface self-reference

我遇到了我正在制作的程序中的接口问题。我想创建一个接口,它的一个方法接收/返回对自己对象类型的引用。它类似于:

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;
    }
}

但它看起来似乎是一种解决方法或类似的东西。还有另一种方法吗?

4 个答案:

答案 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支持协变返回类型,因此这是一个选项。利用AB来自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,因此返回类型与基本函数的兼容。 (这称为“协方差”。)

事实上,由于AB也来自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();
}

然后将结果转换为您想要的类型。您现有的AB课程将按原样运作。

(这是返回类型协方差的一个例子。在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,为什么不使用?