Certains génériques Kotlin peuvent être exprimés en Java, tandis que d'autres ne le sont pas. Commençons par ce qui peut être exprimé en Java.
Déclarons une fonction générique dans Kotlin.
// Kotlin
fun <T> convertToString(arg: T) : String {
return arg.toString()
}
Déclarez un paramètre de type entre le mot-clé fun
dans une déclaration de fonction régulière et le nom de la fonction.
Les fonctions équivalentes peuvent être exprimées en Java.
// Java
<T> String convertToString(T arg) {
return arg.toString();
}
Vous pouvez contraindre les paramètres de type.
fun <T: Exception> convertToString(arg: T) : String {
return arg.localizedMessage
}
Le paramètre de type «T» a une contrainte qui en fait une exception ou sa sous-classe. Cela peut également être exprimé en Java.
// Java
<T extends Exception> String convertToString(T arg) {
return arg.getLocalizedMessage();
}
Définissons une classe générique dans Kotlin.
class Box<T>(t: T) {
var value = t
}
Déclarez un paramètre de type entre le nom de la classe et le constructeur principal. Les classes équivalentes peuvent être représentées en Java.
class Box<T> {
T value;
Box(T t) {
this.value = t;
}
}
Vous pouvez également contraindre les paramètres de type des classes.
class Box<T: Number> (t: T) {
var value = t
}
Le paramètre de type «T» est contraint à être Number ou sa sous-classe. Cela peut également être exprimé en Java.
static class Box<T extends Number> {
T value;
Box(T t) {
this.value = t;
}
}
where
La clause where
est utile lorsque vous souhaitez spécifier plusieurs contraintes de type dans une fonction ou une classe.
fun <T> doSomething(t: T) where T: Runnable, T: Cancellable {
}
Semblable au type générique de limite de Java, Kotlin a également une notation pour spécifier le déplacement lors de la déclaration de variables.
Java | Kotlin | |
---|---|---|
Contrainte de limite supérieure | <? extends XXX> | <out XXX> |
Contrainte de limite inférieure | <? super XXX> | <in XXX> |
Le chien est un sous-type d'animal.
Par conséquent, List \
open class Animal
class Dog: Animal()
var animals: List<out Animal> = emptyList()
val dogs: List<Dog> = emptyList()
animals = dogs
Le chien est un sous-type d'animal.
List \
open class Animal
class Cat: Animal()
val animals: MutableList<Animal> = mutableListOf()
var cats: MutableList<in Cat> = mutableListOf()
cats = animals
Dans Kotlin, la spécification de déplacement au moment de la déclaration est appelée ** type projection **.
En Java, la relation entre covariant et contravariant ne peut pas être spécifiée dans la classe elle-même. Par conséquent, il est nécessaire de spécifier le déplacement à chaque fois que la déclaration de variable etc.
Kotlin, d'autre part, a un mécanisme pour spécifier le déplacement lors de la déclaration d'une classe. Il n'y a aucun risque que le déplacement soit utilisé contre l'intention du concepteur de classe ou de l'implémenteur.
//↓ Spécifier la position de sortie pour le paramètre de type
class Supplier<out T> {
fun get(): T {
//
}
}
La classe Supplier
est covariante par rapport au paramètre de type T.
var animalSupplier: Supplier<Animal> = Supplier()
var dogSupplier: Supplier<Dog> = Supplier()
animalSupplier = dogSupplier
Il n'est pas nécessaire de spécifier le déplacement lors de la déclaration de la variable. De même, il est possible de créer un contravariant en spécifiant la position «in».
Vous pouvez transmettre null aux fonctions et arguments génériques suivants.
fun <T> doSomething(t: T){
}
doSomething(null) // OK
Le type Kotlin qui correspond à la classe racine Java ʻObject est ʻAny
.
Cependant, la limite supérieure pour les paramètres de type sans contrainte est ʻAny? Au lieu de ʻAny
.
Si vous souhaitez déclarer une fonction générique tolérante non nulle Spécifiez ʻAny` pour la contrainte de type.
fun <T: Any> doSomething(t: T){
}
doSomething(null) //Erreur de compilation
doSomething(1) // OK
doSomething("hoge") // OK
Il existe un mécanisme appelé projection en étoile qui spécifie un astérisque «*» pour le paramètre de type.
var animals: List<*> = //
La liste ci-dessus «List <*>» n'est pas égale à «List <Any?>». Il se comporte comme List <out Any?>
.
La projection en étoile est une syntaxe utilisée lorsque les paramètres de type ne vous intéressent pas.
Il est sûr d'obtenir un élément et de le traiter comme ʻAny? `, Mais il n'est pas sûr d'ajouter un élément à une liste.
Comme indiqué ci-dessous, il se comporte comme une position «out» en raison du risque de recevoir un type inattendu.
val animals: MutableList<*> = mutableListOf<Animal>()
val animal = animals.first() // OK
animals.add(1) //Erreur de compilation
animals.add(Dog()) //Erreur de compilation
Recommended Posts