Scala 如何处理方法 return 类型中 Any 到 AnyVal 的协方差?

How does Scala handle Any to AnyVal covariance in method return types?

一例抵千言:

class A { def foo: Any = new Object }

class B extends A {
  override def foo: AnyVal = 42
}

在Java中,甚至不允许使用签名@Override public int foo()B中的重写方法foo只能return包装器整数类型 (@Override java.lang.Integer foo()).

Scala 是否能够在上面覆盖的 def foo: AnyVal 方法中避免 boxing/unboxing of AnyVal 值?

不,不是。 Scala 必须坚持发出正确的字节码:

λ scalac -Xprint:jvm Bar.scala
[[syntax trees at end of                       jvm]] // Bar.scala
package yuval.tests {
  class A extends Object {
    def foo(): Object = new Object();
    def <init>(): yuval.tests.A = {
      A.super.<init>();
      ()
    }
  };
  class B extends yuval.tests.A {
    override def foo(): Object = scala.Int.box(42);
    def <init>(): yuval.tests.B = {
      B.super.<init>();
      ()
    }
  }
}

您可以看到,虽然 AnyVal 在 Scala 中是允许的,但发出的 foo 的实际方法签名是 Object 而不是 AnyVal,并且 Int 是盒装的。

Yuval 的回答可以概括:AnyVal 的擦除是 Object(你可以看到这个,例如通过在 REPL 中输入 classOf[AnyVal]),所以只要你有 AnyVal 在 Scala 中,你可以期待字节码中的 Object

例如如果您将 A 更改为

class A { def foo: AnyVal = 0 }

还是Object

也许有一些情况使用AnyVal本身会避免装箱,但我会感到惊讶。它的创建几乎是为了编译器的方便,后来又有了另一个用途 (value classes),但它在用户代码中很少有用(除了定义值 类)。