5

我知道在 Java 泛型中,当使用具有多个边界的类型参数时,编译器会将类型信息擦除到“最左边的边界”(即列表中的第一个类/枚举或接口)。那么为什么下面的代码编译没有问题呢?

public class Generic<T extends Object & Appendable & AutoCloseable> {

  T t;

  T method() throws Exception {
    t.close();
    char c='\u0000';
    t.append(c);
    return t;
  }

  public <T> T method2(T t) {
    return t;
  }  

}

类型参数 T 不应该被视为 Object 吗?(因此不允许我调用 close() 或 append())??

4

4 回答 4

0

您应该在此处阅读有关桥接方法的信息

在编译扩展参数化类或实现参数化接口的类或接口时,编译器可能需要创建一个合成方法,称为桥方法,作为类型擦除过程的一部分。您通常不需要担心桥接方法,但如果出现在堆栈跟踪中,您可能会感到困惑。

于 2015-12-26T12:05:52.143 回答
0

您的案例包含multiply bound

具有多个边界的类型变量是边界中列出的所有类型的子类型。如果其中一个边界是一个类,则必须首先指定它。

因此调用 AutoCloseable 接口中的 close() 方法和 Appendable 接口中的 append() 方法在语法上是合法的。

于 2015-12-26T12:07:46.433 回答
0

这本身不是一个答案,只是这个最左边的规则并不完全相关 - 我仍在试图找出正确的JLS部分(不像我希望的那样容易),但你可以看到类型不是来自这里的对象

<T extends Object & Appendable & AutoCloseable> void whatType(T... args) {
    System.out.println(args.getClass().getComponentType().getSimpleName());
}


new DeleteMe().whatType(); // prints AutoCloseable
于 2018-05-17T09:20:56.507 回答
0

这是反汇编您的代码。变量t是对象类型。checkcast在调用接口方法之前生成指令。如果 的值t没有实现接口,则抛出 ClassCastException。

Compiled from "Generic.java"
public class Generic<T extends java.lang.Appendable & java.lang.AutoCloseable> {
  T t;

  public Generic();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  T method() throws java.lang.Exception;
    Code:
       0: aload_0
       1: getfield      #2                  // Field t:Ljava/lang/Object;
       4: checkcast     #3                  // class java/lang/AutoCloseable
       7: invokeinterface #4,  1            // InterfaceMethod java/lang/AutoCloseable.close:()V
      12: iconst_0
      13: istore_1
      14: aload_0
      15: getfield      #2                  // Field t:Ljava/lang/Object;
      18: checkcast     #5                  // class java/lang/Appendable
      21: iload_1
      22: invokeinterface #6,  2            // InterfaceMethod java/lang/Appendable.append:(C)Ljava/lang/Appendable;
      27: pop
      28: aload_0
      29: getfield      #2                  // Field t:Ljava/lang/Object;
      32: areturn

  public <T> T method2(T);
    Code:
       0: aload_1
       1: areturn
}
于 2015-12-26T12:27:05.527 回答