为什么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
难道不能让编译器看到“意图”并像在其他类似地方一样进行静态调用吗?