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

Последнее обновление: 26.05.2021

Для создания объекта необходимо вызвать конструктор класса. По умолчанию компилятор создает конструктор, который не принимает параметров и который мы можем использовать. Но также мы можем определять свои собственные конструкторы. Для определения конструкторов применяется ключевое слово constructor.

Классы в Kotlin могут иметь один первичный конструктор (primary constructor) и один или несколько вторичных конструкторов (secondary constructor).

Первичный конструктор

Первичный конструктор является частью заголовка класса и определяется сразу после имени класса:

class Person constructor(_name: String){
   
}

Конструкторы, как и обычные функции, могут иметь параметры. Так, в данном случае конструктор имеет параметр _name, который представляет тип String. Через параметры конструктора мы можем передать извне данные и использовать их для инициализации объекта. При этом первичный конструктор в отличие от функций не определяет никаких действий, он только может принимать данные извне через параметры.

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

class Person(_name: String){
   
}

Инициализатор

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

class Person(_name: String){
    val name: String
    init{
        name = _name
    }
}

В классе Person определено свойство name, которое хранит имя человека. Чтобы передать эту свойству значение параметра _name из первичного конструктора, применяется блок инициализатора. Блок инициализатора определяется после ключевого слова init.

Цель инициализатора состоит в инициализации объекта при его создании. Стоит отметить, что здесь свойству name не задается начальное значение, потому это свойство в любом случае будет инициализировано в блоке инициализатора, и при создании объекта оно в любом случае получит значение.

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

fun main() {
    val tom = Person("Tom")
    val bob = Person("Bob")
    val alice = Person("Alice")
	
    println(tom.name)   // Tom
    println(bob.name)   // Bob
    println(alice.name) // Alice
}

class Person(_name: String){
    val name: String
    init{
        name = _name
    }
}

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

Стоит отметить, что в классе может быть определено одновременно несколько блоков инициализатора.

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

class Person(_name: String){
	
    val name: String = _name
}

Первичный конструктор и свойства

Первичный конструктор также может использоваться для определения свойств:

fun main() {

    val bob: Person = Person("Bob", 23)

    println("Name: ${bob.name}  Age: ${bob.age}")
}

class Person(val name: String, var age: Int){

}

Свойства определяются как и параметры, при этом их определение начинается с ключевого слова val (если их не планируется изменять) и var (если свойства должны быть изменяемыми). И в этом случае нам уже необязательно явным образом определять эти свойства в теле класса, так как их уже определяет конструктор. И при вызове конструктора этим свойствам автоматически передаются значения: Person("Bob", 23)

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

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

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

class Person(_name: String){
    val name: String = _name
    var age: Int = 0
	
    constructor(_name: String, _age: Int) : this(_name){
        age = _age
    }
}

Здесь в классе Person определен первичный конструктор, который принимает значение для установки свойства name:

class Person(_name: String)

И также добавлен вторичный конструктор. Он принимает два параметра: _name и _age. С помощью ключевого слова this вызывается первичный конструктор, поэтому через этот вызов необходимо передать значения для параметров первичного конструктора. В частности, в первичный конструктор передается значение параметра _name. В самом вторичном конструкторе устанавливается значение свойства age.

constructor(_name: String, _age: Int) : this(_name){
	age = _age
}

Таким образом, при вызове вторичного конструктора вначале вызывается первичный конструктор, срабатывает блок инициализатора, который устанавливает свойство name. Затем выполняются собственно действия вторичного конструктора, который устанавливает свойство age.

Используем данную модификацию класса Person:

fun main() {

    val tom: Person = Person("Tom")
    val bob: Person = Person("Bob", 45)
    
    println("Name: ${tom.name}  Age: ${tom.age}")
    println("Name: ${bob.name}  Age: ${bob.age}")
}

class Person(_name: String){
    val name: String = _name
    var age: Int = 0
	
    constructor(_name: String, _age: Int) : this(_name){
        age = _age
    }
}

В функции main создаются два объекта Person. Для создания объекта tom применяется первичный конструктор, который принимает один параметр. Для создания объекта bob применяется вторичный конструктор с двумя параметрами.

Консольный вывод программы:

Name: Tom  Age: 0
Name: Bob  Age: 45

При необходимости мы можем определять и больше вторичных конструкторов:

fun main() {

    val tom = Person("Tom")
    val bob = Person("Bob", 41)
    val sam = Person("Sam", 32, "JetBtains")

    println("Name: ${tom.name}  Age: ${tom.age}  Company: ${tom.company}")
    println("Name: ${bob.name}  Age: ${bob.age}  Company: ${bob.company}")
    println("Name: ${sam.name}  Age: ${sam.age}  Company: ${sam.company}")
}

class Person(_name: String){
    val name = _name
    var age: Int = 0
    var company: String = "Undefined"

    constructor(_name: String, _age: Int) : this(_name){
        age = _age
    }

    constructor(_name: String, _age: Int, _comp: String) : this(_name, _age){
         company = _comp
    }
}

Здесь в класс Person добавлено новое свойство - company, которое описывает компании, в которой работает человек. И также добавлен еще один конструктор, который принимает три параметра:

constructor(_name: String, _age: Int, _comp: String) : this(_name, _age){
	company = _comp
}

Чтобы не дублировать код установки свойств name и age, этот вторичный конструктор передает установку этих свойств другому вторичному конструктору, который принимает два параметра, через вызов this(_name, _age). То есть данный вызов по сути будет вызывать первый вторичный конструктор с двумя параметрами.

Консольный вывод программы:

Name: Tom  Age: 0  Company: Undefined
Name: Bob  Age: 41  Company: Undefined
Name: Sam  Age: 32  Company: JetBtains
Помощь сайту
WebMoney
  • P378451176208
  • Z280152397659
ЮMoney/Яндекс-Деньги
  • 410011174743222
PayPal
  • metanit22@mail.ru
Перевод на карту
  • Номер карты: 4048415020898850