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

Leo*_*ele 19 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

我不能使用"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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

Pat*_*ker 13

在扩展接口时,有一种方法可以强制使用自己的类作为参数:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

这甚至在编写泛型类时起作用.唯一的缺点:一是有投thisSELF.

正如安德烈·马卡罗夫在注意以下评论这并不能可靠地工作编写泛型类时.

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
Run Code Online (Sandbox Code Playgroud)

  • 这里施放到'SELF`是不安全的.请考虑以下内容:`B类扩展A <B> {}`然后`C类扩展A <B> {}`.满足所有类型限制但在`C`中``getSelf()`方法将`B`作为返回类型,而`C`不扩展`B`,因此转换将产生`ClassCastException`. (3认同)

Ker*_* SB 7

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; }
}
Run Code Online (Sandbox Code Playgroud)

问题的关键是,无论A.getSelf()B.getSelf()是合法的覆盖I.getSelf(),即使他们的返回类型是不同的.这是因为每一个A可以治疗一样Object,所以返回类型兼容与基础功能.(这称为"协方差".)

事实上,自从AB也被从推导I,可以替代ObjectI出于同样的原因.

协方差通常是一件好事:拥有类型接口对象的人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)
Run Code Online (Sandbox Code Playgroud)

  • @LeonardoRaele - 当你说"我不能使用'我''时,你解雇了这个解决方案*:-) (2认同)