2016-12-04 50 views
8

我有下面的代碼片段在科特林:科特林字符的compareTo失敗

val pair: Pair<Char,Char> = 'z' to 'z' 
val comparison = pair.first.compareTo(pair.second) 
println(comparison) 

它在第二條線失敗,以下情況例外,當我嘗試運行它:

java.lang.ClassCastException: java.lang.Character cannot be cast to java.lang.Number 

IDE(IntelliJ)不會抱怨任何錯誤的類型。這個問題與某個事實有關,因爲'z'.compareTo('z')工作正常,因此Chars來自Pair<Char, Char>。你知道Kotlin如何解決下面的問題嗎?

我使用科特林1.0.4

回答

10

TL; DR顯然,這是一個編譯器錯誤。

此行爲的原因在於Kotlin編譯器爲這兩個調用生成的字節碼。 (如果您使用IntelliJ IDEA,則可以使用the bytecode viewing tool檢查字節碼)。

首先,對於'z'.compareTo('z')呼叫產生的字節碼是:

LINENUMBER 10 L3 
BIPUSH 122 
BIPUSH 122 
INVOKESTATIC kotlin/jvm/internal/Intrinsics.compare (II)I 

它調用kotlin.jvm.internal.Intrisics.compare()比較兩個Int s,並且Char s的被推送到堆棧直接作爲Int S(BIPUSH裝置推字節整數)。

但如果你看看字節碼pair.first.compareTo(pair.second),你會發現這樣的事情:

ALOAD 1 
INVOKEVIRTUAL kotlin/Pair.getFirst()Ljava/lang/Object; 
CHECKCAST java/lang/Number 
INVOKEVIRTUAL java/lang/Number.intValue()I 

ALOAD 1 
INVOKEVIRTUAL kotlin/Pair.getSecond()Ljava/lang/Object; 
CHECKCAST java/lang/Number 
INVOKEVIRTUAL java/lang/Number.intValue()I 

INVOKESTATIC kotlin/jvm/internal/Intrinsics.compare (II)I 

它調用kotlin.jvm.internal.Intrisics.compare也是如此,但在這裏就是它試圖做之前:

  • 獲取(ALOAD 1INVOKEVIRTUAL ...行)
  • 檢查對象是否可以投射到NumberCHECKCAST ...
  • java.lang.Number.intValue()INVOKEVIRTUAL ...

第二和第三線的罪魁禍首,Char不是Number。它看起來就像是編譯器爲這個比較生成了不正確的字節碼(這對於Number類型來說是正確的,看起來像Char只是沒有單獨處理)。

Kotlin問題跟蹤器中有an issue about this,它可能會在將來的版本中修復。


要修復代碼中的呼籲,現在,我們也可以將Char s的電話之前手動:

pair.first.toInt().compareTo(pair.second.toInt())