Czy jest możliwy dostęp do funkcji rozszerzeń z kodu Java?
Zdefiniowałem funkcję rozszerzenia w pliku Kotlin.
package com.test.extensions
import com.test.model.MyModel
/**
*
*/
public fun MyModel.bar(): Int {
return this.name.length()
}
Gdzie MyModel
jest (wygenerowana) klasa java. Teraz chciałem uzyskać do niego dostęp w moim normalnym kodzie java:
MyModel model = new MyModel();
model.bar();
Jednak to nie działa. IDE nie rozpozna bar()
metody i kompilacja nie powiedzie się.
Co działa przy użyciu funkcji statycznej z kotlin:
public fun bar(): Int {
return 2*2
}
używając, import com.test.extensions.ExtensionsPackage
więc moje IDE wydaje się być poprawnie skonfigurowane.
Przeszukałem cały plik Java-interop z dokumentacji kotlin i dużo googlowałem, ale nie mogłem go znaleźć.
Co ja robię źle? Czy to w ogóle możliwe?
java
kotlin
extension-function
Lovis
źródło
źródło
import package com.test.extensions.MyModel
?com.test.extensions.ExtensionsPackage
Odpowiedzi:
Wszystkie funkcje Kotlin zadeklarowane w pliku zostaną domyślnie skompilowane do metod statycznych w klasie w tym samym pakiecie i z nazwą pochodzącą z pliku źródłowego Kotlin (pierwsza litera pisana wielkimi literami i rozszerzenie „.kt” zastąpione przyrostkiem „Kt” ) . Metody wygenerowane dla funkcji rozszerzających będą miały dodatkowy pierwszy parametr z typem odbiornika funkcji rozszerzającej.
Stosując to do pierwotnego pytania, kompilator Java zobaczy plik źródłowy Kotlin o nazwie example.kt
tak jakby została zadeklarowana następująca klasa Java
Ponieważ z punktu widzenia Javy nic się nie dzieje z klasą rozszerzoną, nie można po prostu użyć składni kropkowej, aby uzyskać dostęp do takich metod. Ale nadal można je wywołać jako zwykłe statyczne metody Java:
Import statyczny może być użyty dla klasy ExampleKt:
źródło
bar(model, param1, param2);
Funkcje rozszerzające najwyższego poziomu Kotlin są kompilowane jako metody statyczne Java.
Podany plik Kotlin
Extensions.kt
w pakieciefoo.bar
zawierającym:Odpowiedni kod Java wyglądałby tak:
Chyba że
Extensions.kt
zawierał linięW takim przypadku zostanie nazwana statyczna klasa Java
DemoUtils
W Kotlinie metody rozszerzające można zadeklarować na inne sposoby. (Na przykład jako funkcja składowa lub jako rozszerzenie obiektu towarzyszącego).
źródło
Mam plik Kotlin o nazwie NumberFormatting.kt, który ma następującą funkcję
W javie mam do niego łatwy dostęp przez plik NumberFormattingKt w następujący sposób po wymaganym imporcie
import ....extensions.NumberFormattingKt;
źródło
Zawsze możesz zobaczyć rzeczywisty kod Java, który jest generowany z twojego kodu Kotlin, przechodząc do
Tools > Kotlin > Show Kotlin Bytecode
, a następnie klikającDecompile
. To może Ci ogromnie pomóc. W twoim przypadku kod Java będzie wyglądał tak, jeśli maszMyModelExtensions.kt
możesz to poprawić, używając
@JvmName
na pliku zawierającymbar
:i da to taki kod:
Używanie
MyModels
jest zgodne z sugestiami Effective Java dotyczącymi klas narzędziowych. Możesz także zmienić nazwę metody w następujący sposób:to od strony Javy będzie wyglądać idiomatycznie:
źródło
Musisz zduplikować swoje funkcje w plikach klas:
Utwórz plik Kotlin dla ex Utils.kt
Wpisz kod
LUB
W kotlin użyj:
W Javie użyj tego:
źródło
Mi to pasuje:
Kotlin
Kod Java
Mój projekt to stary projekt na Androida stworzony w Javie; teraz utworzyłem pierwszy plik kotlin i dodałem zabawne rozszerzenia ciągów String.isNotNullOrEmpty (): Boolean {...}
i mogę to nazwać z pliku java za pomocą: StringUtilsKt.isNotNullOrEmpty (thestring).
Nazwa mojego pliku Kotlin to StringUtils
źródło
Inne odpowiedzi tutaj dotyczą przypadku wywołania funkcji rozszerzenia znajdującej się na najwyższym poziomie pliku pakietu Kotlin.
Jednak w moim przypadku musiałem wywołać funkcję rozszerzenia znajdującą się wewnątrz klasy. W szczególności miałem do czynienia z przedmiotem.
Rozwiązaniem jest niezwykle proste .
Wszystko, co musisz zrobić, to oznaczyć swoją funkcję rozszerzenia jako
@JvmStatic
, i voila! Twój kod Java będzie mógł uzyskać do niego dostęp i go używać.źródło
Kiedy rozszerzasz taką klasę:
Skompiluje się do tego:
Tutaj jest więcej przykładów .
źródło
O ile wiem, nie jest to możliwe. Z mojego czytania dokumentów rozszerzeń wynika, że
tworzy nową metodę z podpisem
Następnie Kotlin mapuje tę funkcję na wywołania formularza
myModel.bar()
, gdzie ifbar()
nie znajduje się wMyModel
klasie, szuka statycznych metod pasujących do sygnatury i schematu nazewnictwa, który generuje. Zauważ, że jest to tylko założenie z ich stwierdzeń, że rozszerzenia są importowane statycznie i nie zastępują zdefiniowanych metod. Nie dotarłem na tyle daleko, aby wiedzieć na pewno.Tak więc, zakładając, że powyższe jest prawdą, nie ma możliwości wywołania rozszerzeń Kotlin ze zwykłego starego kodu Java, ponieważ kompilator zobaczy po prostu nieznaną metodę wywoływaną na obiekcie i wyświetli błąd.
źródło