Как реализация ScalaNumber работает в отношении базового?

#math #scala #numbers #biginteger #bigdecimal

#математика #scala #числа #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 .

Я упускаю что-то довольно очевидное или здесь есть что-то особенное?

РЕДАКТИРОВАТЬ: Конечно, я пропустил что — то очевидное … С тобой все в порядке. Ко-вариантные возвращаемые типы. Спасибо!

Ответ №1:

Это просто ковариантный возвращаемый тип, который разрешен как в Scala, так и в Java.

Обоснование этого таково: если класс Base обещает вернуть A форму определенного метода, то подкласс Derived <: Base соблюдает принцип подстановки Лискова, если он возвращает 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