Классы. Абстрактные классы

Классы. Абстрактные классы



В главное меню

Если класс абстрактный - будет базовым классом для других классов. Его экземпляры нельзя будет создавать.

Их цель — предложить реализации функций через наследование подклассам, которые могут иметь экземпляры.

Абстрактный класс объявляется с помощью ключевого слова abstract. Кроме реализованных функций, абстрактные классы включают абстрактные функции — объявления функций без реализации.


Абстрактный класс:

abstract class Worker(val name: String, var age: Int) {
    abstract fun work()
}

Метод work не реализован, но обязателен в классах наследника.


Класс, наследник

class Seller(name: String, age: Int): Worker(name, age) {
    override fun work() {
        println("Продаю товар")
    }
}

В данном классе обязательно нужно будет имплементировать метод work.

Операторы:

is - можно проверить является ли объект типом какого-то класса. Если является то в блоке if можем сразу обращаться к этому объекту как к нужному типу.

as - для явного преобразования типа


Пример:

Создаем коллекцию рабочих. Создаем на основе этого списка новый - список уборщиков

val workerCollection = mutableListOf<Worker>()
workerCollection.add(Seller("Петя", 25))
workerCollection.add(Seller("Коля", 47))
workerCollection.add(Seller("Саша", 30))
workerCollection.add(Programmer("Маша", 31, "JAVA"))
workerCollection.add(Programmer("Даня", 24, "KOTLIN"))
workerCollection.add(Programmer("Лев", 50, "C++"))
workerCollection.add(Director("Nik", 50))

val cleanerList = workerCollection.filter { it is Cleaner }.map { it as Cleaner }

for (worker in cleanerList) {
    worker.clean()
}

Переопределение полей

Мы можем переопределять не только методы, но и поля. Для этого в родительском классе их нужно пометь как open а в дочернем override.


Пример:

Родительский класс

//переменная name объявлена как val - не йнельзя присвоить новое значение, но в классе Car мы переопределили эту переменную и сделали ее var
abstract class Vehicle (open val name: String) {
    abstract fun drive()
}


Дочерний класс

class Car(override var name: String = "Машина"): Vehicle(name) {
    fun startEngine(): Boolean {
        println("Запускаю движок!")
        return true
    }

    override fun drive() {
        println("Тачка едет...")
    }
}

Если в main попытаемся поменять имя, то не получится, т.к. экземпляр класса объявлен от родительского. Нужно выполнить проверку.

if (car is Car) {
    car.name = "Машина 2"
}

Умное приведение типов - SmartCast

smartcast - если переменная car не является типом Car, то выходим из метода и остальной код выполняться не будет

if (car !is Car) return 
car.name = "Машина 2"
//У машины есть метод, но вызвать его не можем, т.е. приведен к общему типу - car.startEngine().
// Если добавим условие car is Car && - оно выполнится и будет применено ко второму
if (car is Car && car.startEngine())

Анонимные Классы

sportsMan.callWaterBoy(object : WaterBoy {
    override fun bringWater() {
        println("Ok")
    }
})

Если нужно один раз передать экземпляр класса - то можно не создавать класс, а создать объект


INLINE

Если всё, что нужно от метода - это вызывать функцию, которую ему передали - нет смысла делать это при помощи создания интерфейса или абстрактных классов.


class SportsMan {
    inline fun callWaterBoy(bringWater: () -> Unit) {
        bringWater()
    }
}

Если мы оставим без inline, то будет создан объект анонимного класса у которого будет вызван какой-то метод.

Если указываем inline, то в месте вызова функции передастся данная функция.

sportsMan.callWaterBoy {
    println("Ok")
}

А иначе - вызывали бы анонимный класс вот так

    sportsMan.callWaterBoy(object : WaterBoy {
        override fun bringWater() {
            println("Ok")
        }
    })


Report Page