Scala如何在方法返回类型中处理Any to AnyVal协方差?

时间:2018-04-12 09:57:19

标签: scala covariance

一个例子胜过千言万语:

class A { def foo: Any = new Object }

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

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

Scala是否能够避免在上面重写的AnyVal方法中装箱/取消装箱def foo: AnyVal值?

2 个答案:

答案 0 :(得分:4)

不,它没有。 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>();
      ()
    }
  }
}

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

答案 1 :(得分:0)

Yuval的答案可以概括为:AnyVal的删除是Object(你可以在REPL中输入classOf[AnyVal]看到这一点),所以每当你AnyVal进入时Scala,你可以在字节码中得到Object

E.g。如果您将A更改为

class A { def foo: AnyVal = 0 }

它仍然是Object

也许有某些情况下使用AnyVal本身会避免拳击,但我会感到惊讶。它的创建非常适合编译器的方便,稍后再次使用(value classes),但它在用户代码中很少有用(定义值类除外)。