que entre diferencias java kotlin extension-function

entre - Acceso a las funciones de extensión de Kotlin desde Java



diferencias entre java y kotlin (8)

¿Es posible acceder a las funciones de extensión desde el código Java?

Definí la función de extensión en un archivo Kotlin.

package com.test.extensions import com.test.model.MyModel /** * */ public fun MyModel.bar(): Int { return this.name.length() }

Donde MyModel es una clase Java (generada). Ahora, quería acceder a él en mi código normal de Java:

MyModel model = new MyModel(); model.bar();

Sin embargo, eso no funciona. El IDE no reconocerá el método bar() y la compilación falla.

Lo que sí funciona es usar una función estática de kotlin:

public fun bar(): Int { return 2*2 }

utilizando import com.test.extensions.ExtensionsPackage por lo que mi IDE parece estar configurado correctamente.

Busqué en todo el archivo de interoperabilidad Java de los documentos de Kotlin y también busqué mucho en Google, pero no pude encontrarlo.

¿Qué estoy haciendo mal? ¿Es esto posible?


Cuando extiendes una clase como esta:

fun String.concatenatedLength(str: String): Int { return (this.length + str.length) } fun f() { var len = "one string".concatenatedLength("another string") println(len) }

Se compilará para esto:

import kotlin.jvm.internal.Intrinsics; import org.jetbrains.annotations.NotNull; public final class ExampleKt { public static final int concatenatedLength(@NotNull String $receiver, @NotNull String str) { Intrinsics.checkParameterIsNotNull((Object) $receiver, (String) "$receiver"); Intrinsics.checkParameterIsNotNull((Object) str, (String) "str"); return $receiver.length() + str.length(); } public static final void f() { int len = ExampleKt.concatenatedLength("one string", "another string"); System.out.println(len); } }

Hay más ejemplos aquí .


La función de extensión de nivel superior de Kotlin se compila como métodos estáticos de Java.

Dado el archivo Kotlin Extensions.kt en el paquete foo.bar contiene:

fun String.bar(): Int { ... }

El código Java equivalente sería:

package foo.bar; class ExtensionsKt { public static int bar(String receiver) { ... } }

A menos que, es decir, Extensions.kt contenga la línea

@file:JvmName("DemoUtils")

En cuyo caso, la clase estática de Java se llamaría DemoUtils

En Kotlin, los métodos de extensión se pueden declarar de otras maneras. (Por ejemplo, como una función miembro o como una extensión de un objeto complementario).


Las otras respuestas aquí cubren el caso de llamar a una función de extensión ubicada en el nivel superior de un archivo de paquete Kotlin.

Sin embargo, mi caso fue que necesitaba llamar a una función de Extensión ubicada dentro de una Clase. Específicamente, estaba tratando con un Objeto.

La solución es increíblemente simple .

¡Todo lo que tiene que hacer es anotar su función de extensión como @JvmStatic y listo! Su código Java podrá acceder a él y usarlo.


Necesita duplicar sus funciones en los archivos de clase:

Crear archivo Kotlin, por ejemplo, Utils.kt

introduzca el código

class Utils { companion object { @JvmStatic fun String.getLength(): Int {//duplicate of func for java return this.length } } } fun String.getLength(): Int {//kotlin extension function return this.length }

O

class Utils { companion object { @JvmStatic fun getLength(s: String): Int {//init func for java return s.length } } } fun String.getLength(): Int {//kotlin extension function return Utils.Companion.getLength(this)//calling java extension function in Companion }

En el uso de kotlin:

val str = "" val lenth = str.getLength()

En Java use esto:

String str = ""; Integer lenth = Utils.getLength(str);


Por lo que puedo decir, esto no es posible. De mi lectura de las extensiones de documentos, parece que

public fun MyModel.bar(): Int { return this.name.length() }

crea un nuevo método con la firma

public static int MyModelBar(MyModel obj) { return obj.name.length(); }

Luego, Kotlin asigna esa función a llamadas de la forma myModel.bar() , donde si bar() no se encuentra en la clase MyModel , busca métodos estáticos que coincidan con la firma y el esquema de nombres que genera. Tenga en cuenta que esto es solo una suposición de sus afirmaciones sobre las extensiones que se importan estáticamente y que no anulan los métodos definidos. No he llegado lo suficientemente lejos en su fuente para saber con certeza.

Por lo tanto, suponiendo que lo anterior es cierto, no hay forma de que las extensiones de Kotlin se invoquen desde el código java antiguo, ya que el compilador solo verá un método desconocido que se llama en un objeto y se produce un error.


Siempre puede ver el código Java real que se genera a partir de su código Kotlin yendo a Tools > Kotlin > Show Kotlin Bytecode código de Tools > Kotlin > Show Kotlin Bytecode , luego haciendo clic en Decompile . Esto puede ayudarte tremendamente. En su caso, el código Java se verá así si tiene MyModelExtensions.kt

public final class MyModelExtensionsKt { public static final int bar(@NotNull MyModel $receiver) { Intrinsics.checkParameterIsNotNull($receiver, "$receiver"); return $receiver.getName().length(); } }

puedes mejorar esto usando @JvmName en el archivo que contiene la bar :

@file:JvmName("MyModels") package io.sspinc.datahub.transformation public fun MyModel.bar(): Int { return this.name.length }

y dará como resultado este código:

public final class MyModels { public static final int bar(@NotNull MyModel $receiver) { Intrinsics.checkParameterIsNotNull($receiver, "$receiver"); return $receiver.getName().length(); } }

Usar MyModels está en línea con lo que Effective Java sugiere para las clases de utilidad. También puede cambiar el nombre de su método de esta manera:

public fun MyModel.extractBar(): Int { return this.name.length }

entonces desde el lado de Java parecerá idiomático:

MyModels.extractBar(model);


Tengo un archivo Kotlin llamado NumberFormatting.kt que tiene la siguiente función

fun Double.formattedFuelAmountString(): String? { val format = NumberFormat.getNumberInstance() format.minimumFractionDigits = 2 format.maximumFractionDigits = 2 val string = format.format(this) return string }

En java, simplemente accedo a él sobre el archivo NumberFormattingKt de la siguiente manera después de la importación de import ....extensions.NumberFormattingKt; requerida import ....extensions.NumberFormattingKt;

String literString = NumberFormattingKt.formattedFuelAmountString(item.getAmount());


Todas las funciones de Kotlin declaradas en un archivo se compilarán por defecto a métodos estáticos en una clase dentro del mismo paquete y con un nombre derivado del archivo fuente de Kotlin (Primera letra en mayúscula y extensión ".kt" reemplazada por el sufijo "Kt" ) . Los métodos generados para las funciones de extensión tendrán un primer parámetro adicional con el tipo de receptor de función de extensión.

Al aplicarlo a la pregunta original, el compilador de Java verá el archivo fuente de Kotlin con el nombre example.kt

package com.test.extensions public fun MyModel.bar(): Int { /* actual code */ }

como si se declarara la siguiente clase Java

package com.test.extensions class ExampleKt { public static int bar(MyModel receiver) { /* actual code */ } }

Como no sucede nada con la clase extendida desde el punto de vista de Java, no puede simplemente usar la sintaxis de puntos para acceder a dichos métodos. Pero todavía son invocables como métodos estáticos Java normales:

import com.test.extensions.ExampleKt; MyModel model = new MyModel(); ExampleKt.bar(model);

La importación estática se puede usar para la clase ExampleKt:

import static com.test.extensions.ExampleKt.*; MyModel model = new MyModel(); bar(model);