Перейти до вмісту

Освоюємо Kotlin/Класи та об'єкти

Матеріал з Вікіпідручника


Розглянемо основи об'єктно-орієнтоване програмування (ООП) в Kotlin, а саме поняття класу та об'єкту (екземпляру класу).

Визначення простого класу

[ред.]

Клас - це спеціальна конструкція, яка об'єднує в собі змінні та функції. Функції в ООП парадигмі також називають методами класу. Змінні називаються полями (fields) класу або ж властивостями (properties). В Kotlin більш принято використовувати термін "властивості". Насправді властивості в Kotlin більш функціональні ніж поля у такій мові як Java, але для початку можна прийняти, що це майже одне і те саме. На основі одного класу може створюватись багато об'єктів (екземплярів класів) з різними значеннями властивостей класу.

Найпростіший клас, можна створити з вказанням ключового слова class та назви класу:

class Car

Створити об'єкт такого класу можна так:

fun main(){
    var car1=Car()
}

Щоправда толку з такого класу мало. Тому додами властивості класу назву та колір автомобіля:

class Car {
    var name:String=""
    var color:String=""
}
fun main(){
    var car1=Car() //створюємо об'єкт
    car1.name="Toyota" // присвоюємо назву машини
    car1.color="червоний"// присвоюємо колір машини
    var car2=Car() //створюємо другий об'єкт
    car2.name="Honda"
    car2.color="голубий"
//Виведемо інформацію про наші автомобілі
    println("Марка машини: ${car1.name}, колір: ${car1.color}")
    println("Марка машини: ${car2.name}, колір: ${car2.color}")
}
Standard input or output Результат:
Марка машини: Toyota, колір: червоний
Марка машини: Honda, колір: голубий

Як бачимо для зверення до властивості потрібно вказати назву об'єкта, точку і назву властивості об'єкта car1.name. Сама властивість класу може бути оголошеним як var так і val.

Конструктор

[ред.]

Для того, щоб зразу присвоїти значення властивостям при створенні об'єкту використовують конструктор.

class Car {
    var name:String=""
    var color:String=""
    constructor(name:String, color:String){
        this.name=name //присвоюємо властивості name значення отримане конструктором
        this.color=color
    }
}
fun main(){
    var car1=Car("Toyota", "червоний") //створюємо об'єкт
    var car2=Car("Honda", "голубий") //створюємо другий об'єкт

    println("Марка машини: ${car1.name}, колір: ${car1.color}")
    println("Марка машини: ${car2.name}, колір: ${car2.color}")
}

Зверніть увагу, що для того, щоб звернутися до властивості з середини конструктора, то використовується ключове слово this. Його потрібно використати, оскільки в нас параметр конструктора та властивість класу мають одне і те ж ім'я.

Конструкторів оголошений з ключовим словом constructor може бути багато. Вони можуть відрізнятися кількістю параметрів та їх типами.

Первинний конструктор

[ред.]

Kotlin дозволяє оголосити конструктор пряму в заголовку класу, в круглих дужках, який автоматично присвоїть значення полям. Такий конструктор називають первинним(primary). Також клас може містити інші функції, наприклад для виводу інформації про себе:

class Car (var name:String, var color:String){
    fun getInfo(){
        println("Марка машини: $name, колір: $color")
    }
}
fun main(){
    var car1=Car("Toyota", "червоний") //створюємо об'єкт
    var car2=Car("Honda", "голубий") //створюємо другий об'єкт

    car1.getInfo()
    car2.getInfo()
}

Перед дужками з параметрами при потребі пожна вказати ключове слово constructor:

class Car constructor (var name:String, var color:String){}

Це може знадобитися, якщо ми хочемо задати модифікатор доступу до конструктора (як то private):

class Car private constructor (var name:String, var color:String){}

Детальніше про модифікатори доступу дальше в розділі.

В разі необхідності можна створити додаткові вторинні конструктори з ключовим словом contructor, проте при цьому потрібно з вторинного конструктора викликати первинний конструктор:

class Car (var name:String, var color:String){

    constructor(name:String):this(name, "червоний"){ // this дозволяє викликати первинний конструктор
    }
    fun getInfo(){
        println("Марка машини: $name, колір: $color")
    }
}
fun main(){
    var car1=Car("Honda", "голубий") //створюємо об'єкт первинним конструктором
    var car2=Car("Toyota") //створюємо об'єкт з вторинним конструктором

    car1.getInfo()
    car2.getInfo()
}


Можна вручну присвоїти значення властивостям використовуючи параметри первинного конструктора. В такому разі перед параметрами конструктора не вказуються ключові слова var та val. Це дає змогу зробити додаткові дії перед присвоєнням властивостям значення. Наприклад, перевести рядок тексту у верхній регістр. Можна також окремо оголошувати поля, яких немає в конструкторі.

class Song(title_param: String, artist_param: String) {
    var title=title_param //присвоїти значення взяти з конструктора
    var artist=artist_param.uppercase() //рядок до верхнього регістру
    var playable =true // додаємо нову властивість

    fun play() {
        println("Playing the song $title by $artist")
    }
    fun stop() {
        println("Stopped playing $title")
    }
}
fun main(args: Array<String>) {
    val song1=Song("We Will Rock You", "Queen")

    println(song1.title) //прямий доступ до властивості title
    println(song1.artist) // прямий доступ до властивості artist
    println("playable="+song1.playable) //прямий доступ до властивості playable
    song1.play()
    song1.stop()
}
Standard input or output Результат:
We Will Rock You
QUEEN
playable=true
Playing the song We Will Rock You by QUEEN
Stopped playing We Will Rock You

Блоки ініціалізації

[ред.]

В класі також можуть бути від одного до багатьох init блоків, що дозволяють здійснити певні дії при створенні об'єкта.

class Car constructor (namep:String, colorp:String){
    var name:String
    var color:String

    init {
        name=namep
        color=colorp
        println("Створюємо об'єкт: $name")

    }
}
fun main(){
    var car1=Car("Toyota", "Червоний") //створюємо об'єкт
    var car2=Car("Honda", "Синій") //створюємо другий об'єкт
}
Standard input or output Результат:
Створюємо об'єкт: Toyota
Створюємо об'єкт: Honda

Класи даних

[ред.]

Часто постає необхідність оголосити клас, який би містив дані про певну сутність. При цьому потрібно здійснити рутинне оголошення гетер, сетер методів, перевизначити певні методи, як то toString. Kotlin бере на себе цю рутину. Достатньо, лиш, оголосити клас як data:

data class User(var name:String, var age:Int) {
}

Використання класу:

fun main() {
    val user1 = User("Jane", 35)
    println("Вік ${user1.age}") //отримати вік
    val (name, age) = user1 //деструктиризація об'єкту
    println("$name, $age років")
}
Standard input or output Результат:
Вік 35
Jane, 35 років

Також в цьому класі вже будуть перевизначені функції: equals()/hashCode(), toString(), componentN(), copy(). Детальніше читайте тут

Вкладені класи

[ред.]

Класи можуть вміщуватись у інші класи:

class Person {
    val name:String="Jon"
    class Document{
        val id:Int=0
        fun sayHello(){
            println("Hello")
        }
    }
}
fun main(){
    Person().name //Створюємо об'єкт і отримуємо доступ до змінної. Результат: Jon
    Person.Document().id    //Назва зовнішнього класу, 
                            // створюємо об'єкт внутрішнього класу
                            // і доступаємось до змінної
    Person.Document().sayHello() //аналогічно доступ до функції
}

Вкладеними також можуть бути інтерфейси

Внутрішні класи

[ред.]

Внутрішні класи можуть мати доступ до елементів зовнішнього класу. Для оголошення внутрішнього класу використовується ключове слово inner:

class Person {
    val name:String="Jon"
    inner class Document{
        val id:Int=0
        fun sayHello(){
            println("Ім'я особи-"+name)
        }
    }
}
fun main(){
    Person().Document().sayHello()
}


необхідно дописати про companion object