Классы
Классы в 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.
Если вы не хотите, чтобы у вашего класса был public конструктор, объявите пустой первичный конструктор с нестандартной видимостью:
class DontCreateMe private constructor() { /*...*/ }
Создание экземпляров классов
Для создания экземпляра класса вызовите конструктор как обычную функцию:
val invoice = Invoice()
val customer = Customer("Joe Smith")
Процесс создания экземпляров вложенных, внутренних и анонимных внутренних классов описан в Вложенных классах.
Члены класса
Классы могут содержать:
Наследование
Классы могут быть производными друг от друга и образовывать иерархии наследования. Узнайте больше о наследовании в 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()
}
Компаньон-объекты
Если вам нужно написать функцию, которая может быть вызвана без наличия экземпляра класса, но которой необходим доступ к внутренностям класса (например, фабричный метод), вы можете написать её как член объявления объекта внутри этого класса.
Более конкретно, если вы объявляете компаньон-объект внутри своего класса, вы можете получить доступ к его членам, используя только имя класса в качестве квалификатора.
© 2010–2023 JetBrains s.r.o. and Kotlin Programming Language contributors
Licensed under the Apache License, Version 2.0.
https://kotlinlang.org/docs/classes.html