2017-03-21 2 views
15

In Kotlin, der folgende Code kompiliert:Wie funktioniert das Löschen in Kotlin?

class Foo { 
    fun bar(foo: List<String>): String { 
     return "" 
    } 

    fun bar(foo: List<Int>): Int { 
     return 2; 
    } 
} 

Dieser Code jedoch nicht:

class Foo { 
    fun bar(foo: List<String>): String { 
     return "" 
    } 

    fun bar(foo: List<Int>): String { 
     return "2"; 
    } 
} 

das Kompilieren den folgenden Fehler verursachen:

Error:(8, 5) Kotlin: Platform declaration clash: The following declarations have the same JVM signature (foo(Ljava/util/List;)Ljava/lang/String;): 
    fun foo(layout: List<Int>): String 
    fun foo(layout: List<String>): String 

In Java, kein Beispiel wird kompiliert:

class Foo { 
    String bar(List<Integer> foo) { 
     return ""; 
    } 

    Integer bar(List<String> foo) { 
     return 2; 
    } 
} 

class Foo { 
    String bar(List<Integer> foo) { 
     return ""; 
    } 

    String bar(List<String> foo) { 
     return "2"; 
    } 
} 

Wenig überraschend, die beide nach dem Stand der Schnipsel erzeugen die bekannte Compiler-Fehler:

Error:(13, 12) java: name clash: bar(java.util.List<java.lang.String>) and bar(java.util.List<java.lang.Integer>) have the same erasure 

Was mich wundert ist, dass das erste Kotlin Beispiel überhaupt funktioniert, und zweitens, wenn es funktioniert, warum die zweite Kotlin Beispiel fehlschlagen ? Betrachtet Kotlin den Rückgabetyp einer Methode als Teil seiner Signatur? Warum respektieren Methodensignaturen in Kotlin im Gegensatz zu Java den vollständigen Parametertyp?

Antwort

13

Eigentlich kennt Kotlin den Unterschied zwischen den beiden Methoden in Ihrem Beispiel, aber jvm wird nicht. Deshalb ist es eine "Plattform" -Kollision.

Sie können Ihr zweites Beispiel machen kompilieren, indem Sie die @JvmName Anmerkung mit:

class Foo { 
    @JvmName("barString") fun bar(foo: List<String>): String { 
    return "" 
    } 

    @JvmName("barInt") fun bar(foo: List<Int>): String { 
    return "2"; 
    } 
} 

Diese Anmerkung besteht aus diesem Grund. Sie können mehr in der interop documentation lesen.

+0

Warum aber kompiliert das erste Kotlin-Beispiel ohne diese Annotation? Erkennt die JVM Methoden mit unterschiedlichen Rückgabetypen? Laut [dieser Antwort] (http://stackoverflow.com/a/16149445/1772342) ist der Rückgabetyp nicht Teil der Signatur einer Methode. – breandan

+0

Ah, ich verstehe. Vielleicht erlaubt Java keine identischen Name/Parameter-Methoden mit verschiedenen Rückgabetypen während der Kompilierung, aber die JVM erkennt sie? – breandan

+4

@breandan Nun ja, der Rückgabetyp ist Teil der Signatur, aber im ersten Fall ist es für die beiden Methoden unterschiedlich, (obwohl der Parameter gelöschten Typ der gleiche ist), so dass die Signaturen unterschiedlich sind. Sie sind 'foo (Ljava/util/Liste;) Ljava/lang/String;' und 'foo (Ljava/util/List;) Ljava/lang/Integer;' bzw.. Java berücksichtigt nur die Parametertypen und den Methodennamen in der Namenskonfliktprüfung, sodass das erste Beispiel in Java nicht kompiliert wird. Dies ist mehr über das Überladen und Anotyp-Löschen und kann leicht in der Sprache behoben werden (wie Kotlin) – Strelok

Verwandte Themen