2017-06-28 36 views
5

今天我遇到了一個非常奇怪的運行時錯誤,同時開發涉及SAM轉換和子分類的kotlin/android。Kotlin SAM運行時錯誤:NoSuchMethodError:沒有靜態方法

下面是純java + kotlin的一個簡單示例。這裏有兩個Java類:

public class A { 
    public interface I { 
     public void f(); 
    } 

    public I i; 
} 

public class B extends A {} 

,這裏是一個科特林主要功能:

fun main(args: Array<String>) { 
    A().i = B.I {} 
} 

此代碼編譯正常,但在運行時我收到以下錯誤:

Exception in thread "main" java.lang.NoSuchMethodError: B.I(Lkotlin/jvm/functions/Function0;)LA$I; 
     at MainKt.main(Main.kt:2) 

現在,這已經很糟糕了 - 如果這樣的代碼不起作用(我從來不會猜到)編譯器應該引發錯誤。但至少有人可以說,通過子類B而不是定義A(即,A.I)的地址參考接口I是不好的主意。

這是不太清楚不過,如果這個代碼是在子類的B在那裏我可以參考I直接使用I

class C: B { 
    constructor() { 
     this.i = I {} 
    } 
} 

所以我的問題是:

  1. 這是爲什麼行爲發生在所有?
  2. 如果正在發生,爲什麼編譯器不會引發錯誤?

PS:在Android上的錯誤信息類似於此,它是更加混亂:

Caused by: java.lang.NoSuchMethodError: No static method OnFocusChangeListener(Lkotlin/jvm/functions/Function2;)Landroid/view/View$OnFocusChangeListener; in class Landroid/widget/LinearLayout; or its super classes (declaration of 'android.widget.LinearLayout' appears in /system/framework/framework.jar:classes2.dex) 
+2

主要方法似乎前端認可' BI {}'作爲函數調用,lambda參數在括號外。我敢打賭,這是失敗假設的結果。 Verifier(或者他們命名的)確實發現'B.I'表示通過JLS後面的某個名稱註冊中心(允許通過子類型引用超類型靜態成員)的有效SAM界面。編譯器後端的名稱系統不遵循JLS(因爲kotlin沒有靜態),但是在'B.java'中沒有發現'B.I' *聲明*,所以它期望它是一個函數調用。這只是一個隨機猜測。 – glee8e

+1

結論我的猜測:編譯器前端和後端有不同的政策*是否允許通過子類型引用的超類型靜態成員*。您應該在[kotlin youtrack](https://youtrack.jetbrains.com/issues/KT)上提出問題。 – glee8e

+1

https://youtrack.jetbrains.com/issue/KT-18745 – dpoetzsch

回答

0

定義爲靜態的喜歡 -

companion object { 
    @JvmStatic fun main(args: Array<String>) { 
     A().i = B.I {} 
    } 
} 
+0

這並不能解決我的問題 – dpoetzsch

相關問題