Spec-Zone.ru › Kotlin 1.7

Классы

Классы в Kotlin объявляются с помощью ключевого слова class:

class Person { /*...*/ }

Объявление класса состоит из имени класса, заголовка класса (указывающего параметры типа, первичный конструктор и некоторые другие вещи) и тела класса, заключённого в фигурные скобки. И заголовок, и тело являются необязательными; если у класса нет тела, фигурные скобки можно опустить.

class Empty

Конструкторы

Класс в Kotlin может иметь первичный конструктор и один или несколько вторичных конструкторов. Первичный конструктор является частью заголовка класса и следует за именем класса и необязательными параметрами типа.

class Person constructor(firstName: String) { /*...*/ }

Если первичный конструктор не имеет аннотаций или модификаторов видимости, ключевое слово constructor можно опустить:

class Person(firstName: String) { /*...*/ }

Первичный конструктор не может содержать никакого кода. Код инициализации можно поместить в блоки инициализации, которые предваряются ключевым словом init.

Во время инициализации экземпляра блоки инициализации выполняются в том же порядке, что и они появляются в теле класса, чередуясь с инициализаторами свойств:

//sampleStart
class InitOrderDemo(name: String) {
    val firstProperty = "First property: $name".also(::println)
    
    init {
        println("First initializer block that prints $name")
    }
    
    val secondProperty = "Second property: ${name.length}".also(::println)
    
    init {
        println("Second initializer block that prints ${name.length}")
    }
}
//sampleEnd

fun main() {
    InitOrderDemo("hello")
}

Параметры первичного конструктора могут использоваться в блоках инициализации. Они также могут использоваться в инициализаторах свойств, объявленных в теле класса:

class Customer(name: String) {
    val customerKey = name.uppercase()
}

Kotlin имеет краткую синтаксическую конструкцию для объявления свойств и их инициализации из первичного конструктора:

class Person(val firstName: String, val lastName: String, var age: Int)

Такие объявления также могут включать значения по умолчанию для свойств класса:

class Person(val firstName: String, val lastName: String, var isEmployed: Boolean = true)

При объявлении свойств класса можно использовать запятую в конце:

class Person(
    val firstName: String,
    val lastName: String,
    var age: Int, // trailing comma
) { /*...*/ }

Так же, как и обычные свойства, свойства, объявленные в первичном конструкторе, могут быть изменяемыми (var) или неизменяемыми (val).

Если у конструктора есть аннотации или модификаторы видимости, ключевое слово constructor требуется, а модификаторы идут перед ним:

class Customer public @Inject constructor(name: String) { /*...*/ }

Узнайте больше о модификаторах видимости.

Вторичные конструкторы

Класс также может объявлять вторичные конструкторы, которые предваряются constructor:

class Person(val pets: MutableList<Pet> = mutableListOf())

class Pet {
    constructor(owner: Person) {
        owner.pets.add(this) // adds this pet to the list of its owner's pets
    }
}

Если у класса есть первичный конструктор, каждый вторичный конструктор должен делегировать первичному конструктору, либо напрямую, либо косвенно через другие вторичные конструкторы. Делегирование другому конструктору того же класса выполняется с помощью ключевого слова this:

class Person(val name: String) {
    val children: MutableList<Person> = mutableListOf()
    constructor(name: String, parent: Person) : this(name) {
        parent.children.add(this)
    }
}

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

Даже если у класса нет первичного конструктора, делегирование всё равно происходит неявно, и блоки инициализации всё равно выполняются:

//sampleStart
class Constructors {
    init {
        println("Init block")
    }

    constructor(i: Int) {
        println("Constructor $i")
    }
}
//sampleEnd

fun main() {
    Constructors(1)
}

Если класс без абстрактных методов не объявляет никаких конструкторов (первичный или вторичный), у него будет сгенерированный первичный конструктор без аргументов. Видимость конструктора будет public.

Если вы не хотите, чтобы у вашего класса был общедоступный конструктор, объявите пустой первичный конструктор с не по умолчанию видимостью:

class DontCreateMe private constructor() { /*...*/ }

В JVM, если у всех параметров первичного конструктора есть значения по умолчанию, компилятор сгенерирует дополнительный конструктор без параметров, который будет использовать значения по умолчанию. Это упрощает использование Kotlin с библиотеками, такими как Jackson или JPA, которые создают экземпляры классов через конструкторы без параметров.

class Customer(val customerName: String = "")

Создание экземпляров классов

Для создания экземпляра класса вызывайте конструктор так, как если бы это была обычная функция:

val invoice = Invoice()

val customer = Customer("Joe Smith")

В Kotlin нет ключевого слова new.

Процесс создания экземпляров вложенных, внутренних и анонимных внутренних классов описан в Вложенных классах.

Члены класса

Классы могут содержать:

  • Конструкторы и блоки инициализации

  • Функции

  • Свойства

  • Вложенные и внутренние классы

  • Объявления объектов

Наследование

Классы могут наследоваться друг от друга и образовывать иерархии наследования. Узнайте больше о наследовании в Kotlin.

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

Класс может быть объявлен abstract, вместе с некоторыми или всеми его членами. Абстрактный член не имеет реализации в своём классе. Вам не нужно добавлять аннотации к абстрактным классам или функциям с open.

abstract class Polygon {
    abstract fun draw()
}

class Rectangle : Polygon() {
    override fun draw() {
        // draw the rectangle
    }
}

Вы можете переопределить не абстрактный open член абстрактным.

open class Polygon {
    open fun draw() {
        // some default polygon drawing method
    }
}

abstract class WildShape : Polygon() {
    // Classes that inherit WildShape need to provide their own
    // draw method instead of using the default on Polygon
    abstract override fun draw()
}

Объекты-компаньоны

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

Более конкретно, если вы объявляете объект-компаньон внутри вашего класса, вы можете получить доступ к его членам, используя только имя класса как квалификатор.

Последнее изменение: 02 августа 2022
Пакеты и импорты Наследование

© 2010–2022 JetBrains s.r.o. and Kotlin Programming Language contributors
Licensed under the Apache License, Version 2.0.
https://kotlinlang.org/docs/classes.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API