Budući da je Kotlin objektno-orijentisani jezik, on sadrži i klasne tipove podataka. O klasama i razlozima zašto se one uvode u programskih jezicima se može pročitati na sledećoj stranici. Ovde ćemo izložiti samo nekoliko osnovnih operacija nad klasnim tipovima podataka.
Klase se u Kotlinu definišu upotrebom ključne reči class. Klasa se definiše zajedno sa parametrima svog glavnog konstruktora i svojim parametrima na sledeći način:
class ime_klase(parametar_1 : tip_parametra, ..., parametar_n : tip_parametra) { //ovo je inicijalizacioni blok naredbe... }
Pre parametara je moguće navoditi ključnu reč var ili val u zavisnosti od toga da li želimo da parametri objekta mogu da se menjaju ili ne.
U glavnom konstruktoru, mogu samo da stoje deklaracije i definicije atributa klase. Iz tog rauloga, uvode se blokovi koji počinju ključnom rečju init i čija je namena da izvšre da pripreme vrednosti atributa ili da ispisuju poruke korisniku. Takvi blokovi se izvšravaju onim redom kojim su i napisani unutar glavnog konstruktora.
Recimo, na sledećem primeru definišemo klasu Tacka sa atributima x, y i z koja predstavlja tačku u prostoru i dodatni atribut r koji predstavlja udaljenost od koordinatnog početka.
class Tacka(val _x: Double, val _y: Double, val _z: Double) { //ovo je inicijalizacioni blok val x = _x init { println("Inicijalizovali smo x: ${x}") } val y = _y init { println("Inicijalizovali smo y: ${y}") } val z = _z init { println("Inicijalizovali smo z: ${z}") } val r init { r = sqrt(x*x + y*y + z*z) println("Inicijalizovali smo r: ${r}") } }
Objekat klase se instancira na sledeći način:
val ime_objekta = ime_klase(parametar_1, ..., parametar_n)
Na našem konkretnom primeru, tačku (0, 0, 0) bismo instancirali ovako:
val A = Tacka(0.0, 0.0, 0.0)
Osim glavnog konstruktora, moguće je dodati i alternativne konstruktore. Alternativni konstruktori se dodaju u inicijalizacionom bloku pomoću constructor bloka. Da bi ispravno radili alternativni konstruktori, mora se prvo pozvati ranije definisani alternativni konstruktor ili glavni konstruktor, ukoliko glavni konstruktor postoji. To se radi na sledeći način:
class ime_klase(parametar_1 : tip_parametra, ..., parametar_n : tip_parametra) { //ovo je inicijalizacioni blok naredbe... constructor(argument_1: tip_argumenta, ..., argument_n: tip_argumenta) : this(args...) { naredbe... }
Komandom this(args...) se kreira objekat na osnovu nekog ranije definisanog konstruktora, a potom se unutar bloka mogu predefinisati neke vrednosti.
Recimo, na primeru naše klase Tacka, možemo dodati ime svakoj tački i definisati konstruktor koji prihvata i ime tačke.
class Tacka(val _x: Double, val _y: Double, val _z: Double) { //ovo je inicijalizacioni blok val x = _x init { println("Inicijalizovali smo x: ${x}") } val y = _y init { println("Inicijalizovali smo y: ${y}") } val z = _z init { println("Inicijalizovali smo z: ${z}") } val r init { r = sqrt(x*x + y*y + z*z) println("Inicijalizovali smo r: ${r}") } var name : String = ""; constructor(_x: Double, _y: Double, _z: Double) : this(_x, _y, _z, name : String){ this.name = name; } }
Metodi klase se zadaju ključnom rečju fun na sledeći način:
class ime_klase(parametar_1 : tip_parametra, ..., parametar_n : tip_parametra) { //ovo je inicijalizacioni blok naredbe... fun(argument_1: tip_argumenta, ..., argument_n: tip_argumenta) { naredbe... }
Unutar metoda je moguće koristiti i paramtre klase. Recimo, na našem primeru sa tačkom, možemo definisati metodu koja vraća rastojanje od druge tačke na sledeći način:
fun x() : Double { return this.x } fun y() : Double { return this.y } fun z() : Double { return this.z } fun distance(p: Tacka) : Double { return sqrt((p.x()-x)*(p.x()-x) + (p.y()-y)*(p.y()-y) + (p.z()-z)*(p.z()-z)) }
Metode x(), y() i z() nam služe za vraćanje parametara atributa x, y i z. Ovakve funkcije se zovu "geteri". U slučaju da su objekti klase mutabilni, mogu se dodavati i "seteri", metode koje menjaju atribute. Ovakvi metodi postoje zbog vidljivosti. Vidljivost u Kotlinu funkcioniše na isti način kao u Javi, a o tome se može detaljnije videti ovde. Osim atributa klase, mogu i metode i konstruktori imati odgovarajuću vidljivost. Tada se, kad su metode u pitanju, stavlja odgovarajući modifikator pre deklaracije funkcije. U slučaju da želimo, primera radi, da definišemo da nam glavni konstruktor bude private, tada bismo pisali ime_klase private constructor(parametri...).
Osim metoda, moguće je u klasi definisati takozvane companion objects. Companion object je specijalna vrsta objekta koji se može koristiti i bez postojanja objekta klase, kao i static metode u Javi. Ovakvi metodi mogu biti korisni u nekim situacijama.
Sintaksa ovog metoda je sledeća:
class ime_klase(parametri...) { companion object ime_objekta { metodi ili atributi... } }
Companion objects imaju i pogodnost da mogu da implementiraju interfejse. O interfejsima će biti više reči na sledećoj stranici.
Ovakvi objekti se koriste i kada ne postoji nijedna instanca klase, prostim navođenjem imena klase, kao u primeru ispod:
class ime_klase(parametri...) { companion object ime_objekta { metodi ili atributi... } } fun main() { ime_klase.metod_1(parametri...) }
U Kotlinu je, kao i u svim drugim objektno-orijentisanim jezicima, omogućeno nasleđivanje klasa. Ono funkcioniše slično kao u Javi. Za razliku od Jave, moguće je da podklasa nasledi više klasa, ali se to ne preporučuje i ređe se koristi.
Da bi klasu mogla da nasledi neka druga klasa, mora se naglasiti da je nadklasa otvorena za nasleđivanje pomoću ključne reči open na sledeći način:
open class ime_klase(parametar_1 : tip_parametra, ..., parametar_n : tip_parametra) { //ovo je inicijalizacioni blok naredbe... }
Nasleđivanje klasa funkcioniše na neki od sledeća dva načina:
open class ime_klase_1(parametar_1 : tip_parametra, ..., parametar_n : tip_parametra) { //ovo je inicijalizacioni blok naredbe... } class ime_klase_2(parametar_1 : tip_parametra, ..., parametar_n : tip_parametra) : ime_klase_1(paramtetri...) { //ovo je inicijalizacioni blok naredbe... }
U drugom slučaju, kod bi izgledao ovako:
open class ime_klase_1(parametar_1 : tip_parametra, ..., parametar_n : tip_parametra) { //ovo je inicijalizacioni blok naredbe... } class ime_klase_2 { //ovo je inicijalizacioni blok naredbe... constructor(parametri1...) : super(parametri2...) { naredbe... } }
Unutar podklase je takođe moguće predefinisati metode nadklase pomoću ključne reči override na sledeći način:
open class ime_klase_1(parametar_1 : tip_parametra, ..., parametar_n : tip_parametra) { //ovo je inicijalizacioni blok naredbe... fun neki_metod(argumenti...) { naredbe... } } class ime_klase_2 { //ovo je inicijalizacioni blok naredbe... constructor(parametri1...) : super(parametri2...) { naredbe... } override fun neki_metod(argumenti...) { naredbe... } }
Moguće je sprečiti da se metod predefiniše tako što se naznači ključnom rečju final. U tom slučaju, podklasama nije dozvoljeno da menjaju taj metod.
Klasa se može proglasiti apstraktnom i dodati joj se apstraktni metodi tako što se ispred ključnih reči class i fun stavi ključna reč abstract. Tada svaka potklasa takve klase mora implementirati te metode ili i ona biti potklasa. Ovako isto funkcioniše i u programskom jeziku Java.