Self-type - 需要类型绑定内的类型

Raf*_*ter 15 java generics

我想知道是否有可能限制在接口上声明的方法要求类型绑定内的类型。实际上,我想提供一种在无法提供真正类型安全的情况下强制转换类型安全的方法。

例如,考虑具有Base通过中间接口继承的基本类型的层次结构。通常,人们知道一种类型是接口,FirstInterface但不知道是什么特定的类正在实现它。我想要一种方法,它允许转换到接口的任一实现,而不允许转换到其他实现,Base如下例所示:

interface Base<TYPE extends Base<TYPE>> {
  default <CAST extends TYPE> CAST as(Class<? extends CAST> type) {
    if (type.isInstance(this)) {
      return type.cast(this);
    } else {
      throw new IllegalArgumentException();
    }
  }
}

interface FirstIface<TYPE extends FirstIface<TYPE>> extends Base<TYPE> { }
class FirstClassA implements FirstIface<FirstClassA> { }
class FirstClassB implements FirstIface<FirstClassB> { }

interface SecondIface<TYPE extends SecondIface<TYPE>> extends Base<TYPE> { }
class SecondClassA implements SecondIface<SecondClassA> { }
class SecondClassB implements SecondIface<SecondClassB> { }

interface ThirdIface<TYPE extends ThirdIface<TYPE>> extends FirstIface<TYPE>, SecondIface<TYPE> { }
class ThirdClassA implements ThirdIface<ThirdClassA> { }
class ThirdClassB implements ThirdIface<ThirdClassB> { }
Run Code Online (Sandbox Code Playgroud)

我希望能够在 Java 中编译以下代码:

FirstIface<?> i = new FirstClassA();
FirstClassA a = i.as(FirstClassA.class); // desired: compiles, now: compiler error
FirstClassB b = i.as(FirstClassB.class); // desired: runtime exception, now: compiler error
Run Code Online (Sandbox Code Playgroud)

这同样适用于 的层次结构ThirdIFace,而以下代码应呈现编译器错误:

SecondIface<?> i = new SecondClassA();
SecondClassA a = i.as(SecondClassA.class); // now and desired: compiler error
SecondClassB b = i.as(SecondClassB.class); // now and desired: compiler error
Run Code Online (Sandbox Code Playgroud)

有什么方法可以声明Base.as保留此要求吗?代码是自动生成的,因此也可以在自动生成的接口中提供覆盖(类也是如此)。当使用覆盖时,场景为SecondIface extends FirstIface.

Xav*_*ury 0

我能想到的最佳解决方案是:

    interface Base<TYPE extends Base<TYPE, BASE>, BASE extends Base<?, ?>> {

        default <CAST extends BASE> CAST as(Class<CAST> type) {
            if (type.isInstance(this)) {
                return type.cast(this);
            } else {
                throw new IllegalArgumentException();
            }
        }
    }

    interface FirstIface<TYPE extends FirstIface<TYPE>> extends Base<TYPE, FirstIface<?>> {}
    static class FirstClassA implements FirstIface<FirstClassA> {}
    static class FirstClassB implements FirstIface<FirstClassB> {}

    interface SecondIface<TYPE extends SecondIface<TYPE>> extends Base<TYPE, SecondIface<?>> {}
    static class SecondClassA implements SecondIface<SecondClassA> {}
    static class SecondClassB implements SecondIface<SecondClassB> {}

    public static void main(String... args) {
        {
            FirstIface<?> i = new FirstClassA();
            FirstClassA a = i.as(FirstClassA.class);
            FirstClassB b = i.as(FirstClassB.class); // runtime exception
            SecondClassA x = i.as(SecondClassA.class); // compile exception
            SecondClassB y = i.as(SecondClassB.class); // compile exception
        }
        {
            SecondIface<?> i = new SecondClassA();
            FirstClassA a = i.as(FirstClassA.class); // compile exception
            FirstClassB b = i.as(FirstClassB.class); // compile exception
            SecondClassA x = i.as(SecondClassA.class);
            SecondClassB y = i.as(SecondClassB.class); // runtime exception
        }
        new FirstClassA().as(FirstClassB.class); // unfortunately, this compiles fine :-(
    }
Run Code Online (Sandbox Code Playgroud)