铸造成原始类型

gru*_*mli 3 java generics casting raw-types

我遇到了一个代码,我不明白为什么它的工作原理.假设我创建了一个通用接口Foo<T>,如下所示:

interface Foo<T>{
   void set(T item);
}
Run Code Online (Sandbox Code Playgroud)

然后我创建一个名为Barwhich 的类Foo<String>,如下所示:

class Bar implements Foo<String>{ 
   @override
   public void set(String item){
      //useless body
   }
}
Run Code Online (Sandbox Code Playgroud)

基于此,我们可以编写以下代码:

Bar bar = new Bar();
bar.set("Some string");
Foo rawFoo = (Foo) bar;
rawFoo.set(new Object()); // ClassCastException: Object cannot be cast to string
Run Code Online (Sandbox Code Playgroud)

最后一行是我没有真正得到的.众所周知,使用原始类型时,通用参数类型将转换为Object.在这种情况下,代码编译,我们可以将Object传递给set()方法.但是Java如何确定它必须在运行时将Object转换为String?

And*_*ner 5

如果你Bar使用反编译javap:

class Bar implements Foo<java.lang.String> {
  Bar();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public void set(java.lang.String);
    Code:
       0: return

  public void set(java.lang.Object);
    Code:
       0: aload_0
       1: aload_1
       2: checkcast     #2                  // class java/lang/String
       5: invokevirtual #3                  // Method set:(Ljava/lang/String;)V
       8: return
}
Run Code Online (Sandbox Code Playgroud)

void set(java.lang.Object)是一种合成桥梁方法.注意checkcast说明.等效的"真实"代码如下所示:

public void set(Object object) {
  set((String) object);
}
Run Code Online (Sandbox Code Playgroud)

编译器创建了此方法,以使类在类型擦除下工作; 实现工作的实际方法是set(java.lang.String)桥方法委托的方法.

这种桥接方法实际上覆盖了基类中的方法.使用@Override注释声明的方法仅仅是一个重载.