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. |
Plik Constructors1.scala:
class Constructors1(hello: String) {
println("Creating a new object with parameter: " + hello)
def greet(name: String) = println(hello + " " + name)
}

