Понимание множественных конструкторов Kotlin

Простые примеры для демонстрации первичных и вторичных / множественных конструкторов в Kotlin

Эта статья была первоначально опубликована на vtsen.hashnode.dev 23 июля 2022 года.

В Kotlin у вас есть один первичный и множество вторичных конструкторов.

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

Это первичный конструктор с одним параметром.

class Example constructor(private val param1: String) {
    init {
        println("init is called.")
    }
}
Вход в полноэкранный режим Выход из полноэкранного режима

Вы также можете опустить ключевое слово constructor.

class Example(private val param1: String) {
    init {
        println("init is called.")
    }
}
Вход в полноэкранный режим Выход из полноэкранного режима

Вы НЕ можете инициализировать в первичном конструкторе. Вместо этого необходимо инициализировать код в блоке init{}.

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

Ниже приведены 2 вторичных конструктора.

class Example(private val param1: String) {

    init {
        println("init is called.")
    }

    //First secondary constructor
    constructor(
        param1: String, 
        param2: String) : this(param1) {

        println("Second constructor is called")
    }

    //Second secondary constructor
    constructor(
        param1: String, 
        param2: String, 
        param3: String) : this(param1) {

        println("Third constructor is called")
    }
}
Вход в полноэкранный режим Выход из полноэкранного режима

Здесь есть несколько важных замечаний:

  • Вы должны вызвать первичный конструктор (например, вызвать this(param1)). Не совсем так! Смотрите следующий раздел — Вызов другого вторичного конструктора
  • Вы можете объявить var или val в параметре вторичного конструктора
  • Вы можете инициализировать свой код во вторичном конструкторе

Обратите внимание, что первичный конструктор вместе с блоком init{} вызывается первым перед инициализацией вторичного конструктора.

Поэтому, если я вызову третий конструктор,

val obj = Example(param1="1", param2="2", param3="3")
Войти в полноэкранный режим Выйти из полноэкранного режима

вывод будет выглядеть следующим образом.

init is called.
Third constructor is called
Вход в полноэкранный режим Выйти из полноэкранного режима

Вызов другого вторичного конструктора

Вместо вызова первичного конструктора во вторичном конструкторе можно также вызвать другой вторичный конструктор.

В этом примере второй вторичный конструктор вызывает первый вторичный конструктор.

class Example(private val param1: String) {

    init {
        println("init is called.")
    }

    //First secondary constructor
    constructor(
        param1: String,
        param2: String) : this(param1) {

        println("Second constructor is called")
    }

    //Second secondary constructor
    constructor(
        param1: String,
        param2: String,
        param3: String) : this(param1, param2) {

        println("Third constructor is called")
    }
}
Вход в полноэкранный режим Выход из полноэкранного режима

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

init is called.
Second constructor is called
Third constructor is called
Вход в полноэкранный режим Выход из полноэкранного режима

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

Это пример пустого первичного конструктора и вторичного конструктора.

class Example() {
    init {
        println("init is called.")
    }

    constructor(param1: String): this() {
        println("Second constructor is called")
    }
}
Вход в полноэкранный режим Выход из полноэкранного режима

Однако на самом деле вам не нужно вызывать this() в вашем вторичном конструкторе. Вам также нужно изменить Example() на Example.

class Example {
    init {
        println("init is called.")
    }

    constructor(param1: String) {
        println("Second constructor is called")
    }
}
Вход в полноэкранный режим Выход из полноэкранного режима

Случай использования вторичного конструктора

Я столкнулся с необходимостью использования вторичного конструктора, когда хочу внедрить зависимость Hilt в мою модель представления.

%[https://vtsen.hashnode.dev/convert-view-model-to-use-hilt-dependency-injection]

У меня есть код вроде этого, где параметр preview используется для @preview jetpack compose. Он установлен в true только в @preview. Однако если я перенесу это изменение на использование инъекции зависимостей Hilt, она не сможет инжектировать эту зависимость.

class MainViewModel(
    private val repository: ArticlesRepository,
    preview: Boolean = false,
) : ViewModel() {
   /*...*/
}
Вход в полноэкранный режим Выход из полноэкранного режима

Таким образом, я разбиваю это на вторичный конструктор ниже.

class MainViewModel(
    private val repository: ArticlesRepository) : ViewModel() {
    constructor (
        repository: ArticlesRepository, 
        preview: Boolean) : this(repository) {
        /*...*/
    }
}
Вход в полноэкранный режим Выход из полноэкранного режима

Поэтому я использую @Inject constructor для первичного конструктора, а вторичный конструктор используется для @preview.

С реализацией Hilt это выглядит следующим образом

@HiltViewModel
class MainViewModel
    @Inject constructor(
        private val repository: ArticlesRepository,
    ) : ViewModel() {

    constructor (
        repository: ArticlesRepository, 
        preview: Boolean) : this(repository) {
        /*...*/
    }
    /*...*/
}
Вход в полноэкранный режим Выход из полноэкранного режима

Заключение

Я не часто использовал множественные конструкторы, а вы? Поэтому я задокументировал это здесь для будущего использования.


Смотрите также

  • Советы и хитрости Kotlin

Оцените статью
devanswers.ru
Добавить комментарий