Классы
Как и другие объектно-ориентированные языки, Kotlin использует классы для инкапсуляции данных (свойств) и поведения (функций), создавая повторно используемый структурированный код.
Классы — это чертежи или шаблоны объектов, которые создаются с помощью конструкторов. Когда вы создаёте экземпляр класса, вы создаёте конкретный объект на основе этого шаблона.
В Kotlin предусмотрен лаконичный синтаксис для объявления классов. Чтобы объявить класс, используйте ключевое слово class, за которым следует имя класса:
class Person { /*...*/ }
Объявление класса состоит из следующих частей:
-
Заголовок класса, включающий, помимо прочего:
Ключевое слово
classИмя класса
Параметры типа (если есть)
Первичный конструктор (необязательно)
-
Тело класса (необязательно), заключённое в фигурные скобки
{}и содержащее члены класса, например:
Заголовок и тело класса могут быть минимальными. Если у класса нет тела, фигурные скобки {} можно опустить:
// Class with primary constructor, but without a body class Person(val name: String, var age: Int)
Ниже приведён пример объявления класса с заголовком и телом, а затем создания его экземпляра:
// Person class with a primary constructor
// that initializes the name property
class Person(val name: String) {
// Class body with age property
var age: Int = 0
}
fun main() {
// Creates an instance of the Person class by calling the constructor
val person = Person("Alice")
// Accesses the instance's properties
println(person.name)
// Alice
println(person.age)
// 0
}
Создание экземпляров
Экземпляр создаётся, когда вы используете класс как шаблон для создания реального объекта, с которым будет работать ваша программа.
Чтобы создать экземпляр класса, укажите имя класса, за которым следуют круглые скобки (), как при вызове функции:
// Creates an instance of the Person class val anonymousUser = Person()
В Kotlin можно создавать экземпляры:
Без аргументов (
Person()): создаётся экземпляр со значениями по умолчанию, если они объявлены в классе.С аргументами (
Person(value)): создаётся экземпляр с указанными значениями.
Созданный экземпляр можно присвоить изменяемой (var) или доступной только для чтения (val) переменной:
// Creates an instance using the default value
// and assigns it to a mutable variable
var anonymousUser = Person()
// Creates an instance by passing a specific value
// and assigns it to a read-only variable
val namedUser = Person("Joe")
Экземпляры можно создавать там, где это необходимо: внутри функции main(), внутри других функций или внутри другого класса. Кроме того, экземпляры можно создавать внутри другой функции, а затем вызывать эту функцию из main().
Следующий код объявляет класс Person со свойством для хранения имени. В нём также показано, как создать экземпляр со значением по умолчанию конструктора и с указанным значением:
// Class header with a primary constructor
// that initializes name with a default value
class Person(val name: String = "Sebastian")
fun main() {
// Creates an instance using the default constructor's value
val anonymousUser = Person()
// Creates an instance by passing a specific value
val namedUser = Person("Joe")
// Accesses the instances' name property
println(anonymousUser.name)
// Sebastian
println(namedUser.name)
// Joe
}
Сведения о создании экземпляров вложенных, внутренних и анонимных внутренних классов см. в разделе Вложенные классы.
Конструкторы и блоки инициализации
При создании экземпляра класса вызывается один из его конструкторов. В Kotlin у класса может быть первичный конструктор и один или несколько вторичных конструкторов.
Первичный конструктор — это основной способ инициализации класса. Он объявляется в заголовке класса. Вторичный конструктор задаёт дополнительную логику инициализации и объявляется в теле класса.
Первичный и вторичные конструкторы необязательны, но у класса должен быть как минимум один конструктор.
Первичный конструктор
Первичный конструктор задаёт начальное состояние экземпляра при его создании.
Чтобы объявить первичный конструктор, укажите его в заголовке класса после имени класса:
class Person constructor(name: String) { /*...*/ }
Если у первичного конструктора нет аннотаций или модификаторов видимости, ключевое слово constructor можно опустить:
class Person(name: String) { /*...*/ }
Первичный конструктор может объявлять параметры как свойства. Используйте ключевое слово val перед именем аргумента, чтобы объявить свойство, доступное только для чтения, и ключевое слово var — для изменяемого свойства:
class Person(val name: String, var age: Int) { /*...*/ }
Эти свойства-параметры конструктора хранятся в экземпляре и доступны за пределами класса.
Можно также объявить параметры первичного конструктора, которые не являются свойствами. Перед такими параметрами не указываются val или var, поэтому они не сохраняются в экземпляре и доступны только внутри тела класса:
// Primary constructor parameter that is also a property
class PersonWithProperty(val name: String) {
fun greet() {
println("Hello, $name")
}
}
// Primary constructor parameter only (not stored as a property)
class PersonWithAssignment(name: String) {
// Must be assigned to a property to be usable later
val displayName: String = name
fun greet() {
println("Hello, $displayName")
}
}
К свойствам, объявленным в первичном конструкторе, могут обращаться функции-члены класса:
// Class with a primary constructor declaring properties
class Person(val name: String, var age: Int) {
// Member function accessing class properties
fun introduce(): String {
return "Hi, I'm $name and I'm $age years old."
}
}
Первичному конструктору также можно назначить значения свойств по умолчанию:
class Person(val name: String = "John", var age: Int = 30) { /*...*/ }
Если при создании экземпляра конструктору не передано значение, для свойств используются значения по умолчанию:
// Class with a primary constructor
// including default values for name and age
class Person(val name: String = "John", var age: Int = 30)
fun main() {
// Creates an instance using default values
val person = Person()
println("Name: ${person.name}, Age: ${person.age}")
// Name: John, Age: 30
}
Параметры первичного конструктора можно использовать для инициализации дополнительных свойств класса непосредственно в теле класса:
// Class with a primary constructor
// including default values for name and age
class Person(
val name: String = "John",
var age: Int = 30
) {
// Initializes the description property
// from the primary constructor parameters
val description: String = "Name: $name, Age: $age"
}
fun main() {
// Creates an instance of the Person class
val person = Person()
// Accesses the description property
println(person.description)
// Name: John, Age: 30
}
Как и в функциях, в объявлениях конструкторов можно использовать завершающие запятые:
class Person(
val name: String,
val lastName: String,
var age: Int,
) { /*...*/ }
Блоки инициализации
Первичный конструктор инициализирует класс и задаёт его свойства. В большинстве случаев для этого достаточно простого кода.
Если при создании экземпляра нужно выполнить более сложные операции, поместите эту логику в блоки инициализации внутри тела класса. Эти блоки выполняются при вызове первичного конструктора.
Объявите блоки инициализации с помощью ключевого слова init, за которым следуют фигурные скобки {}. Внутри фигурных скобок укажите код, который должен выполняться при инициализации:
// Class with a primary constructor that initializes name and age
class Person(val name: String, var age: Int) {
init {
// Initializer block runs when an instance is created
println("Person created: $name, age $age.")
}
}
fun main() {
// Creates an instance of the Person class
Person("John", 30)
// Person created: John, age 30.
}
Добавьте столько блоков инициализации (init {}), сколько необходимо. Они выполняются в том порядке, в котором указаны в теле класса, вместе с инициализаторами свойств:
//sampleStart
// Class with a primary constructor that initializes name and age
class Person(val name: String, var age: Int) {
// First initializer block
init {
// Runs first when an instance is created
println("Person created: $name, age $age.")
}
// Second initializer block
init {
// Runs after the first initializer block
if (age < 18) {
println("$name is a minor.")
} else {
println("$name is an adult.")
}
}
}
fun main() {
// Creates an instance of the Person class
Person("John", 30)
// Person created: John, age 30.
// John is an adult.
}
//sampleEnd
В блоках инициализации можно использовать параметры первичного конструктора. Например, в приведённом выше коде первый и второй блоки инициализации используют параметры name и age первичного конструктора.
Блоки init часто используются для проверки данных. Например, можно вызвать функцию require:
class Person(val age: Int) {
init {
require(age > 0) { "age must be positive" }
}
}
Вторичные конструкторы
В Kotlin вторичные конструкторы — это дополнительные конструкторы класса, помимо первичного. Они полезны, когда нужно несколько способов инициализации класса, а также для взаимодействия с Java.
Чтобы объявить вторичный конструктор, используйте ключевое слово constructor внутри тела класса и укажите параметры конструктора в круглых скобках (). Логику конструктора поместите в фигурные скобки {}:
// Class header with a primary constructor that initializes name and age
class Person(val name: String, var age: Int) {
// Secondary constructor that takes age as a
// String and converts it to an Int
constructor(name: String, age: String) : this(name, age.toIntOrNull() ?: 0) {
println("$name created with converted age: ${this.age}")
}
}
fun main() {
// Uses the secondary constructor with age as a String
Person("Bob", "8")
// Bob created with converted age: 8
}
В приведённом выше коде вторичный конструктор делегирует вызов первичному с помощью ключевого слова this, передавая name и значение age, преобразованное в целое число.
В Kotlin вторичные конструкторы должны делегировать вызов первичному конструктору. Благодаря этому вся логика инициализации первичного конструктора выполняется до запуска логики вторичного конструктора.
Делегирование конструктора может быть:
Прямым, когда вторичный конструктор сразу вызывает первичный конструктор.
Косвенным, когда один вторичный конструктор вызывает другой, а тот делегирует вызов первичному конструктору.
Ниже показано, как работает прямое и косвенное делегирование:
// Class header with a primary constructor that initializes name and age
class Person(
val name: String,
var age: Int
) {
// Secondary constructor with direct delegation
// to the primary constructor
constructor(name: String) : this(name, 0) {
println("Person created with default age: $age and name: $name.")
}
// Secondary constructor with indirect delegation:
// this("Bob") -> constructor(name: String) -> primary constructor
constructor() : this("Bob") {
println("New person created with default age: $age and name: $name.")
}
}
fun main() {
// Creates an instance based on the direct delegation
Person("Alice")
// Person created with default age: 0 and name: Alice.
// Creates an instance based on the indirect delegation
Person()
// Person created with default age: 0 and name: Bob.
// New person created with default age: 0 and name: Bob.
}
В классах с блоками инициализации (init {}) код этих блоков становится частью первичного конструктора. Поскольку вторичные конструкторы сначала делегируют вызов первичному, все блоки инициализации и инициализаторы свойств выполняются до тела вторичного конструктора. Даже если у класса нет первичного конструктора, делегирование всё равно происходит неявно:
// Class header with no primary constructor
class Person {
// Initializer block runs when an instance is created
init {
// Runs before the secondary constructor
println("1. First initializer block runs")
}
// Secondary constructor that takes an integer parameter
constructor(i: Int) {
// Runs after the initializer block
println("2. Person $i is created")
}
}
fun main() {
// Creates an instance of the Person class
Person(1)
// 1. First initializer block runs
// 2. Person 1 created
}
Классы без конструкторов
У классов, в которых не объявлены конструкторы (первичный или вторичные), есть неявный первичный конструктор без параметров:
// Class with no explicit constructors
class Person {
// No primary or secondary constructors declared
}
fun main() {
// Creates an instance of the Person class
// using the implicit primary constructor
val person = Person()
}
Этот неявный первичный конструктор имеет общедоступный уровень видимости, то есть к нему можно обратиться из любого места. Если вы не хотите, чтобы у класса был общедоступный конструктор, объявите пустой первичный конструктор с другим уровнем видимости:
class Person private constructor() { /*...*/ }
Наследование
Наследование классов в Kotlin позволяет создать новый класс (производный класс) на основе существующего (базового класса), унаследовав его свойства и функции, а также добавив или изменив поведение.
Подробные сведения об иерархиях наследования и использовании ключевого слова open см. в разделе Наследование.
Абстрактные классы
В Kotlin абстрактные классы нельзя создавать напрямую. Они предназначены для наследования другими классами, которые определяют их фактическое поведение. Такое поведение называется реализацией.
В абстрактном классе можно объявлять абстрактные свойства и функции, которые должны быть реализованы в подклассах.
У абстрактных классов также могут быть конструкторы. Они инициализируют свойства класса и обеспечивают наличие необходимых параметров в подклассах. Чтобы объявить абстрактный класс, используйте ключевое слово abstract:
abstract class Person(val name: String, val age: Int)
Абстрактный класс может содержать как абстрактные, так и неабстрактные члены (свойства и функции). Чтобы объявить член абстрактным, необходимо явно использовать ключевое слово abstract.
Абстрактные классы или функции не нужно помечать ключевым словом open, поскольку по умолчанию они неявно допускают наследование. Подробнее о ключевом слове open см. в разделе Наследование.
У абстрактных членов нет реализации в абстрактном классе. Реализацию можно определить в подклассе или наследующем классе с помощью override функции или свойства:
// Abstract class with a primary constructor that declares name and age
abstract class Person(
val name: String,
val age: Int
) {
// Abstract member
// Doesn't provide implementation,
// and it must be implemented by subclasses
abstract fun introduce()
// Non-abstract member (has an implementation)
fun greet() {
println("Hello, my name is $name.")
}
}
// Subclass that provides an implementation for the abstract member
class Student(
name: String,
age: Int,
val school: String
) : Person(name, age) {
override fun introduce() {
println("I am $name, $age years old, and I study at $school.")
}
}
fun main() {
// Creates an instance of the Student class
val student = Student("Alice", 20, "Engineering University")
// Calls the non-abstract member
student.greet()
// Hello, my name is Alice.
// Calls the overridden abstract member
student.introduce()
// I am Alice, 20 years old, and I study at Engineering University.
}
Объекты-компаньоны
В Kotlin у каждого класса может быть объект-компаньон. Объекты-компаньоны — это разновидность объявления объекта, позволяющая обращаться к его членам по имени класса без создания экземпляра класса.
Предположим, вам нужно написать функцию, которую можно вызвать без создания экземпляра класса, но которая логически связана с классом (например, фабричную функцию). В этом случае её можно объявить внутри объявления объекта-компаньона внутри класса:
// Class with a primary constructor that declares the name property
class Person(
val name: String
) {
// Class body with a companion object
companion object {
fun createAnonymous() = Person("Anonymous")
}
}
fun main() {
// Calls the function without creating an instance of the class
val anonymous = Person.createAnonymous()
println(anonymous.name)
// Anonymous
}
Если объявить объект-компаньон внутри класса, обращаться к его членам можно, указывая только имя класса в качестве квалификатора.
Подробнее см. в разделе Объекты-компаньоны.
© 2010–2026 JetBrains s.r.o. and Kotlin Programming Language contributors
Licensed under the Apache License, Version 2.0.
https://kotlinlang.org/docs/classes.html