Dado que Kotlin no le permite declarar directamente constantes dentro de una class como miembros static en Java, tenemos un par de opciones sobre cómo hacerlo en Kotlin. Mi pregunta es, ¿cuáles son los costos de rendimiento de cada opción y cuál es más barata? No quiero saber cuál es más legible o se considera la mejor práctica, solo lo quiero desde una perspectiva de rendimiento.
Así que un código que se ve así:
class Thing { companion object { const val TAG = "Thing" } ... }En Java se ve así:
public final class Thing { public static final String TAG = "Thing"; public static final Thing.Companion Companion = new Thing.Companion((DefaultConstructorMarker)null); public static final class Companion { private Companion() { } public Companion(DefaultConstructorMarker $constructor_marker) { this(); } } ... } Crea este Companion de clase interno y lo instancia. ¿Qué tan costoso es esto?
Así que esto:
const val TAG = "Thing" class Thing { ... }Se convierte en esto:
public final class ThingKt { public static final String TAG = "Thing"; } public final class Thing { ... } Crea una nueva clase con un miembro static . ¿Qué tan diferente es esto de usar un objeto para almacenarlo?
Al igual que:
object ThingConstants { const val TAG = "Thing" } class Thing { ... }Que en Java se ve así:
public final class ThingConstants { public static final String TAG = "Thing"; public static final ThingConstants INSTANCE; ... // Private constructor } public final class Thing { ... } Muy similar a declarar como de nivel superior, excepto que la clase creada tiene un campo INSTANCE que se inicializa en un constructor privado. ¿Qué tan costoso es esto en comparación con el uso de una variable de nivel superior?
Entonces solo usas el buen viejo val :
class Thing { val TAG = "Thing" ... } Esto es un misterio para mi. No crea ninguna clase adicional, pero tampoco aprovecha los beneficios del modificador const . Esto significa que cada instancia de la clase tendrá su propia instancia de TAG , además de generar getters y setters para ella también, ¿verdad? Pero también leí que la JVM lo optimiza como una constante. Así que hay más en esta opción de lo que inicialmente pensé.
Las opciones 1-3 son las mismas para el rendimiento porque todas son const , por lo que están en línea donde sea que se usen en tiempo de compilación.
La opción 4 no crea instancias duplicadas de String para cada instancia de la clase. En cambio, cada instancia de la clase tendrá un campo de miembro que apunta a la misma instancia compartida. En cuanto al rendimiento, técnicamente tiene que llamar a un método getter cada vez que se recupera, pero esperaría que las VM modernas optimicen esa sobrecarga en el tiempo de ejecución.
Las opciones 1-3 crean definiciones de clase Java adicionales, por lo que hay un poco más de sobrecarga de memoria inicial para ellas. Pero si ya tiene otros miembros en esos objetos o niveles superiores de archivo, ya tiene esas clases de todos modos. La opción 4 tiene un campo adicional en la clase, por lo que podría pesar más si hay muchas instancias de la clase.