反编译Scala代码:为什么派生类中有两个重写方法?

Cod*_*Now 8 polymorphism inheritance scala dynamic-dispatch decompiler

反编译Scala代码:为什么派生类中有两个重写方法?

class A
{
    private var str: String = "A"
    val x: A = this

    override def toString(): String = str

    def m1(other: AnyRef): AnyRef = {
      println("This is A.m1(AnyRef)")
      other
    }
}

class B extends A {
    private var str: String = "B"
    var z: Int = 0
    override val x: B = this

    override def m1(other: AnyRef): B = {
      println("This is B.m1(AnyRef)")
      this
    }
}
Run Code Online (Sandbox Code Playgroud)

上面代码的B类反编译为:

public class test$B extends test$A {
  private java.lang.String str;
  private int z;
  private final test$B x;
  private java.lang.String str();
  private void str_$eq(java.lang.String);
  public int z();
  public void z_$eq(int);
  public test$B x();
  public test$B m1(java.lang.Object);
  public java.lang.Object m1(java.lang.Object);
  public test$A x();
  public test$B();
}
Run Code Online (Sandbox Code Playgroud)

我无法理解为什么m1反编译代码中有两个"版本"的方法.从我的理解,B.m1只是覆盖A.m1public java.lang.Object m1(java.lang.Object)属于,A不应该在课堂上B.

Ant*_*ony 8

这是一种合成桥接方法.

在Java字节码中,方法仅覆盖具有完全相同签名的方法.如果B没有任何实例Object m1(Object),那么任何调用它的尝试都会调用A中的实现,这不是你想要的.因此,编译器插入一个简单调用的合成桥接方法B m1(Object).此行为并非特定于Scala - 它也发生在纯Java中.

您可以通过检查反汇编来更详细地查看它.如果我编译并反汇编以下代码

class A
{
    def m1(other: AnyRef): AnyRef = {
      println("This is A.m1(AnyRef)")
      other
    }
}

class B extends A {
    override def m1(other: AnyRef): B = {
      println("This is B.m1(AnyRef)")
      this
    }
}
Run Code Online (Sandbox Code Playgroud)

B的相关部分是

.method public m1 : (Ljava/lang/Object;)LB; 
    .code stack 2 locals 2 
L0:     getstatic Field scala/Predef$ MODULE$ Lscala/Predef$; 
L3:     ldc 'This is B.m1(AnyRef)' 
L5:     invokevirtual Method scala/Predef$ println (Ljava/lang/Object;)V 
L8:     aload_0 
L9:     areturn 
L10:    
    .end code 
    .methodparameters 
        other final 
    .end methodparameters 
.end method 

.method public bridge synthetic m1 : (Ljava/lang/Object;)Ljava/lang/Object; 
    .code stack 2 locals 2 
L0:     aload_0 
L1:     aload_1 
L2:     invokevirtual Method B m1 (Ljava/lang/Object;)LB; 
L5:     areturn 
L6:     
    .end code 
    .methodparameters 
        other final 
    .end methodparameters 
.end method 
Run Code Online (Sandbox Code Playgroud)

如您所见,该方法m1 (Ljava/lang/Object;)Ljava/lang/Object;只是将参数转发给m1 (Ljava/lang/Object;)LB;.