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:

$ 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.

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.