Einige Kotlin-Generika können in Java ausgedrückt werden, andere nicht. Beginnen wir mit dem, was in Java ausgedrückt werden kann.
Lassen Sie uns eine generische Funktion in Kotlin deklarieren.
// Kotlin
fun <T> convertToString(arg: T) : String {
return arg.toString()
}
Deklarieren Sie einen Typparameter zwischen dem Schlüsselwort fun
in einer regulären Funktionsdeklaration und dem Funktionsnamen.
Äquivalente Funktionen können in Java ausgedrückt werden.
// Java
<T> String convertToString(T arg) {
return arg.toString();
}
Sie können Typparameter einschränken.
fun <T: Exception> convertToString(arg: T) : String {
return arg.localizedMessage
}
Der Typparameter T
hat eine Einschränkung, die ihn zu einer Ausnahme oder seiner Unterklasse macht.
Dies kann auch in Java ausgedrückt werden.
// Java
<T extends Exception> String convertToString(T arg) {
return arg.getLocalizedMessage();
}
Definieren wir eine generische Klasse in Kotlin.
class Box<T>(t: T) {
var value = t
}
Deklarieren Sie einen Typparameter zwischen dem Klassennamen und dem primären Konstruktor. Äquivalente Klassen können in Java dargestellt werden.
class Box<T> {
T value;
Box(T t) {
this.value = t;
}
}
Sie können Typparameter für Klassen auch einschränken.
class Box<T: Number> (t: T) {
var value = t
}
Der Typparameter T
ist auf Number oder seine Unterklasse beschränkt.
Dies kann auch in Java ausgedrückt werden.
static class Box<T extends Number> {
T value;
Box(T t) {
this.value = t;
}
}
where
KlauselDie "where" -Klausel ist nützlich, wenn Sie mehrere Typeinschränkungen in einer Funktion oder Klasse angeben möchten.
fun <T> doSomething(t: T) where T: Runnable, T: Cancellable {
}
Ähnlich wie beim Java-Boundary-Wildcard-Typ verfügt Kotlin auch über eine Notation, die die Verschiebung beim Deklarieren von Variablen angibt.
Java | Kotlin | |
---|---|---|
Obergrenze Einschränkung | <? extends XXX> | <out XXX> |
Untergrenze Einschränkung | <? super XXX> | <in XXX> |
Hund ist ein Subtyp von Tier.
Daher erstellt List \
open class Animal
class Dog: Animal()
var animals: List<out Animal> = emptyList()
val dogs: List<Dog> = emptyList()
animals = dogs
Hund ist ein Subtyp von Tier.
List \
open class Animal
class Cat: Animal()
val animals: MutableList<Animal> = mutableListOf()
var cats: MutableList<in Cat> = mutableListOf()
cats = animals
In Kotlin wird die Verschiebungsspezifikation zum Zeitpunkt der Deklaration als ** Typprojektion ** bezeichnet.
In Java kann die Beziehung zwischen Kovariante und Kontravariante nicht in der Klasse selbst angegeben werden. Daher muss die Verschiebung jedes Mal angegeben werden, wenn die Variablendeklaration usw. erfolgt.
Kotlin hingegen verfügt über einen Mechanismus zum Festlegen der Verschiebung bei der Deklaration einer Klasse. Es besteht keine Gefahr, dass eine Verschiebung gegen die Absicht des Klassendesigners oder Implementierers verwendet wird.
//↓ Geben Sie die Position für den Typparameter an
class Supplier<out T> {
fun get(): T {
//
}
}
Die Supplier
-Klasse ist in Bezug auf den Typparameter T kovariant.
var animalSupplier: Supplier<Animal> = Supplier()
var dogSupplier: Supplier<Dog> = Supplier()
animalSupplier = dogSupplier
Es ist nicht erforderlich, die Verschiebung anzugeben, wenn die Variable deklariert wird. In ähnlicher Weise ist es möglich, eine Kontravariante durch Angabe der Position "in" zu erstellen.
Sie können den folgenden generischen Funktionen und Argumenten null übergeben.
fun <T> doSomething(t: T){
}
doSomething(null) // OK
Der Kotlin-Typ, der der Java-Stammklasse "Object" entspricht, ist "Any". Die Obergrenze für nicht eingeschränkte Typparameter lautet jedoch "Beliebig" anstelle von "Beliebig".
Wenn Sie eine nicht null tolerante generische Funktion deklarieren möchten Geben Sie "Beliebig" für die Typeinschränkung an.
fun <T: Any> doSomething(t: T){
}
doSomething(null) //Kompilierungsfehler
doSomething(1) // OK
doSomething("hoge") // OK
Es gibt einen Mechanismus namens Sternprojektion, der ein Sternchen "*" für den Typparameter angibt.
var animals: List<*> = //
Die obige "Liste <*>" ist nicht gleich "Liste <Beliebig?>". Es verhält sich wie "List <out Any?>". Die Sternprojektion ist eine Syntax, die verwendet wird, wenn Sie nicht an Typparametern interessiert sind. Es ist sicher, ein Element abzurufen und als "Beliebig?" Zu behandeln. Es ist jedoch nicht sicher, ein Element zu einer Liste hinzuzufügen.
Wie unten gezeigt, verhält es sich aufgrund des Risikos, einen unerwarteten Typ zu erhalten, wie eine "out" -Position.
val animals: MutableList<*> = mutableListOf<Animal>()
val animal = animals.first() // OK
animals.add(1) //Kompilierungsfehler
animals.add(Dog()) //Kompilierungsfehler
Recommended Posts