Klasy w Scali są wzorcami do tworzenia obiektów. Klasy mogą zawierać metody, wartości, zmienne, typy, obiekty, cechy i klasy; wszystkie one są nazywane składnikami klasy (class members). Typy, obiekty i cechy zostaną omówione w dalszej części przewodnika.
Definiowanie klasy
Minimalna definicja klasy składa się ze słowa kluczowego class
oraz jej identyfikatora.
Nazwy klas powinny zaczynać się z wielkiej litery.
class User
val user1 = new User
Do tworzenia nowych instancji klasy służy słowo kluczowe new
.
Ponieważ żaden konstruktor nie został zdefiniowany, klasa User
posiada konstruktor domyślny, który nie przyjmuje żadnych parametrów.
Zazwyczaj jednak definiujemy konstruktor i ciało klasy.
Poniższy przykład przedstawia definicję klasy służącej do reprezentowania punktu.
class Point(var x: Int, var y: Int) {
def move(dx: Int, dy: Int): Unit = {
x = x + dx
y = y + dy
}
override def toString: String =
s"($x, $y)"
}
val point1 = new Point(2, 3)
point1.x // 2
println(point1) // wyświetla (2, 3)
Klasa Point
ma cztery składniki: zmienne x
i y
oraz metody move
i toString
.
W przeciwieństwie do innych języków programowania, główny konstruktor zawiera się w sygnaturze klasy: (var x: Int, var y: Int)
.
Metoda move
przyjmuje jako parametry dwie liczby całkowite i zwraca wartość ()
typu Unit
, która nie niesie ze sobą żadnych informacji.
Odpowiada to słowu kluczowemu void
w językach Java - podobnych.
Metoda toString
nie przyjmuje żadnych parametrów, ale zwraca wartość typu String
.
Ponieważ toString
nadpisuje metodę toString
zdefiniowaną w AnyRef
, jest ona dodatkowo oznaczona słowem kluczowym override
.
Konstruktory
Konstruktory mogą zawierać parametry opcjonalne - wystarczy dostarczyć wartość domyślną dla takiego parametru.
class Point(var x: Int = 0, var y: Int = 0)
val origin = new Point // x i y są mają wartość 0
val point1 = new Point(1)
println(point1.x) // wyświetla 1
W tej wersji klasy Point
, x
oraz y
mają domyślną wartość 0
- dlatego nie jest wymagane przekazanie żadnych parametrów.
Jednak z powodu tego, że konstruktor jest ewaluowany od lewej do prawej strony, jeżeli chcesz przekazać parametr tylko do argumentu y
, musisz określić nazwę tego parametru.
class Point(var x: Int = 0, var y: Int = 0)
val point2 = new Point(y = 2)
println(point2.y) // wyświetla 2
Jest to również dobra praktyka, która zwiększa przejrzystość kodu.
Prywatne składniki oraz składnia getterów i setterów
Domyślnie wszystkie składniki klasy są publiczne.
Aby ukryć je przed zewnętrznymi klientami (wszystkim co jest poza daną klasą), należy użyć słowa kluczowego private
.
class Point {
private var _x = 0
private var _y = 0
private val bound = 100
def x = _x
def x_= (newValue: Int): Unit = {
if (newValue < bound) _x = newValue else printWarning
}
def y = _y
def y_= (newValue: Int): Unit = {
if (newValue < bound) _y = newValue else printWarning
}
private def printWarning = println("UWAGA: wartość poza przedziałem")
}
val point1 = new Point
point1.x = 99
point1.y = 101 // wyświetla ostrzeżenie
W powyższym przykładnie klasy Point
dane przechowywane są w prywatnych zmiennych _x
i _y
.
Publiczne metody def x
i def y
istnieją w celu uzyskania dostępu do prywatnych danych - są to gettery.
Metody def x_=
i def y_=
(settery) służą do walidacji oraz ustawiania wartości zmiennych _x
i _y
.
Zwróć uwagę na specyficzną składnię dla setterów: posiadają one _=
dołączone do nazwy, dopiero w dalszej kolejności zdefiniowane są ich parametry.
Parametry głównego konstruktora oznaczone przez val
i var
są publiczne.
Ponieważ val
jest niezmienne, poniższy kod nie jest prawidłowy
class Point(val x: Int, val y: Int)
val point = new Point(1, 2)
point.x = 3 // <-- nie kompiluje się
Parametry konstruktora nie zawierające val
lub var
są prywatne - widoczne jedynie we wnętrzu klasy.
class Point(x: Int, y: Int)
val point = new Point(1, 2)
point.x // <-- nie kompiluje się
Contributors to this page:
Contents
- Wprowadzenie
- Podstawy
- Hierarchia typów
- Klasy
- Domyślne wartości parametrów
- Parametry nazwane
- Cechy
- Krotki
- Kompozycja klas przez domieszki
- Funkcje wyższego rzędu
- Funkcje zagnieżdżone
- Rozwijanie funkcji (Currying)
- Klasy przypadków
- Dopasowanie wzorców (Pattern matching)
- Obiekty singleton
- Wzorce wyrażeń regularnych
- Obiekty ekstraktorów
- For Comprehensions
- Klasy generyczne
- Wariancje
- Górne ograniczenia typów
- Dolne ograniczenia typów
- Klasy wewnętrzne
- Typy abstrakcyjne
- Typy złożone
- Jawnie typowane samoreferencje
- Parametry domniemane
- Konwersje niejawne
- Metody polimorficzne
- Lokalna inferencja typów
- Operatory
- Parametry przekazywane według nazwy
- Adnotacje
- Pakiety i importy
- Obiekty pakietu