Deklaracja
Klasy w Kotlin
definiuje się za pomocą słowa kluczowego class
oraz nazwy. Deklaracja może zawierać także ciało klasy w klamrach oraz nagłówek (podstawowy konstruktor wraz z parametrami). W skład ciała klasy mogą wchodzić: konstruktory, bloki inicjalizujące, funkcje, właściwości, klasy zagnieżdzone i wewnętrzne oraz wyrażenia i deklaracje obiektu. Słowo kluczowe this
podobnie jak w innych językach programowania wskazuje obiekt odbiorcy na rzecz którego następuje odwołanie do jego elementów. Może więc zatem odnosić się do np. konstruktora czy właściwości. W celu uzyskania referencji do klasy należy wykorzystać mechanizm refleksji
.
Konstruktor
Klasy mogą posiadać konstruktor podstawowy
(primary constructor
) oraz konstruktory dodatkowe
(secondary constructor
). Konstruktor podstawowy jest częścią nagłówka klasy i definiowany jest słowem kluczowym constructor
zaraz po nazwie klasy.
Konstruktor podstawowy nie posiada żadnego własnego bloku kodu. Zamiast tego inicjalizacja może mieć miejsce w blokach inicjalizujących (initializer block
), które definiuje się słowem kluczowym init
. Parametry konstruktora podstawowego mogą być wykorzystane również w przypisywaniu wartości zmiennych poza blokiem inicjalizującym.
Konstruktory dodatkowe definiowane są w ciele klasy również za pomocą słowa kluczowego constructor
, opcjonalnych argumentów oraz ciała. Jeśli klasa ma konstruktor podstawowy wówczas każdy konstruktor dodatkowy musi odnosić się do konstruktora podstawowego. Delegacja do innego konstruktora tej samej klasy odbywa się przy pomocy słowa kluczowego this
następującego po definicji argumentów konstruktora.
Jeśli klasa nie posiada żadnego konstruktora podstawowego lub dodatkowego wówczas generowany jest domyślny podstawowy konstruktor bez argumentów z widocznością public
.
Refleksja pozwala również na uzyskanie referencji do konstruktora dzięki czemu możliwe jest przekazanie go do funkcji jako parametr.
Właściwości i pola
Klasy w Kotlin w przeciwieństwie do Java
nie zawierają pól
tylko właściwości
, które składają się z pola oraz metod dostępowych.
Właściwości klasy mogą być deklarowane jako typy zmienne (var
) lub tylko do odczytu (val
). Co więcej jeśli argumenty konstruktora są zadeklarowane jako var lub val wówczas stają się automatycznie właściwościami klasy.
Ciało deklaracji poza nazwą, typem oraz inicjalizacją może definiować metody dostępowe get
oraz set
. Jeśli ciało deklaracji właściwości nie posiada akcesorów get lub set wówczas przyjmuje implementacje domyślną (get dla stałych oraz get i set dla zmiennych). Aby właściwość mogła uzyskać dostęp do swojego pola należy użyć w metodzie dostępowej identyfikatora field
. Dostęp do właściwości instancji klasy odbywa się za pomocą kropki (jeśli modyfikator dostępu na to pozwala).
Dostęp do akcesorów właściwości można uzyskać poprzez referencje dzięki refleksji.
Klasy danych
Kotlin umożliwia stworzenie klasy oznaczonej jako data
której przeznaczeniem jest trzymanie danych. Dla wszystkich właściwości klasy zadeklarowanych w konstruktorze podstawowym automatycznie tworzone są domyślne metody equals
, hashCode
, toString
, copy
oraz metody dostępowe co eliminuje boilerplate
w stosunku do odpowiednika w Java
. Data class
musi posiadać konstruktor podstawowy z argumentami oznaczonymi jako val
lub var
. Data class może implementować interfejsy lub dziedziczyć po klasie jednak nie może być oznaczone jako abstract
, open
, sealed
czy inner
.
Klasy zagdnieżdzone i wewnętrzne
Deklaracja klasy może odbywać się w ciele inne klasy. Taka klasa nazywa się klasą zagnieżdzoną
(nested class
). Dodatkowo klasa zagnieżdzona może być oznaczona słowem kluczowym inner
co sprawia, że staje się klasą wewnętrzną
(inner class
) z dostępem do elementów klasy zewnętrznej (odwołanie może nastąpić z użyciem instrukcji super@KlasaZewnętrzna
). Klasa wewnętrzna trzyma referencję do obiektu klasy zewnętrznej.
Klasy zapięczetowane
Klasa zapięczętowana
(sealed class
) pozwala na reprezentowanie ograniczonej hierarchii klas, której instancja może przyjmować jeden z typów skończonego zbioru (klasa ma ustaloną ilość podklas). Koncept sealed class jest podobny do enum class
jednakże klasa oznaczona jako sealed
może mieć kilka instancji tej samej podklasy (dla enum jest to jeden obiekt) co pozwala obiektom na przechowywanie stanu. Klasy sealed są dobrym narzędziem we współpracy z wyrażeniem when
.
Klasy inline
Klasy oznaczone jako inline
umożliwiają opakowanie typu prymitywnego
(wrapper
) bez utraty wydajności w stosunku do klas opakowań prymitywów, które nie są inline. W czasie działania obiekt klasy inline będzie kompilowany do typu bazowego i reprezentowany jako pojedyncza właściwość. Deklaracja klasy inline wymaga konstruktora podstawowego z jednym argumentem, zezwala na definiowanie właściwości i funkcji oraz implementowanie interfejsów. Nie może jednak rozszerzać innych klas i być rozszerzalną oraz nie może zawierać bloków init
, klasy wewnętrznej (inner class
) czy pól (backing fields
).
Klasy oznaczone jako inline
są podobne do aliasu typu (typealias
), jednakże alias jest zgodny z przypisanym typem podstawowym i innymi aliasami wskazującymi na ten typ (wprowadza nową nazwę na typ), a klasa inline rzeczywiście tworzy nowy typ.
Wyrażenia i deklaracje obiektu
Wyrażenie obiektu
(object expression
) jest strukturą, która umożliwia tworzenie pojedynczej instancji obiektu bez konieczności tworzenia nowego typu. Deklaruje się go za pomocą wyrażenia wraz ze słowem kluczowym object
.
Anonimowa klasa wewnętrzna
(anonymous inner class
) to klasa, która posiada dokładnie jedną instancje (jest modyfikacją kodu istniejącej klasy) bez jawnej deklaracji nowego podtypu. Object expression
może być wykorzystywane w celu stworzenia instancji klasy anonimowej.
Deklaracja obiektu
(object declaration
) jest implementacją wzorca Singleton
w Kotlin. Deklarowana jest za pomocą słowa kluczowego object
oraz nazwy i podobnie jak zwyczajna klasa może posiadać zmienne czy też funkcje. Inicjalizacja object declaration
jest oznaczona jako bezpieczna wątkowo (thread-safe
) i nie może zachodzić lokalnie, a odnoszenie się do właściwości następuje tak jak wywołanie funkcji statycznej czy pola w Java.
Obiekt towarzysza
(companion object
) jest tym samym co object declaration
jednakże deklarowany jest wewnątrz klasy za pomocą słowa kluczowego companion
oraz opcjonalnie nazwy. Klasa może posiadać tylko jeden companion object, a jeśli nie posiada on nazwy wówczas odwołanie następuje poprzez nazwę klasy i słowo Companion
(co przypomina odwołanie do pól i metod statycznych znanych z Java).
Modyfikatory dostępu
Klasy, obiekty, konstruktory, funkcje, właściwości i interfejsy mogą przyjmować jeden z czterech modyfikatorów dostępu: public
(deklaracja dostępna wszędzie), internal
(wszędzie w tym samym module), protected
(w tej samej klasie i podklasach), private
(deklaracja dostępna tylko w tej samej klasie). W przypadku braku podania modyfikatora widoczności domyślnie ustawiany jest public
. Lokalne deklaracje mają widoczność lokalną, zatem nie mogą przyjmować modyfikatorów dostępu.