Классы
Классы в Kotlin объявляются с помощью использования ключевого слова class
.
class Person { /*...*/ }
Объявление класса состоит из имени класса, заголовка (указания типов его параметров, основного конструктора и т.п) и тела класса, заключённого в фигурные скобки. И заголовок, и тело класса являются необязательными составляющими. Если у класса нет тела, фигурные скобки могут быть опущены.
class Empty
Конструкторы
Класс в Kotlin может иметь основной конструктор (primary constructor) и один или более дополнительных конструкторов (secondary constructors). Основной конструктор является частью заголовка класса, его объявление идёт сразу после имени класса (и необязательных параметров).
class Person constructor(firstName: String) { /*...*/ }
Если у основного конструктора нет аннотаций и модификаторов видимости, ключевое слово constructor
может быть опущено.
class Person(firstName: String) { /*...*/ }
Основной конструктор не может содержать в себе исполняемого кода. Инициализирующий код может быть помещён в соответствующие блоки (initializers blocks),
которые помечаются словом init
.
При создании экземпляра класса блоки инициализации выполняются в том порядке, в котором они идут в теле класса, чередуясь с инициализацией свойств.
class InitOrderDemo(name: String) {
val firstProperty = "Первое свойство: $name".also(::println)
init {
println("Первый блок инициализации: ${name}")
}
val secondProperty = "Второе свойство: ${name.length}".also(::println)
init {
println("Второй блок инициализации: ${name.length}")
}
}
Обратите внимание, что параметры основного конструктора могут быть использованы в инициализирующем блоке. Они также могут быть использованы при инициализации свойств в теле класса.
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, // завершающая запятая
) { /*...*/ }
Свойства, объявленные в основном конструкторе, могут быть изменяемые (var
) и неизменяемые (val
).
Если у конструктора есть аннотации или модификаторы видимости, ключевое слово constructor
обязательно, и модификаторы используются перед ним.
class Customer public @Inject constructor(name: String) { /*...*/ }
Для более подробной информации см. “Модификаторы доступа”.
Дополнительные конструкторы
В классах также могут быть объявлены дополнительные конструкторы (secondary constructors), перед которыми используется ключевое слово constructor
.
class Person(val pets: MutableList<Pet> = mutableListOf())
class Pet {
constructor(owner: Person) {
owner.pets.add(this) // добавляет этого питомца в список домашних животных своего владельца
}
}
Если у класса есть основной конструктор, каждый дополнительный конструктор должен прямо или косвенно ссылаться (через другой(ие) конструктор(ы)) на основной.
Осуществляется это при помощи ключевого слова this
.
class Person(val name: String) {
val children: MutableList<Person> = mutableListOf()
constructor(name: String, parent: Person) : this(name) {
parent.children.add(this)
}
}
Обратите внимание, что код в блоках инициализации фактически становится частью основного конструктора. Дополнительный конструктор ссылается на основной при помощи своего первого оператора, поэтому код во всех блоках инициализации, а также инициализация свойств выполняется перед выполнением кода в теле дополнительного конструктора.
Даже если у класса нет основного конструктора на него все равно происходит неявная ссылка и блоки инициализации выполняются также.
class Constructors {
init {
println("Блок инициализации")
}
constructor(i: Int) {
println("Constructor $i")
}
}
Если в абстрактном классе не объявлено никаких конструкторов (основного или дополнительных), у этого класса автоматически сгенерируется пустой конструктор без параметров. Видимость этого конструктора будет public.
Если вы не желаете иметь класс с открытым public конструктором, вам необходимо объявить пустой конструктор с соответствующим модификатором видимости.
class DontCreateMe private constructor () { /*...*/ }
В JVM компилятор генерирует дополнительный конструктор без параметров в случае, если все параметры основного конструктора имеют значения по умолчанию. Это делает использование таких библиотек, как Jackson и JPA, более простым с Kotlin, так как они используют пустые конструкторы при создании экземпляров классов.
> class Customer(val customerName: String = "") > ``` <a name="creating-instances-of-classes"></a> <!-- ## Creating instances of classes --> ## Создание экземпляров классов <!-- To create an instance of a class, call the constructor as if it were a regular function: --> Для создания экземпляра класса конструктор вызывается так, как если бы он был обычной функцией. ```kotlin val invoice = Invoice() val customer = Customer("Joe Smith")
В Kotlin нет ключевого слова
new
.
Создание экземпляров вложенных, внутренних и анонимных внутренних классов описано в разделе Вложенные классы.
Члены класса
Классы могут содержать в себе:
Наследование
Классы могут быть производными друг от друга и формировать иерархии наследования. Узнайте больше о наследовании в Котлине.
Абстрактные классы
Класс может быть объявлен как abstract
со всеми или некоторыми его членами. Абстрактный член не имеет реализации в своём классе.
Обратите внимание, что нам не надо аннотировать абстрактный класс или функцию словом open
- это и так подразумевается.
abstract class Polygon {
abstract fun draw()
}
class Rectangle : Polygon() {
override fun draw() {
// рисование прямоугольника
}
}
Можно переопределить неабстрактный open
член абстрактным.
open class Polygon {
open fun draw() {
// некоторый метод рисования полигонов по умолчанию
}
}
abstract class WildShape : Polygon() {
// Классы, которые наследуют WildShape, должны предоставлять свой собственный
// метод рисования вместо использования по умолчанию для полигона
abstract override fun draw()
}
Вспомогательные объекты
Если вам нужно написать функцию, которая может быть использована без создания экземпляра класса, имеющую доступ к данным внутри этого класса (к примеру, фабричный метод), вы можете написать её как член объявления объекта внутри этого класса.
В частности, если вы объявляете вспомогательный объект в своём классе, у вас появляется возможность обращаться к членам класса, используя только название класса в качестве классификатора.