Sobes.tech
Middle

Wie arbeitet man mit generischen Typen in Kotlin?

sobes.tech KI

Antwort von AI

Generische Typen in Kotlin ermöglichen die Erstellung von Klassen, Schnittstellen und Funktionen, die mit Daten verschiedener Typen arbeiten, während die Typsicherheit zur Kompilierungszeit erhalten bleibt.

Grundkonzepte und Arbeitsweisen:

  • Deklaration von generischen Klassen und Schnittstellen:
    class Box<T>(val item: T) // Generische Klasse mit Typparameter T
    interface MyList<E> { // Generische Schnittstelle mit Typparameter E
        fun add(element: E)
        fun get(index: Int): E
    }
    
  • Deklaration von generischen Funktionen:
    fun <T> printAnything(value: T) { // Generische Funktion mit Typparameter T
        println(value)
    }
    
  • Erstellung von Instanzen generischer Typen:
    val intBox: Box<Int> = Box(123) // Angabe eines konkreten Typs (Int)
    val stringBox = Box("hello") // Der Compiler schätzt den Typ (String)
    
  • Varianten: Ermöglicht die Definition, wie Untertypen mit generischen Typen funktionieren.
    • Kovarianz (out): Ermöglicht die Verwendung des Typs und seiner Untertypen. Wird mit out gekennzeichnet. Beispiel: List<out Any> kann List<String> enthalten. Wird für Typen verwendet, die Werte produzieren (z.B. Lesen aus Sammlungen).
      interface Producer<out T> { // out T - kovarianter Parameter
           fun produce(): T
      }
      
    • Kontravarianz (in): Ermöglicht die Verwendung des Typs und seiner Supertypen. Wird mit in gekennzeichnet. Beispiel: Comparator<in String> kann mit Comparator<Any> arbeiten. Wird für Typen verwendet, die Werte konsumieren (z.B. Schreiben in Sammlungen).
      interface Consumer<in T> { // in T - kontravarianter Parameter
          fun consume(value: T)
      }
      
    • Invarianz: Der Typ im generischen Parameter muss genau derselbe sein. Dies ist das Standardverhalten.
  • Einschränkungen von Typen (where): Ermöglicht es, den Typparameter so zu beschränken, dass er bestimmte Schnittstellen implementiert oder von einer bestimmten Klasse erbt.
    fun <T : Comparable<T>> max(a: T, b: T): T { // T muss Comparable implementieren
        return if (a > b) a else b
    }
    
    fun <T> process(item: T) where T : Runnable, T : Comparable<T> {
        item.run()
        // ... Verwendung der Vergleichbarkeit
    }
    
  • Sternprojektion (*): Wird verwendet, wenn die konkreten Typargumente egal sind. Ähnlich wie <?> in Java.
    fun printList(list: List<*>) { // Kann eine Liste beliebigen Typs akzeptieren
         for (item in list) {
             println(item)
         }
    }
    

Generische Typen in Kotlin verwenden Typerasure (type erasure), wie in Java. Informationen über konkrete Typargumente gehen während der Laufzeit verloren. Für die Arbeit mit Typen während der Laufzeit werden reified-Typen verwendet.

  • Reified-Typen (reified): Sind nur für inline-Funktionen verfügbar. Ermöglichen es, die Typinformation des Parameters während der Laufzeit zu behalten.
    inline fun <reified T> checkType(value: Any) { // T - reified Typ
        if (value is T) {
            println("Wert ist vom Typ T")
        } else {
            println("Wert ist nicht vom Typ T")
        }
    }