L'initialisation de la variable Kotlin pour la classe enfant se comporte bizarrement pour l'initialisation de la variable avec la valeur 0


16

J'ai créé la hiérarchie de classes suivante:

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

La sortie de ce code est

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

Mais si je change l'initialisation à xpartir

var x: Int = 33

à

var x: Int = 0

la sortie montre l'invocation de la méthode contrairement à la sortie ci-dessus:

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

Est-ce que quelqu'un sait pourquoi l'initialisation avec 0provoque un comportement différent de celui avec une autre valeur?


4
Pas directement lié, mais appeler des méthodes remplaçables à partir de constructeurs n'est généralement pas une bonne pratique car cela peut conduire à un comportement inattendu (et rompre efficacement le contrat / invariants de la superclasse des sous-classes).
Adam Hošek

Réponses:


18

la super classe est initialisée avant la sous-classe.

L'appel du constructeur de B appelle le constructeur de A, qui appelle la fonction f en imprimant "x dans f: 1", après que A est initialisé, le reste de B est initialisé.

Donc, essentiellement, le réglage de la valeur est écrasé.

(Lorsque vous initialisez des primitives avec leur valeur nulle dans Kotlin, elles ne se initialisent techniquement pas du tout)

Vous pouvez observer ce comportement de "remplacement" en modifiant la signature de

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

Depuis xn'est plus le primitifint , le champ est réellement initialisé à une valeur, produisant la sortie:

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

5
Lorsque vous initialisez des primitives avec leur valeur nulle dans Kotlin, techniquement, elles ne s'initialisent pas du tout, c'est ce que je voulais lire ... Merci!
deHaar

Cela ressemble toujours à un bug / incohérence.
Kroppeb

2
@Kroppeb c'est juste Java, le même comportement peut être observé dans le code Java seul. Cela n'a rien à voir avec Kotlin
Sxtanna

8

Ce comportement est décrit dans la documentation - https://kotlinlang.org/docs/reference/classes.html#derived-class-initialization-order

Si l'une de ces propriétés est utilisée dans la logique d'initialisation de la classe de base (directement ou indirectement, via une autre implémentation de membre ouvert surchargée), cela peut entraîner un comportement incorrect ou une défaillance d'exécution. Lors de la conception d'une classe de base, vous devez donc éviter d'utiliser des membres ouverts dans les constructeurs, les initialiseurs de propriété et les blocs init.

UPD:

Il y a un bogue qui produit cette incohérence - https://youtrack.jetbrains.com/issue/KT-15642

Lorsqu'une propriété est affectée en tant qu'effet secondaire d'un appel de fonction virtuelle à l'intérieur du super constructeur, son initialiseur ne remplace pas la propriété si l'expression de l'initialiseur est la valeur par défaut du type (null, zéro primitif).


1
De plus, IntelliJ vous en avertit. L'appel f()dans le initbloc de Adonne l'avertissement "Appel de la fonction non finale f dans le constructeur"
Kroppeb

Dans la documentation que vous avez fournie, il est indiqué que "l'initialisation de la classe de base est effectuée comme première étape et se produit donc avant l'exécution de la logique d'initialisation de la classe dérivée", ce qui est exactement ce qui se produit dans le premier exemple de la question. Cependant, dans le deuxième exemple, l'instruction d'initialisation ( var x: Int = 0) de la classe dérivée n'est pas exécutée du tout, ce qui est contraire à ce que dit la documentation, ce qui m'amène à penser que cela pourrait être un bogue.
Subaru Tashiro

@SubaruTashiro Oui, vous avez raison. C'est un autre problème - youtrack.jetbrains.com/issue/KT-15642 .
vanyochek
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.