【问题标题】:How does the implementation of ScalaNumber work regarding underlying?ScalaNumber 的实现如何与底层有关?
【发布时间】:2011-05-19 19:47:13
【问题描述】:

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

我错过了一些非常明显的东西还是这里有什么特殊情况?

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

【问题讨论】:

    标签: math scala numbers biginteger bigdecimal


    【解决方案1】:

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

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

    【讨论】:

      【解决方案2】:

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

      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
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-10-18
        • 1970-01-01
        • 2010-11-15
        • 2020-02-20
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多