2017-12-05 1 views
7

Es gibt eine versiegelte Klasse:versiegelte Klasse der Objekte auf mysteriöse Weise immer null, wenn sie von anderen Begleitobjekt verwiesen

sealed class Alphabet(val name: String) { 
    object A : Alphabet("A") 
    object B : Alphabet("B") 
    object C : Alphabet("C") 
    object D : Alphabet("D") 
    object E : Alphabet("E") 

    companion object { 
    val array = arrayOf(A, B, C, D, E) 
    val list = listOf(A, B, C, D, E) 
    } 

    override fun toString(): String { 
    return name 
    } 
} 

Und es gibt eine weitere Klasse mit Begleitobjekt:

class AlphabetMap { 

    companion object { 
    val map = mapOf(
     Alphabet.A to 1, 
     Alphabet.B to 2, 
     Alphabet.C to 3, 
     Alphabet.D to 4, 
     Alphabet.E to 5 
    ) 
    } 
} 

Und wenn ich drucken möchten Array (oder Liste):

class AlphabetTest { 

    @Test 
    fun printValues() { 
    Alphabet.array.forEach { print("$it ") };println() 
    Alphabet.list.forEach { print("$it ") };println() 
    } 
} 

es richtig, die Ergebnisse drucken:

A B C D E 
A B C D E 

aber wenn ich die AlphabetMap im Code initialisieren:

class AlphabetTest { 

    val m = AlphabetMap() 

    @Test 
    fun printValues() { 
    Alphabet.array.forEach { print("$it ") };println() 
    Alphabet.list.forEach { print("$it ") };println() 
    } 
} 

Das Ergebnis geheimnisvoll wird:

null B C D E 
null B C D E 

Das erste Element (A) wird

null

Wenn ich definieren

val m = AlphabetMap 

Das Ergebnis ist das gleiche.

Wenn ich AlphabetMap in der Funktion init:

@Test 
    fun printValues() { 
    val m = AlphabetMap() // or val m = AlphabetMap 
    Alphabet.array.forEach { print("$it ") };println() 
    Alphabet.list.forEach { print("$it ") };println() 
    } 

Das Ergebnis ist das gleiche:

null B C D E 
null B C D E 

aber wenn ich so init:

@Test 
    fun printValues() { 
    Alphabet.array.forEach { print("$it ") };println() 
    val m = AlphabetMap() // or val m = AlphabetMap 
    Alphabet.list.forEach { print("$it ") };println() 
    } 

Alles funktioniert jetzt :

A B C D E 
A B C D E 

Wenn ich die AlphabetMap zu

class AlphabetMap { 
    companion object { 
    val map = mapOf(
     //Alphabet.A to 1, 
     Alphabet.B to 2, 
     Alphabet.C to 3, 
     Alphabet.D to 4, 
     Alphabet.E to 5 
    ) 
    } 
} 

Das Ergebnis wird

A null C D E 
A null C D E 

umschreiben Und wenn AlphebetMap ist:

class AlphabetMap { 
    companion object { 
    val map = mapOf(
     Alphabet.E to 5 
    ) 
    } 
} 

Das Ergebnis wird:

A B C D null 
A B C D null 

Was könnte schief gehen? Ist es ein Fehler? oder Sprachfunktion?

Umgebungen: jdk1.8.0_144, OS X

<kotlin.version>1.2.0</kotlin.version> 
<kotlin.compiler.jvmTarget>1.8</kotlin.compiler.jvmTarget> 
<kotlin.compiler.incremental>false</kotlin.compiler.incremental> 
<dependency> 
    <groupId>org.jetbrains.kotlin</groupId> 
    <artifactId>kotlin-stdlib</artifactId> 
    <version>${kotlin.version}</version> 
</dependency> 

<dependency> 
    <groupId>org.jetbrains.kotlin</groupId> 
    <artifactId>kotlin-stdlib-jdk8</artifactId> 
</dependency> 
<dependency> 
    <groupId>org.jetbrains.kotlin</groupId> 
    <artifactId>kotlin-reflect</artifactId> 
</dependency> 
<dependency> 
    <groupId>org.jetbrains.kotlinx</groupId> 
    <artifactId>kotlinx-coroutines-core</artifactId> 
</dependency> 
<dependency> 
    <groupId>org.jetbrains.kotlin</groupId> 
    <artifactId>kotlin-test-junit</artifactId> 
    <scope>test</scope> 
</dependency> 
<dependency> 
    <groupId>org.jetbrains.kotlin</groupId> 
    <artifactId>kotlin-test</artifactId> 
    <scope>test</scope> 
</dependency> 
+1

Ich vermute, dass dies eine Variante des Problems der statischen Initialisierung in Java ist. –

+0

@smallufo: pls posten Sie Ihre letzte Aktualisierung als Antwort, es gehört nicht in die Frage. –

+0

@WilliMentzel OK, fertig. – smallufo

Antwort

1

Der einzige Weg, um dieses Problem zu bekommen, ist die Karte Definition außerhalb der Klasse zu verschieben:

val map = mapOf(
    Alphabet.A to 1, 
    Alphabet.B to 2, 
    Alphabet.C to 3, 
    Alphabet.D to 4, 
    Alphabet.E to 5 
) 

class AlphabetMap { 
    companion object { 

    } 
} 

Nach JetBrain der reply on youtrack und reddit, das ist Als entworfen, keine Möglichkeit, es zu lösen.

Das Problem der Zyklen bei der Initialisierung hat keine allgemeine Lösung. No egal welche Regeln wir bekommen, wenn der Initialisierer des Objekts A auf Objekt B zugreift und der Initialisierer von Objekt B auf Objekt A zugreift, wird einer von ihnen in der Lage sein, den anderen in einem nicht initialisierten Zustand zu beobachten.

Verwandte Themen