자식 클래스의 Kotlin 변수 초기화는 값이 0 인 변수를 초기화 할 때 이상하게 동작합니다.


16

다음과 같은 클래스 계층을 만들었습니다.

open class A {
    init {
        f()
    }

    open fun f() {
        println("In A f")
    }
}

class B : A() {
    var x: Int = 33

    init {
        println("x: " + x)
    }

    override fun f() {
        x = 1
        println("x in f: "+ x)
    }

    init {
        println("x2: " + x)
    }
}

fun main() {
    println("Hello World!!")
    val b = B()
    println("in main x : " + b.x)
}

이 코드의 출력은

Hello World!!
x in f: 1
x: 33
x2: 33
in main x : 33

그러나 나는 초기화 변경하는 경우 x에서을

var x: Int = 33

var x: Int = 0

출력은 위의 출력과 달리 메소드의 호출을 보여줍니다.

Hello World!!
x in f: 1
x: 1
x2: 1
in main x : 1

누구나 초기화 0가 다른 값을 가진 것과 다른 동작 을 일으키는 이유를 알고 있습니까?


4
직접 관련이 없지만 생성자에서 재정의 가능한 메서드를 호출하는 것은 예기치 않은 동작으로 이어질 수 있으며 (하위 클래스에서 수퍼 클래스 계약 / 변형을 효과적으로 중단시킬 수 있음) 일반적으로 좋은 방법이 아닙니다.
Adam Hošek

답변:


18

수퍼 클래스는 하위 클래스보다 먼저 초기화됩니다.

B의 생성자 호출은 A의 생성자를 호출하며,이 함수는 f를 "x in f : 1"로 인쇄하는 함수 f를 호출합니다. A가 초기화 된 후 나머지 B가 초기화됩니다.

따라서 기본적으로 값 설정을 덮어 씁니다.

(Kotlin에서 0 값으로 프리미티브를 초기화하면 기술적으로 전혀 초기화되지 않습니다)

서명을 다음과 같이 변경하여이 "덮어 쓰기"동작을 관찰 할 수 있습니다.

var x: Int = 0var x: Int? = 0

때문에 x더 이상 원시적 int필드는 실제로 출력을 생산하는 값으로 초기화되지 가져옵니다 :

Hello World!!
x in f: 1
x: 0
x2: 0
in main x : 0

5
Kotlin에서 제로 값으로 프리미티브를 초기화하면 기술적으로 전혀 초기화하지 않습니다 .
deHaar

이것은 여전히 ​​버그 / 불일치처럼 보입니다.
Kroppeb

2
@Kroppeb 이것은 Java 일뿐이며 Java 코드에서만 동일한 동작을 볼 수 있습니다. Kotlin
Sxtanna

8

이 동작은 설명서 ( https://kotlinlang.org/docs/reference/classes.html#derived-class-initialization-order )에 설명되어 있습니다.

이러한 속성 중 하나라도 기본 클래스 초기화 로직에서 사용되는 경우 (직접적으로 또는 다른 재정의 된 열린 멤버 구현을 통해 간접적으로) 잘못된 동작 또는 런타임 오류가 발생할 수 있습니다. 따라서 기본 클래스를 디자인 할 때는 생성자, 속성 이니셜 라이저 및 init 블록에서 열린 멤버를 사용하지 않아야합니다.

UPD :

이 불일치를 일으키는 버그가 있습니다 — https://youtrack.jetbrains.com/issue/KT-15642

속성이 수퍼 생성자 내에서 가상 함수 호출의 부작용으로 할당 된 경우, 이니셜 라이저 표현식이 유형 기본값 (null, primitive 0) 인 경우 이니셜 라이저가 속성을 겹쳐 쓰지 않습니다.


1
또한 IntelliJ는 이에 대해 경고합니다. 호출 f()에서 init의 블록은 A"생성자가 아닌 최종 함수 f를 호출"경고 제공
Kroppeb

제공 한 문서에서 "기본 클래스 초기화는 첫 번째 단계로 수행되므로 파생 클래스의 초기화 논리가 실행되기 전에 발생합니다"라고 표시됩니다. 이는 문제의 첫 번째 예에서 정확히 발생합니다. 그러나 두 번째 예에서는 var x: Int = 0파생 클래스 의 초기화 명령 ( )이 전혀 실행되지 않으므로 설명서에 나와있는 것과는 달리 이것이 버그 일 수 있다고 생각하게합니다.
스바루 타시로

@SubaruTashiro 네, 그렇습니다. 또 다른 문제는 youtrack.jetbrains.com/issue/KT-15642 입니다.
vanyochek
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.