2017-06-28 2 views
5

Heute lief mir ein merkwürdiger Laufzeitfehler während der Entwicklung von Kotlin/Android, die SAM-Konvertierungen und Unterklassierung beinhaltet.Kotlin SAM Laufzeitfehler: NoSuchMethodError: Keine statische Methode

Hier ist ein minimales Beispiel für reines Java + Kotlin. Hier sind zwei Java-Klassen:

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

    public I i; 
} 

public class B extends A {} 

Und hier ist eine Kotlin Hauptfunktion:

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

Dieser Code kompiliert gut, aber während der Laufzeit erhalte ich folgende Fehlermeldung:

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

Jetzt , das ist schon schlecht - wenn Code wie dieser nicht funktioniert (ich denke nie), sollte der Compiler einen Fehler auslösen. Aber zumindest könnte man sagen, dass es eine schlechte Idee ist, sich auf die Schnittstelle I über die Unterklasse B anstelle des Ortes der Definition A (d. H. A.I) zu beziehen. obwohl

Es ist weniger klar, wenn dieser Code in einer Unterklasse von B ist, wo ich direkt verweisen kann II mit:

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

So würde meine Fragen sein:

  1. Warum ist dies Verhalten passiert überhaupt?
  2. Wenn es passiert, warum ist der Compiler nicht bereits einen Fehler?

PS: In android die Fehlermeldung sieht dies ähnlich, was noch verwirrender ist:

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

es, dass Frontend scheint erkannt ' BI {} 'als Funktionsaufruf mit Lambda-Argument außerhalb von Klammern. Ich wette, dass dies ein Ergebnis fehlgeschlagener Annahmen ist. Verifier (oder wie auch immer sie es nennen) hat gefunden, dass "B.I" eine gültige SAM-Schnittstelle durch irgendeine Namensregistrierung bezeichnet, die der JLS folgt (erlaubt Supertype statische Mitglieder, auf die durch Subtypen verwiesen wird). Das Compiler-Backend, dessen Namensystem nicht JLS folgt (weil Kotlin nicht statisch ist), hat jedoch 'B.I' * in' B.java' nicht deklariert, also erwartet es, dass es sich um einen Funktionsaufruf handelt. Dies ist jedoch nur eine zufällige Schätzung. – glee8e

+1

Schluss mit meiner Vermutung: Das Compiler Frontend und Backend haben unterschiedliche Richtlinien bezüglich * ob statische Supertype Member die über Subtypen referenziert sind *. Sie sollten ein Problem auf [Kotlin Youtrack] (https://youtrack.jetbrains.com/issues/KT) einreichen. – glee8e

+1

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

Antwort

0

Hauptmethode definieren als statische wie-

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

Dies löst nicht mein Problem – dpoetzsch

Verwandte Themen