2017-03-21 71 views
15

在科特林,下面的代碼編譯:刪除在Kotlin中如何工作?

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

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

此代碼,但並不:

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

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

編譯,這將導致以下錯誤:

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 

在Java中,這兩個例子都不會編譯:

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"; 
    } 
} 

不出所料,無論是之前片段的產生熟悉的編譯器錯誤:

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 

讓我驚訝的是,第科特林例如在所有工作,和第二,如果它的工作原理,爲什麼第二科特林例子失敗? Kotlin是否將方法的返回類型視爲其簽名的一部分?此外,爲什麼Kotlin中的方法簽名要尊重完整的參數類型,與Java相比?

回答

13

其實Kotlin知道你的例子中兩種方法的區別,但是jvm不會。這就是爲什麼它是一個「平臺」衝突。

你可以讓你的第二個示例通過使用@JvmName註解編譯:存在這個原因

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

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

這個註解。您可以在interop documentation中閱讀更多內容。

+0

但是爲什麼第一個Kotlin示例在沒有這個註解的情況下編譯? JVM是否可以識別具有不同返回類型的方法?根據[這個答案](http://stackoverflow.com/a/16149445/1772342),返回類型不是方法簽名的一部分。 – breandan

+0

啊,我明白了。也許Java在編譯期間不允許具有不同返回類型的相同名稱/參數方法,但JVM能夠識別它們? – breandan

+4

@breandan好的,返回類型是簽名的一部分,但在第一種情況下,兩種方法是不同的(即使參數擦除類型相同),因此簽名是不同的。它們分別是'foo(Ljava/util/List;)Ljava/lang/String;'和'foo(Ljava/util/List;)Ljava/lang/Integer;'。 Java只考慮名稱衝突檢查中的參數類型和方法名稱,所以Java中的第一個示例不會編譯。這更多的是關於重載和非類型擦除,並且可以很容易地用語言修復(如Kotlin所做的那樣) – Strelok