5.8. Konstruktory
Ciało klasy może, oprócz definicji składowych, zawierać inne instrukcje. Te instrukcje wchodzą w skład głównego konstruktora klasy.
Plik Constructors1.scala: class Constructors1(hello: String) { println("Creating a new object with parameter: " + hello) def greet(name: String) = println(hello + " " + name) }
Ciało klasy Constructors1, zdefiniowanej w pliku Constructors1.scala, oprócz definicji metody, zawiera instrukcję println. Ta instrukcja jest wykonywana przy każdym tworzeniu instancji tej klasy. Zarówno ta instrukcja, jak i definicja metody, odwołują się do parametru klasy.
scala> val a = new Constructors1("Hi") Creating a new object with parameter: Hi a: Constructors1 = Constructors1@199c6b5 scala> a.greet("Peter") Hi Peter
Instrukcje konstruktora mogą odwoływać się do zdefiniowanych składowych.
Plik Constructors2.scala: class Constructors2(sayHello: Boolean) { val greeting = if (sayHello) "Hello" else "Hi" println("I will say '" + greeting + "', like this:") speak def speak = println(greeting) }
W przykładzie z pliku Constructors2.scala, podczas tworzenia obiektu wywoływana jest metoda println, która odwołuje się do wcześniej zdefiniowanej wartości greeting, a następnie zostaje wywołana metoda speak.
scala> val b = new Constructors2(false) I will say 'Hi', like this: Hi b: Constructors2 = Constructors2@3d57c7 scala> b.speak Hi
Plik Constructors3.scala zawiera przykład, w którym metody println oraz speak wywołane są przed definicją wartości greeting.
Plik Constructors3.scala: class Constructors3(sayHello: Boolean) { println("I will say '" + greeting + "', like this:") speak def speak = println(greeting) val greeting = if (sayHello) "Hello" else "Hi" println("I will say '" + greeting + "' now.") speak }
Z tego powodu podczas kompilacji generowane jest ostrzeżenie.
$ scalac Constructors3.scala Constructors3.scala:2: warning: Reference to uninitialized value greeting println("I will say '" + greeting + "', like this:") ^ one warning found
Wartość greeting wyświetlana jest w wierszach i , czyli zanim została zdefiniowana w wierszu . Jej wartość jest wtedy równa null. Natomiast instrukcje z wierszy i , czyli znajdujące się już po jej definicji, pokazują wartość różną od null.
scala> val c = new Constructors3(false) I will say 'null', like this: null I will say 'Hi' now. Hi c: Constructors3 = Constructors3@1b3d178 scala> c.speak Hi
Oprócz głównego konstruktora, klasa może posiadać konstruktory dodatkowe, zwane też pomocniczymi. Te konstruktory tworzy się definiując metody o nazwie this. Można zdefiniować wiele dodatkowych konstruktorów. Każdy z nich musi na początku wywołać inny konstruktor, przy czym może to być konstruktor główny lub jeden z konstruktorów dodatkowych zdefiniowanych wcześniej. Każdy dodatkowy konstruktor musi zawierać listę parametrów — nawet jeśli ta lista jest pusta.
Plik Constructors4.scala: class Constructors4(hello: String, name: String) { println("In the main constructor") def this(hello: String) = { this(hello, "John") println("In the first additional constructor") } def this() = { this("Hello") println("In the second additional constructor") } def greet = hello + " " + name }
Klasa Constructors4, z pliku Constructors4.scala, zawiera definicje dwóch dodatkowych konstruktorów. Poniższe przykłady pokazują różne sposoby tworzenia instancji tej klasy.
scala> val d = new Constructors4() In the main constructor In the first additional constructor In the second additional constructor d: Constructors4 = Constructors4@139d019 scala> val e = new Constructors4("Hi") In the main constructor In the first additional constructor e: Constructors4 = Constructors4@87f8ec scala> val f = new Constructors4("Hi", "Peter") In the main constructor f: Constructors4 = Constructors4@e7fffa scala> val g = new Constructors4 In the main constructor In the first additional constructor In the second additional constructor g: Constructors4 = Constructors4@1f65192
Definicje klas Constructors5 i Constructors6 zawierają błędy. Definicje są umieszczone w plikach Constructors5.scala i Constructors6.scala
Plik Constructors5.scala: class Constructors5(hello: String, name: String) { def this = this("Hi", "John") def this(hello: String) = { println("In an additional constructor") this(hello, "John") } def greet = hello + " " + name }
Plik Constructors6.scala: class Constructors6(hello: String, name: String) { def this() = this("Hello") def this(hello: String) = this(hello, "John") def greet = hello + " " + name }
Oto wyjaśnienia błędów:
- wiersz — definicja konstruktora nie zawiera listy parametrów,
- wiersz — pierwszą instrukcją konstruktora dodatkowego powinno być wywołanie innego konstruktora,
- wiersz — konstruktor nie może się odwoływać do innego konstruktora zdefiniowanego po nim.
$ scalac Constructors5.scala Constructors5.scala:2: error: auxiliary constructor needs non-implicit parameter list def this = this("Hi", "John") ^ Constructors5.scala:4: error: 'this' expected but identifier found. println("In an additional constructor") ^ two errors found $ scalac Constructors6.scala Constructors6.scala:2: error: called constructor's definition must precede calling constructor's definition def this() = this("Hello") ^ one error found
Specyfikacja języka Scala opisuje definiowanie konstruktorów w punkcie 5.3.1. |