2015-11-13 4 views
13

Мне не удалось найти что-либо в определении языка, которое объясняет инициализацию класса в Котлине.Что такое семантика инициализации класса Kotlin?

import java.util.Properties 

fun main(args: Array<String>) { 
    val out = MyClass() 
    out.fn() 
} 

class MyClass { 
    private val a = Properties() // 1 

    init { 
     fn() 
    } 

    public fun fn() { 
     println("Fn called. a = $a") 
    } 

    // private val a = Properties() // 2 
} 

Результаты выполнения этой программы изменяются в зависимости от того, инициализировано ли свойство в (1) или (2).

Я удивлен, что заказ декларации имеет отношение к этому языку и хотел бы понять решения, стоящие за этим. Мое ожидание будет состоять в том, что свойства инициализируются перед вызовом тела конструктора.

ответ

10

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

Ну, init блок не является constructor. Это другая конструкция, которая позволяет выполнять инициализацию объекта, и они [блоки init] выполняются в порядке объявления с инициализаторами свойств.

Конструкторы - это другой зверь, и они выполняются после того, как все свойства были инициализированы, и все блоки init были выполнены. Посмотрите на следующий пример:

class A(val value: Int) { 
    constructor(): this(0) {   
     println("Constructor") 
    }  

    init { 
     println("Init block") 
    } 
} 

fun main(args: Array<String>) { 
    val a = A() 
} 

Выход:

Init block 
Constructor 

Вы можете разместить init блок, куда вы хотите: до constructor или после него; всегда будет выполняться до конструктор A (вторичный конструктор, в этом примере).

+18

Это не совсем правильно. Блоки 'init' содержат код, который включен в основной конструктор. В вашем примере они выполняются, потому что вторичный конструктор делегирует основному конструктору, используя синтаксис ': this (0)'. Если вторичный конструктор не делегирует основному конструктору, блоки init не будут выполняться, когда класс инициализируется с использованием этого конструктора. – yole

+1

Hi Aga/Yole - спасибо за ваши ответы. Вероятно, я должен был сказать, что я Kotlin n00b, но это, вероятно, ясно из моего вопроса. Я думаю, что оба ваших ответа исходят из знакомства с языком. Когда я прочитал это определение Kotlin https://kotlinlang.org/docs/kotlin-docs.pdf, единственной ссылкой, которую я нашел для init, является: «Основной конструктор не может содержать никакого кода. Код инициализации может быть помещен в блоки инициализации , которые имеют префикс ключевого слова init " Однако ничего не говорится о порядке инициализации. (Что я вижу) –

+1

@yole спасибо за разъяснение.:) – aga

4

Проще говоря: при создании экземпляра класса (почти) сначала выполняется конструктор родительского класса (если присутствует), а затем первичный конструктор.

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

class Foo(a: String = "might be first" 
      val b: String = "second" + a) : Boo(a + b + "third"){ 
    var c = a + "fourth" + b 

    init {print("fifth: $c")} 

    val d = "sixth" 
    init {print("seventh: the end of the primary constructor"} 
} 

Если вы вызываете вторичный конструктор, то он работает после того, как первичный, как она состоит в цепи (аналогичен вызову родительских конструкторов).

+1

Можете ли вы изменить свое мнение о заказе и можете удалить «почти» и «возможно», чтобы он стал решающим. Или отложить ответ от @aga –

Смежные вопросы