ScalaNumber的实现如何在底层工作?

时间:2011-05-19 19:47:13

标签: math scala numbers biginteger bigdecimal

scala.math.ScalaNumber是一个Java文件,如下所示:

public abstract class ScalaNumber extends java.lang.Number {
  protected abstract boolean isWhole();
  public abstract Object underlying();
}

scala.math.BigDecimal通过以下方式实现它:

class BigDecimal(val bigDecimal: BigDec, val mc: MathContext)
extends ScalaNumber with ScalaNumericConversions with Serializable {
  ...
  def underlying = bigDecimal
}

以及scala.math.BigInt

class BigInt(val bigInteger: BigInteger) extends ScalaNumber with ScalaNumericConversions with Serializable {
  ...
  def underlying = bigInteger
}

令人困惑的是,underlying的类型为java.math.BigDecimal / java.math.BigInt,而不是Object

我是否会错过一些非常明显的东西,或者这里有什么特别的东西?

编辑:当然我错过了一些明显的东西......你没事。共变体返回类型。谢谢!

2 个答案:

答案 0 :(得分:4)

它只是一个covariant return type,在Scala和Java中都是允许的。

它背后的基本原理是:如果一个类Base承诺返回A形成某个方法,那么子类Derived <: Base会尊重Liskov substitution principle,如果它返回{{} 1}}或任何子类A。当然,如果B <: A返回BigInt#underlying,则对于BigInteger的客户来说这不是问题,他们可能只希望获得普通的ScalaNumber

答案 1 :(得分:4)

在Java和Scala方法中,返回类型在覆盖时可以是协变的。也就是说,如果重写一个方法,你可以使它的返回类型成为overriden方法的返回类型的子类型。

scala> class Foo { def method : Object = "foo" }
defined class Foo

scala> class Bar extends Foo {override def method : String = "bar" }
defined class Bar

scala> (new Foo).method
res0: java.lang.Object = foo

scala> (new Bar).method
res1: String = bar

scala> ((new Bar) : Foo).method
res2: java.lang.Object = bar