Expressions d'objet et déclarations d'objet Kotlin
Kotlin utilise des expressions d'objet et des déclarations d'objet pour créer un objet d'une classe avec de légères modifications, sans avoir besoin de déclarer une nouvelle sous-classe.
Expressions d'objet
Utilisez une expression d'objet pour créer un objet de classe interne anonyme à utiliser comme paramètre de méthode :
window.addMouseListener(object : MouseAdapter() {
override fun mouseClicked(e: MouseEvent) {
// ...
}
override fun mouseEntered(e: MouseEvent) {
// ...
}
})
L'objet peut hériter d'une classe de base, ou implémenter d'autres interfaces :
open class A(x: Int) {
public open val y: Int = x
}
interface B {……}
val ab: A = object : A(1), B {
override val y = 15
}
Si le supertype a un constructeur, des paramètres doivent lui être passés. Plusieurs supertypes et interfaces peuvent être séparés par des virgules.
À l'aide d'une expression d'objet, vous pouvez obtenir directement un objet sans passer par une définition de classe :
fun main(args: Array<String>) {
val site = object {
var name: String = "Example"
var url: String = "www.example.com"
}
println(site.name)
println(site.url)
}
Notez que les objets anonymes ne peuvent être utilisés comme types déclarés que dans des portées locales et privées. Si vous utilisez un objet anonyme comme type de retour d'une fonction publique ou comme type d'une propriété publique, le type réel de cette fonction ou propriété sera le supertype déclaré par l'objet anonyme, ou Any si aucun supertype n'est déclaré. Les membres ajoutés dans l'objet anonyme ne seront pas accessibles.
class C {
// 私有函数,所以其返回类型是匿名对象类型
private fun foo() = object {
val x: String = "x"
}
// 公有函数,所以其返回类型是 Any
fun publicFoo() = object {
val x: String = "x"
}
fun bar() {
val x1 = foo().x // 没问题
val x2 = publicFoo().x // 错误:未能解析的引用“x”
}
}
Dans une expression d'objet, il est possible d'accéder facilement aux autres variables de la portée :
fun countClicks(window: JComponent) {
var clickCount = 0
var enterCount = 0
window.addMouseListener(object : MouseAdapter() {
override fun mouseClicked(e: MouseEvent) {
clickCount++
}
override fun mouseEntered(e: MouseEvent) {
enterCount++
}
})
// ……
}
Déclarations d'objets
Kotlin utilise le mot-clé `object` pour déclarer un objet.
En Kotlin, on peut facilement obtenir un singleton grâce aux déclarations d'objet.
object DataProviderManager {
fun registerDataProvider(provider: DataProvider) {
// ……
}
val allDataProviders: Collection<DataProvider>
get() = // ……
}
Pour référencer cet objet, il suffit d'utiliser son nom :
DataProviderManager.registerDataProvider(……)
Bien sûr, vous pouvez également définir une variable pour obtenir cet objet. Cependant, lorsque vous définissez deux variables différentes pour obtenir cet objet, vous constaterez que vous ne pouvez pas obtenir deux variables différentes. En d'autres termes, grâce à cette approche, nous obtenons un singleton.
var data1 = DataProviderManager
var data2 = DataProviderManager
data1.name = "test"
print("data1 name = ${data2.name}")
Exemple
Dans l'exemple suivant, les deux objets affichent la même adresse URL :
object Site {
var url:String = ""
val name: String = "Example"
}
fun main(args: Array<String>) {
var s1 = Site
var s2 = Site
s1.url = "www.example.com"
println(s1.url)
println(s2.url)
}
Le résultat de sortie est:
www.example.com www.example.com
Les objets peuvent avoir des supertypes :
object DefaultListener : MouseAdapter() {
override fun mouseClicked(e: MouseEvent) {
// ……
}
override fun mouseEntered(e: MouseEvent) {
// ……
}
}
Contrairement aux expressions d'objet, lorsqu'un objet est déclaré à l'intérieur d'une autre classe, cet objet n'est pas accessible via une instance de la classe externe, mais uniquement via le nom de la classe. De même, l'objet ne peut pas accéder directement aux méthodes et variables de la classe externe.
class Site {
var name = "Example"
object DeskTop{
var url = "www.example.com"
fun showName(){
print{"desk legs $name"} // 错误,不能访问到外部类的方法和变量
}
}
}
fun main(args: Array<String>) {
var site = Site()
site.DeskTop.url // 错误,不能通过外部类的实例访问到该对象
Site.DeskTop.url // 正确
}
Objets compagnons
Une déclaration d'objet à l'intérieur d'une classe peut être marquée avec le mot-clé `companion`, afin qu'elle soit associée à la classe externe, et nous pouvons accéder directement aux éléments internes de l'objet via la classe externe.
class MyClass {
companion object Factory {
fun create(): MyClass = MyClass()
}
}
val instance = MyClass.create() // 访问到对象的内部元素
Nous pouvons omettre le nom de l'objet, puis utiliser `Companion` pour remplacer le nom qui doit être déclaré :
class MyClass {
companion object {
}
}
val x = MyClass.Companion
Remarque :Une classe ne peut déclarer qu'un seul objet associé interne, c'est-à-dire que le mot-clé `companion` ne peut être utilisé qu'une seule fois.
Les membres d'un objet compagnon ressemblent à des membres statiques dans d'autres langages, mais à l'exécution, ce sont toujours des membres d'instance d'un véritable objet. Par exemple, il peut également implémenter des interfaces :
interface Factory<T> {
fun create(): T
}
class MyClass {
companion object : Factory<MyClass> {
override fun create(): MyClass = MyClass()
}
}
Différences sémantiques entre les expressions d'objet et les déclarations d'objet
Il existe une différence sémantique importante entre les expressions d'objet et les déclarations d'objet :
-
Les expressions d'objet sont exécutées immédiatement là où elles sont utilisées.
Les déclarations d'objet sont initialisées paresseusement lors du premier accès.
L'initialisation d'un objet compagnon se produit lorsque la classe correspondante est chargée (résolue), ce qui correspond à la sémantique des initialiseurs statiques de Java.