为什么 scalac 需要在需要 `Any` 的方法中装箱 `Int`

Why does scalac need to box an `Int` in a method expecting an `Any`

考虑以下 class:

package test
class Test {
  def main(args: Array[String]): Unit = {
    val i: Int = 0
    println(i)
  }
}

main的字节码是:

public main([Ljava/lang/String;)V
   // parameter final  args
  L0
   LINENUMBER 4 L0
   ICONST_0
  L1
   ISTORE 2
  L2
   LINENUMBER 5 L2
   GETSTATIC scala/Predef$.MODULE$ : Lscala/Predef$;
   ILOAD 2
   INVOKESTATIC scala/runtime/BoxesRunTime.boxToInteger (I)Ljava/lang/Integer;
   INVOKEVIRTUAL scala/Predef$.println (Ljava/lang/Object;)V
  L3
   RETURN
  L4
   LOCALVARIABLE i I L1 L3 2
   LOCALVARIABLE this Ltest/Test; L0 L4 0
   LOCALVARIABLE args [Ljava/lang/String; L0 L4 1
   MAXSTACK = 2
   MAXLOCALS = 3

可以看出,当我们调用 println 时,Int 被装箱到 java.lang.Integer 中。但是println的签名是:

def println(x: Any): Unit

作为 Int <: AnyVal <: Any,为什么 Int 需要在通话中被装箱?

Any 可以在 Scala 中按语法使用,因为编译器会根据需要自动装箱任何 Java 基本类型(Int 等同于这种类型)。从发出的字节代码中,您可以看到 INVOKEVIRTUAL 是在具有以下签名的方法上调用的:

scala/Predef$.println (Ljava/lang/Object;)V

由于 Java 中没有 Any 的概念,scalac 发出 Object 的方法签名,在 Scala 中等同于 AnyRef。由于 Int 扩展了 AnyVal,我们需要分配等效的 Java 包装器,即 Integer.