sintaxis method companion java kotlin java-interop synthetic

java - method - ¿Cuál es el uso previsto de @JvmSynthetic en Kotlin?



object kotlin java (2)

En Java plano, synthetic métodos synthetic son generados por el compilador javac . Normalmente, el compilador debe crear métodos sintéticos en las clases anidadas, cuando la clase adjunta accede a los campos especificados con el modificador privado.

Dada la siguiente clase en java:

public final class SyntheticSample { public static void main(final String[] args) { SyntheticSample.Nested nested = new SyntheticSample.Nested(); out.println("String: " + nested.syntheticString); } private static final class Nested { private String syntheticString = "I''ll become a method!"; } }

cuando la clase SyntheticSample accede al campo nested.syntheticString , de hecho está llamando a un método synthetic estático generado por el compilador (llamado algo así como access$100 ).

Incluso si Kotlin expone una anotación @JvmSynthetic que es capaz de "forzar" la creación de métodos sintéticos, aconsejo no usarla en el código de "usuario" normal. Los métodos sintéticos son trucos de bajo nivel hechos por el compilador, y nunca debemos confiar en tales cosas en el código cotidiano. Creo que está ahí para admitir otras partes de la biblioteca estándar, pero deberías preguntar directamente a los muchachos de JetBrains si tienes curiosidad (prueba en el foro de discusión oficial de Kotlin )

Me he encontrado con la anotación @JvmSynthetic en kotlin-stdlib, y me pregunto para qué sirve, pero, desafortunadamente, no está documentada.

Según tengo entendido, aplicarlo a un elemento de programa agregará el modificador synthetic a los elementos de código de bytes correspondientes. Como consecuencia, el elemento se vuelve invisible desde Java:

class MyClass { @JvmSynthetic fun f() { } }

En algún lugar en el código de Java:

MyClass c = new MyClass(); c.f() // Error: cannot resolve method f()

Pero los mismos elementos todavía son visibles en el código Kotlin:

val c = MyClass() c.f() // OK

¿Es un uso válido de @JvmSynthetic ocultar declaraciones de fuentes que no son de Kotlin? ¿Es el uso previsto? ¿Cuáles son los otros casos de uso apropiados?

Como @JvmSynthetic oculta las funciones de Java, tampoco pueden ser anuladas en Java (y cuando se trata de un miembro abstract , las llamadas se convierten en AbstractMethodError ). Dado esto, ¿puedo usar @JvmSynthetic para prohibir la anulación de miembros de una clase Kotlin en las fuentes de Java?


Primero, para responder qué son realmente los métodos sintéticos, echemos un vistazo a la especificación del lenguaje Java :

11. Una construcción emitida por un compilador de Java debe marcarse como sintética si no corresponde a una construcción declarada explícita o implícitamente en el código fuente, a menos que la construcción emitida sea un método de inicialización de clase (JVMS §2.9).

La anotación @JvmSynthetic hace exactamente eso: impide el acceso desde el código fuente. El método aún aparecerá en la reflexión y luego se marcará como sintético.

Más precisamente, de la documentación de Kotlin (énfasis mío):

@JvmSynthetic

Establece el indicador ACC_SYNTHETIC en el destino anotado en el bytecode de Java.

Los objetivos sintéticos se vuelven inaccesibles para las fuentes Java en tiempo de compilación, mientras que siguen siendo accesibles para las fuentes Kotlin. Marcar el destino como sintético es un cambio compatible binario, el código Java ya compilado podrá acceder a dicho destino.

Esta anotación está pensada para casos excepcionales en los que el diseñador de API debe ocultar el destino específico de Kotlin de la API de Java mientras lo mantiene como parte de la API de Kotlin, por lo que la API resultante es idiomática para ambos.

Como se describe en el último párrafo, @JvmSynthetic es una herramienta para el diseño de API, que permite a un escritor de bibliotecas evitar la generación automática de equivalentes de Java. Probablemente, los casos de uso más populares son las funciones exclusivas de Kotlin, como la sobrecarga de operadores, los métodos de componentN() o las propiedades, que pueden tener una forma más idiomática de exponerse en Java.

Cabe destacar que el objetivo de estas anotaciones son los establecedores / captadores de propiedades, funciones y campos, básicamente todo lo que se traduce en Java a un método.

@Target([ AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER, AnnotationTarget.FIELD]) annotation actual class JvmSynthetic