#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