5.11. Dziedziczenie

Klasy mogą dziedziczyć po innych klasach. W celu określenia, że klasa A dziedziczy po klasie B, w definicji klasy A należy dodać słowo kluczowe extends, a po nim nazwę klasy B i opcjonalnie, w nawiasach, wartości parametrów, które mają być przekazane do konstruktora tej klasy. Jeśli klasa zawiera ciało, to klauzulę extends należy dodać przed ciałem klasy.

Plik Extending1.scala:
class Greet(hello: String, name: String) {
  def greet = println(hello + " " + name)
}
class GreetPeter(hello: String) extends Greet(hello, "Peter")
class HiPeter extends GreetPeter("Hi")

Plik Extending1.scala zawiera trzy klasy, które tworzą hierarchię, w której klasa HiPeter dziedziczy po GreetPeter, a ta z kolei dziedziczy po Greet.

scala> var peter: GreetPeter = new GreetPeter("Hello")
peter: GreetPeter = GreetPeter@11c693d

scala> peter.greet
Hello Peter

scala> peter = new HiPeter
peter: GreetPeter = HiPeter@76f6a0

scala> peter.greet
Hi Peter

scala> peter = new Greet("Hello", "John")
<console>:11: error: type mismatch;
 found   : Greet
 required: GreetPeter
       peter = new Greet("Hello", "John")
               ^

Powyższe przykłady ilustrują użycie tych klas. Zmiennej peter, typu GreetPeter, przypisujemy najpierw instancję klasy GreetPeter, a potem klasy HiPeter. Kompilator dopuszcza przypisanie instancji klasy HiPeter do zmiennej typu GreetPeter, gdyż HiPeter jest podklasą klasy GreetPeter. Natomiast próba przypisania do tej samej zmiennej obiektu typu Greet nie udaje się. Klasa Greet nie jest ani klasą GreetPeter, ani jej podklasą.

Klasy, które dziedziczą po innych klasach, mogą nadpisywać składowe zdefiniowane w nadklasie, a także mogą dodawać nowe składowe. Nadpisywanie nieabstrakcyjnych składowych wymaga użycia modyfikatora override.

Plik Extending2.scala:
class Hello2 { def speak: String = "Hello" }
class Hi2 extends Hello2 {
  override def speak: String = "Hi"
  def hi: String = speak
}
class Speak2(override val speak: String) extends Hello2

Klasa Hi2 z pliku Extending2.scala nadpisuje metodę speak i dodaje nową metodę hi. Metoda speak ma modyfikator override, a metoda hi go nie ma.

scala> val a = new Hello2
a: Hello2 = Hello2@1f4357f

scala> a.speak
res2: String = Hello

scala> val b = new Hi2
b: Hi2 = Hi2@1202a3a

scala> b.speak
res3: String = Hi

scala> b.hi
res4: String = Hi

Próba nadpisania metody speak z pominięciem modyfikatora override zakończyłaby się błędem kompilacji.

Plik Extending3.scala:
class Hello3 { def speak = println("Hello") }
class Hi3 extends Hello3 {
  def speak = println("Hi")
  def hi = speak
}

Plik Extending3.scala zawiera taką błędną definicję klasy.

$ scalac Extending3.scala
Extending3.scala:3: error: overriding method speak in class Hello3 of type => Unit;
 method speak needs `override' modifier
  def speak = println("Hi")
      ^
one error found

Dodanie modyfikatora override do definicji metody hi, tak jak to jest zrobione w pliku Extending4.scala, również powoduje błąd kompilacji.

Plik Extending4.scala:
class Hello4 { def speak = println("Hello") }
class Hi4 extends Hello4 {
  override def speak = println("Hi")
  override def hi = speak
}

Błąd jest spowodowany tym, że metoda hi nie nadpisuje niczego.

$ scalac Extending4.scala
Extending4.scala:4: error: method hi overrides nothing
  override def hi = speak
               ^
one error found

Jeśli klasa utworzona w języku Scala nie dziedziczy jawnie z jakiejś innej klasy, to niejawnie dziedziczy z klasy AnyRef. W pliku HelloName.scala znajduje się definicja klasy HelloName, która niejawnie dziedziczy po AnyRef.

Plik HelloName.scala:
class HelloName(name: String) {
  def hello = println("Hello "+name+"!")
  override def toString = "HelloName("+name+")"
}

Klasa HelloName nadpisuje metodę toString odziedziczoną z klasy AnyRef. Zauważmy, że pokazana przez konsolę tekstowa reprezentacja instancji utworzonej w poniższym przykładzie odpowiada temu, co zwraca metoda toString wywołana na tej instancji.

scala> val paul = new HelloName("Paul")
paul: HelloName = HelloName(Paul)

scala> paul.toString
res0: String = HelloName(Paul)

scala> paul.hello
Hello Paul!

Nie jest możliwe utworzenie bezpośredniej podklasy klasy Any.

scala> class A extends Any
<console>:10: error: Any does not have a constructor
       class A extends Any
                       ^

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.