5.14. Klasy abstrakcyjne
W języku Scala można definiować klasy abstrakcyjne. Takie klasy mogą mieć zadeklarowane, ale niezdefiniowane składowe, nazywane abstrakcyjnymi. Klasa definiowana jako abstrakcyjna musi posiadać modyfikator abstract przed słowem kluczowym class. Natomiast składowe klasy, które nie posiadają definicji, nie poprzedza się modyfikatorem abstract. Klasa AbstractHello, z pliku AbstractHello.scala, definiuje cztery abstrakcyjne składowe.
Plik AbstractHello.scala: abstract class AbstractHello { type T val hello: String var name: T def greet }
Nie jest możliwe utworzenie instancji klasy abstrakcyjnej.
scala> new AbstractHello <console>:11: error: class AbstractHello is abstract; cannot be instantiated new AbstractHello ^
Błędem jest próba definicji klasy, która ma niezdefiniowaną składową, ale nie ma modyfikatora abstract.
scala> class A { def a } <console>:10: error: class A needs to be abstract, since method a is not defined class A { def a } ^
Natomiast sytuacja odwrotna jest prawidłowa — można zdefiniować abstrakcyjną klasę, której wszystkie składowe są zdefiniowane. Mimo że taka klasa ma wszystkie składowe zdefiniowane, nie można utworzyć jej instancji.
scala> abstract class B { def b = "hi" } defined class B scala> new B <console>:12: error: class B is abstract; cannot be instantiated new B ^
Klasa, która dziedziczy z klasy abstrakcyjnej, ale nie definiuje wszystkich jej abstrakcyjnych składowych, musi być również oznaczona modyfikatorem abstract, nawet jeśli nie wprowadza nowych, niezdefiniowanych składowych.
scala> abstract class C { val c : Int } defined class C scala> abstract class D extends C defined class D scala> class E extends C <console>:11: error: class E needs to be abstract, since value c in class C of type Int is not defined class E extends C ^
Klasa, która dziedziczy z klasy abstrakcyjnej, ale która nie wprowadza, ani nie dziedziczy żadnych niezdefiniowanych składowych, może być pozbawiona modyfikatora abstract. Taka klasa nie jest abstrakcyjna i można tworzyć jej instancje.
scala> abstract class F defined class F scala> class G extends F defined class G scala> new G res2: G = G@f9fcb2
W klasie, w której są nadpisywane abstrakcyjne składowe, nie trzeba ich definicji poprzedzać słowem kluczowym override, ale można to zrobić. Innymi słowy, w tych przypadkach słowo kluczowe override jest opcjonalne.
Plik AbstractHelloSubclasses.scala: class Hello1 extends AbstractHello { type T = String val hello = "Hello" var name: T = "Peter" def greet = hello + " " + name } class Hello2 extends AbstractHello { override type T = String override val hello = "Hello" override var name: T = "Peter" override def greet = hello + " " + name }
Obydwie definicje klas z pliku AbstractHelloSubclasses.scala są prawidłowe i kompilują się.
$ scalac AbstractHello.scala AbstractHelloSubclasses.scala $