java 编译器如何处理像 `public interface A extends B<A>` 这样的代码

How does java compiler deal with code like `public interface A extends B<A>`

我刚开始写 java,今天我读了一些这样的代码:

public interface A extends B<A>{
    ...
}

public interface B<E extends B<E>>{
    ...
}

当然我能看懂代码,但是这让我真的很困惑。好像……我用自己创造自己?编译器是怎么处理的?

为了回答您的明确问题,编译器通过相互检查约束来验证泛型,验证所讨论的特定类型是 legal/matching 泛型引用。之后(对于输出代码)通用类型被擦除。这叫做'type erasure'。此处解释了显式步骤:https://docs.oracle.com/javase/tutorial/java/generics/erasure.html

但更有趣的是您显然遇到的语义。

泛型类型并不意味着 'use to create' 而是 'regarding'(无论如何)。 以 List 为例。 List<A> 表示 'List containing instances of class A'。对于调用它的实例的代码,这意味着所有引用泛型类型的方法都将直接或间接地考虑类型 A 的对象。

任何实施 public interface B<E extends B<E>> 的 class 都需要在这方面考虑自己。这一点可能是稍后引用 E 的方法或属性将产生实现它们的类型。例如:

public interface Chainable<E extends Chainable<E>> {
  public void append(E followup);

  public E getNext();
}

...

public class MyLink implements Chainable<MyLink> {
  public void append(MyLink l) {
    ...
  }

  public MyLink getNext() {
    ...
  }
}

通过这种方式,可以确保任何 class 实现 Chainable 的方法都将采用一种方法,并返回该 class 的对象,而不是任何对象。

虽然以上仅在约束方面很有用,但我看不出更好地使用您的示例 public interface A extends B<A>。这样做的原因是,现在实施 A 的任何 class 只能保证考虑 A 而不是实施 class 本身(这会更有用)。示例:

public class C implements A {
  public A methodDeclaredInB(A someParam) {
    ...
  }
}

上面的方法在编译时只知道A,而不知道C。相反,如果有人写道:

public class C implements B<C> {
  public C methodDeclaredInB(C someParam) {
    ...
  }
}

然后 class C 可以用来代替 'only' A.

在某些情况下,知道类型 A 就足够了,但通常您需要类型 C,因此创建一个(本身 non-generic)接口 A以这种方式扩展 B 似乎是通往上面更冗长但更有用的示例的脆弱捷径。

是的,编译器的能力令人惊讶。正如其他答案所说,通用参数通过引用使用。但是有编译(.class)和它们的依赖关系。注意:一些运行时错误是由不同步编译引起的,你可以在 jar 中存储一个 .java 文件 - 我相信)。

那个和self-references的玩弄经常被用来把子class的class传给超级class来限制子class的东西(方法)class.

但是循环行为的相同技巧可以像纯 classes 那样完成:

public interface Foo {
    Foo ZERO = new Bar();
}

public class Bar implements Foo {
    ... ZERO ...
}

所以 java 编译器解决了这个 chicken/egg 问题。