J'essaie de comprendre la différence entre utiliser/ne pas utiliser @JvmStatic et quand je devrais utiliser l'un ou l'autre.
Donc, avec Kotlin et Java, je peux le faire:
TestKotlin.kt
class TestKotlin {
companion object {
val someString = "hello world"
}
}
Ce qui s'appelle alors par Java, comme ceci:
TestJava.Java
public class TestJava {
String kotlinStaticString = TestKotlin.Companion.getSomeString();
}
mais alors, il y a cette option 2:
TestKotlin.kt
v2
class TestKotlin {
companion object {
@JvmStatic // <-- notice the @JvmStatic annotation
val someString = "hello world"
}
}
Et puis, appelez-le de Java, comme ceci:
TestJava.Java
v2
public class TestJava {
String kotlinStaticString = TestKotlin.getSomeString();
}
Donc mes questions sont:
Merci!
Le comportement de l'annotation @JvmStatic
Est expliqué en détail dans la documentation . Lors de la lecture de la documentation, vous devez supposer qu’elle vous donne toutes les informations importantes et que les différences de comportement qui ne sont pas mentionnées dans la documentation n’existent pas.
Dans ce cas, la documentation indique:
Si vous utilisez cette annotation, le compilateur générera une méthode statique dans la classe englobante de l'objet et une méthode d'instance dans l'objet même.
En d'autres termes, l'annotation a pour effet d'indiquer au compilateur de générer une méthode supplémentaire .
La documentation mentionne-t-elle qu'il existe une différence de comportement ou d'allocation de mémoire? Ce ne est pas. Par conséquent, il est prudent de supposer qu'il n'y en a pas.
Y a-t-il une préférence sur laquelle utiliser? Normalement, une API est déclarée à un endroit et utilisée à partir de plusieurs endroits. Si vous appelez une méthode depuis Java, vous devez alors la déclarer comme @JvmStatic
, Car l'ajout de l'annotation @JvmStatic
À un endroit vous permettra d'omettre plusieurs références .Companion
. à plusieurs endroits.
Est-ce que les deux créent un objet singleton pseudo statique, comme le fait Java statique? Cette question n'a pas de sens, car Java static ne crée pas d '"objet singleton pseudo statique". Si vous déclarez une méthode statique dans une classe Java, puis appelez cette méthode, aucun objet ne sera créé.
Vous placez la fonction dans "l'objet compagnon".
Donc, le code Java) ressemble à ceci:
class DemoClass {
public static int myMethod() { return 1; }
}
va devenir
class DemoClass {
companion object {
fun myMethod() : Int = 1
}
}
Vous pouvez ensuite l'utiliser depuis le code Kotlin en tant que
DemoClass.myMethod();
Mais à partir de Java, vous devez l’appeler comme suit:
DemoClass.Companion.myMethod();
(Ce qui fonctionne aussi depuis Kotlin.)
Si vous n'aimez pas avoir à spécifier le bit Companion
, vous pouvez ajouter une annotation @JvmStatic
Ou nommer votre classe d'accompagnement.
De la docs :
Objets Compagnon
Une déclaration d'objet à l'intérieur d'une classe peut être marquée avec le mot clé compagnon:
class MyClass { companion object Factory { fun create(): MyClass = MyClass() } }
Les membres de l'objet compagnon peuvent être appelés en utilisant simplement le nom de la classe comme qualificatif:
val instance = MyClass.create()
...
Toutefois, sur la machine virtuelle Java, vous pouvez générer des membres d’objets associés sous forme de méthodes et de champs statiques réels, si vous utilisez l’annotation
@JvmStatic
. Voir la section relative à l'interopérabilité Java) pour plus de détails.
L'ajout de l'annotation @JvmStatic
Ressemble à ceci
class DemoClass {
companion object {
@JvmStatic
fun myMethod() : Int = 1;
}
}
et ensuite a existera sous la forme d'une fonction statique réelle Java, accessible à partir de Java et de kotlin sous la forme DemoClass.myMethod()
. _.
Si le nom Companion
ne vous plaît pas, vous pouvez également donner un nom explicite à l'objet compagnon qui ressemble à ceci:
class DemoClass {
companion object Blah {
fun myMethod() : Int = 1;
}
}
ce qui vous permettra de l'appeler de Kotlin de la même manière, mais à partir de Java comme DemoClass.Blah.myMethod()
] _ (qui fonctionnera également dans Kotlin).
En Kotlin, l’objet companion
peut être utilisé pour imiter un comportement statique, les appels ressemblent à des appels statiques en Java, le “Companion“
ne fait pas partie de if. S'il est utilisé dans Java cependant, l'objet companion
doit être nommé, à moins que @JvmStatic
est appliqué. Sinon, ça aurait l'air moins idiomatique.
TestKotlin.getSomeString() //this should be preferred whenever possible
Énoncé dans le docs :
Objets Compagnon
Une déclaration d'objet à l'intérieur d'une classe peut être marquée avec le mot clé compagnon:
class MyClass { companion object Factory { fun create(): MyClass = MyClass() } }
Les membres de l'objet compagnon peuvent être appelés en utilisant simplement le nom de la classe comme qualificatif:
val instance = MyClass.create()
...
Toutefois, sur la machine virtuelle Java, vous pouvez générer des membres d’objets associés sous forme de méthodes et de champs statiques réels, si vous utilisez la commande
@JvmStatic
annotation. Voir la section relative à l'interopérabilité Java) pour plus de détails.
Notez qu'il générera une méthode supplémentaire comme indiqué ici :
Si vous utilisez cette annotation, le compilateur générera une méthode statique dans la classe englobante de l'objet et une méthode d'instance dans l'objet même.
Voyons un exemple :
La classe suivante
class Outer {
companion object {
fun callMe() = ""
}
}
ressemble à ceci au niveau du bytecode, représenté ici par Java:
@Metadata(...)
public final class Outer {
public static final Outer.Companion Companion = new Outer.Companion((DefaultConstructorMarker)null);
@Metadata(...)
public static final class Companion {
@NotNull
public final String callMe() {
return "";
}
private Companion() {
}
// $FF: synthetic method
public Companion(DefaultConstructorMarker $constructor_marker) {
this();
}
}
}
Si @JvmStatic
est appliqué à la méthode callMe
, cependant, le bytecode devient le suivant:
@Metadata(...)
public final class Outer {
public static final Outer.Companion Companion = new Outer.Companion((DefaultConstructorMarker)null);
@JvmStatic
@NotNull
public static final String callMe() {
return Companion.callMe();
}
@Metadata(...)
public static final class Companion {
@JvmStatic
@NotNull
public final String callMe() {
return "";
}
private Companion() {
}
// $FF: synthetic method
public Companion(DefaultConstructorMarker $constructor_marker) {
this();
}
}
}
Vous pouvez voir, correctement documenté, la fonction statique callMe
, dans le cadre de Outer
est générée:
@JvmStatic
@NotNull
public static final String callMe() {
return Companion.callMe();
}