9.9. Więcej o nadpisywaniu składowych

Typy składowych definiowanych w podklasie nie zawsze muszą być dokładnie takie, jak typy nadpisywanych składowych. Plik Overriding1.scala ilustruje niektóre z takich sytuacji.

Plik Override1.scala:
class X1 {
  def a: Any = 'a
  def b: Any = 'b
}
class Y1 extends X1 {
  override def a: String = "a"
  override val b: String = "b"
}

Klasa Y1 rozszerza klasę X1. W klasie X1 są zdefiniowane dwie metody typu Any. W klasie Y1 te dwie metody są nadpisywane metodą i wartością typu String, a więc typu, który znajduje się niżej w hierarchii typów od typu nadpisywanych metod. Takie definicje są poprawne i kompilują się.

scala> var x1 = new X1
x1: X1 = X1@199c6b5

scala> x1.a
res0: Any = 'a

scala> x1.b
res1: Any = 'b

scala> x1 = new Y1
x1: X1 = Y1@16c81a3

scala> x1.a
res2: Any = a

scala> x1.b
res3: Any = b

scala> val y1 = new Y1
y1: Y1 = Y1@163a52f

scala> y1.a
res4: String = a

scala> y1.b
res5: String = b

Plik Overriding2.scala ilustruje kolejny przypadek.

Plik Override2.scala:
abstract class X2 {
  type A >: String <: Any
  def a: A
}
class Y2 extends X2 {
  override type A = AnyRef
  def a: A = 'a
}

Klasa Y2 rozszerza klasę X2. W klasie X2 jest zdefiniowany parametr typu A, który ma ograniczenie górne Any i dolne String. Ponadto, w tej klasie zdefiniowana jest abstrakcyjna metoda a typu A. W klasie Y2 typ A jest definiowany jako AnyRef, a więc jako typ spełniający oba ograniczenia parametru typu A z nadklasy. Taka definicja jest prawidłowa. Dodatkowo, nadpisywana jest abstrakcyjna metoda a.

scala> (new Y2).a
res6: Object = 'a

scala> (new Y2).a
res7: Object = 'a

Plik Overriding3.scala ilustruje jeszcze inne sytuacje, tym razem dotyczące nadpisywania aliasu typu przez inny alias typu.

Plik Override3.scala:
abstract class X3 {
  type A <: Any
  type B >: String
  def c(a:A, b:B): Unit
}
abstract class Y3 extends X3 {
  override type A <: AnyRef
  override type B >: AnyRef
}
class Z3 extends Y3 {
  override type A = String
  override type B = Any
  override def c(a:String, b:Any) {
    println(a)
    println(b)
  }
}

Klasa Y3 rozszerza klasę X3. W klasie X3 są zdefiniowane dwa aliasy typu o nazwach A i B. Alias A ma ograniczenie górne Any, a alias B ma ograniczenie dolne String. Ponadto, w tej klasie zdefiniowana jest abstrakcyjna metoda c typu Unit, przyjmująca parametry typu A i B. W klasie Y3 parametr typu A jest nadpisywany i deklarowany z ograniczeniem górnym AnyRef, a więc bardziej ograniczającym parametr z nadklasy. Z kolei parametr typu B jest nadpisywany i deklarowany z ograniczeniem dolnym AnyRef, a więc także bardziej ograniczającym parametr z nadklasy. Obie te deklaracje parametrów są prawidłowe i kompilują się. Klasa Z3 dziedziczy z Y3 i definiuje parametry A i B jako String i Any.

scala> (new Z3).c("a","b")
a
b

Język programowania Scala Wydanie 2. Copyright © Grzegorz Balcerek 2016

Licencja Creative Commons

Ten utwór jest dostępny na licencji Creative Commons Uznanie autorstwa-Na tych samych warunkach 4.0 Międzynarodowe.

Oracle and Java are registered trademarks of Oracle and/or its affiliates. Other names may be trademarks of their respective owners.