为什么scalac需要在一个预期为'Any'的方法中加上'Int'`

为什么scalac需要在一个预期为'Any'的方法中加上'Int'`,scala,boxing,scalac,Scala,Boxing,Scalac,考虑以下类别: 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

考虑以下类别:

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
def println(x: Any): Unit
可以看出,当我们调用
println
时,
Int
被装箱到
java.lang.Integer
中。但是
println
的签名是:

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
def println(x: Any): Unit

As
Int
任何
都可以在Scala中按语法使用,因为编译器会根据需要自动装箱任何Java原语类型(这是
Int
的等价物)。从发出的字节码中,可以看到对具有以下签名的方法调用了
INVOKEVIRTUAL

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

由于Java中没有
Any
的概念,scalac会发出
对象的方法签名,这在Scala中相当于
AnyRef
。由于
Int
扩展了
AnyVal
,我们需要分配等价的Java包装器,即
Integer

,接下来的问题是,它们到底为什么不像Java那样重载println?@oxbow\u lakes Java确实有
println
的原始输入类型,它们最终都会使用
原语类型.toString
生成
字符串,即
整数.toString
,从而避免分配
整数。我假设实现者假设如果你想在生产中
println
,分配一个
Integer
或任何其他包装器将是你最小的问题。除了像我这样的白痴可能不会想太多,而是愉快地复制那种风格,而不知道我在另一个线程上要求的性能含义,
def print():Unit=println(底层.toString)
是否可以停止底层
的包装?瞧,使用
toString
难道不能让编译器看到“意图”并像在其他类似地方一样进行静态调用吗?