Çocuk sınıfı için Kotlin değişken başlatma 0 değerine sahip değişken başlatmak için garip davranıyor


16

Aşağıdaki sınıf hiyerarşisini oluşturdum:

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)
}

Bu kodun çıktısı

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

Ama ben başlatılması değiştirirseniz xgelen

var x: Int = 33

için

var x: Int = 0

çıktı, yukarıdaki çıktının aksine yöntemin çağrılmasını gösterir:

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

Başlatan neden 0başka bir değere sahip olandan farklı bir davranışa neden olduğunu bilen var mı ?


4
Doğrudan ilgili değil, ancak yapıcılardan geçersiz kılınan yöntemleri çağırmak genellikle iyi bir uygulama değildir, çünkü beklenmedik davranışlara yol açabilir (ve üst sınıf sözleşmesini / değişmezleri alt sınıflardan etkili bir şekilde kırabilir).
Adam Hošek

Yanıtlar:


18

süper sınıf, alt sınıftan önce başlatılır.

B'nin yapıcı çağrısı, A başlatıldıktan sonra, f işlevini "x: f: 1" olarak yazdırma f işlevini çağıran A yapıcısını çağırır, B'nin geri kalanı başlatılır.

Yani esasen, değerin ayarının üzerine yazılıyor.

(İlkelleri Kotlin'de sıfır değerleriyle başlattığınızda, teknik olarak sadece başlatmazlar)

İmzayı değiştirerek bu "üzerine yazma" davranışını gözlemleyebilirsiniz.

var x: Int = 0 için var x: Int? = 0

Yana xartık ilkel int, alan aslında çıktı üreten, bir değere başlatıldı alır:

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

5
Kotlin'de ilkel değerlerini sıfır değeriyle başlattığınızda, teknik olarak sadece ilk başta okumak istemediğim şeyleri başlatmayın ... Teşekkürler!
deHaar

Bu hala bir hata / tutarsızlık gibi görünüyor.
Kroppeb

2
@Kroppeb bu sadece Java, aynı davranış sadece Java kodunda gözlemlenebilir. Kotlin
Sxtanna

8

Bu davranış belgelerde açıklanmıştır - https://kotlinlang.org/docs/reference/classes.html#derived-class-initialization-order

Bu özelliklerden herhangi biri temel sınıf başlatma mantığında kullanılırsa (doğrudan veya dolaylı olarak, başka bir geçersiz kılınan açık üye uygulamasıyla), yanlış davranışa veya çalışma zamanı hatasına neden olabilir. Bir temel sınıf tasarlarken, bu nedenle yapıcılar, özellik başlatıcılar ve init bloklarında açık üyeler kullanmaktan kaçınmalısınız.

UPD:

Bu tutarsızlığı üreten bir hata var - https://youtrack.jetbrains.com/issue/KT-15642

Süper yapıcı içinde bir sanal işlev çağrısının yan etkisi olarak bir özellik atandığında, başlatıcı ifadesi varsayılan değer türü (null, ilkel sıfır) ise başlatıcı özelliğin üzerine yazmaz.


1
Dahası, IntelliJ sizi bu konuda uyarıyor. Arama f()içinde initblok A"yapıcı olmayan nihai fonksiyon f arama" uyarı verir
Kroppeb

Sağladığınız belgelerde, "temel sınıf başlatması ilk adım olarak yapılır ve bu nedenle türetilmiş sınıfın başlatma mantığı çalıştırılmadan önce gerçekleşir" yazıyor, bu da sorunun ilk örneğinde olduğu gibi. Bununla birlikte, ikinci örnekte, var x: Int = 0türetilmiş sınıfın başlatma talimatı ( ) hiç çalışmaz, bu da belgelerin söylediklerine aykırıdır, bu da bunun bir hata olabileceğine inanmamı sağlar.
Subaru Tashiro

@SubaruTashiro Evet, haklısın. Bu başka bir sorun - youtrack.jetbrains.com/issue/KT-15642 .
vanyochek
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.