Menu
Coddy logo textTech

Klasy generyczne

Część sekcji Programowanie obiektowe ścieżki Kotlin w Coddy. Lekcja 38 z 57.

Klasa również może mieć parametry typu. Box<T> przechowuje wartość dowolnego typu, a każda instancja ustala typ: Box<Int> akceptuje tylko wartości typu Int:

class Box<T>(var value: T) {
    fun describe() = "box with $value"
}

Wewnątrz main:

val numberBox = Box(42)
val textBox = Box("hello")
numberBox.value += 1
println(numberBox.describe())
println(textBox.describe())
// numberBox.value = "x"   // błąd: String nie jest typem Int

Wynik:

box with 43
box with hello

Kontenery to typowe klasy generyczne. Jedna implementacja Stack<T> działa dla każdego typu elementu, a kompilator sprawdza, co trafia do środka i co z niego wychodzi:

class Stack<T> {
    private val items = mutableListOf<T>()
    val size: Int
        get() = items.size

    fun push(item: T) { items.add(item) }
    fun pop(): T? = items.removeLastOrNull()
    fun peek(): T? = items.lastOrNull()
}

Wewnątrz main:

val stack = Stack<String>()
stack.push("a")
stack.push("b")
println(stack.pop())
println(stack.peek())
println(stack.size)

Wynik:

b
a
1

Argument typu jest wnioskowany z argumentów konstruktora, jeśli jakieś są, jak w przypadku Box(42). W przeciwnym razie podaj go: Stack<String>(). Instancje z różnymi argumentami typu są różnymi typami, więc Stack<String> nigdy nie zostanie pomylony z Stack<Int>. Funkcje klasy generycznej mogą również definiować własne parametry typu:

class Box<T>(val value: T) {
    fun <R> map(f: (T) -> R): Box<R> = Box(f(value))
}

Wewnątrz main:

val length = Box("kotlin").map { it.length }
println(length.value + 1)

Wynik:

7

Interfejsy generyczne podlegają tym samym regułom. Klasa może implementować jeden generycznie lub dla jednego konkretnego argumentu typu:

interface Repository<T> {
    fun add(item: T)
    fun all(): List<T>
}
class MemoryRepository<T> : Repository<T> {
    private val items = mutableListOf<T>()
    override fun add(item: T) { items.add(item) }
    override fun all() = items.toList()
}
class TagRepository : Repository<String> {
    private val tags = sortedSetOf<String>()
    override fun add(item: String) { tags.add(item.lowercase()) }
    override fun all() = tags.toList()
}

Wewnątrz main:

val ids = MemoryRepository<Int>()
ids.add(3); ids.add(1)
val tags = TagRepository()
tags.add("Kotlin"); tags.add("JVM")
println("${ids.all()} ${tags.all()}")

Wynik:

[3, 1] [jvm, kotlin]
challenge icon

Wyzwanie

Łatwy

Napisz klasę generyczną History<T>(limit), która zapamiętuje ostatnie elementy limit. add(item) dodaje element na końcu i usuwa najstarszy, gdy jest ich więcej niż limit. latest to najnowszy element albo null, a all() zwraca elementy od najstarszego do najnowszego w postaci listy tylko do odczytu. Następnie napisz rozszerzenie History<Int>.average(), które istnieje tylko dla historii liczb i zwraca średnią całkowitą przechowywanych liczb (0, gdy historia jest pusta).

Dostarczony kod odczytuje limit, wiersz słów i wiersz liczb. Wypełnia obiekty History<String> i History<Int>, a następnie wypisuje przechowywane słowa, najnowsze słowo, przechowywane liczby, ich średnią oraz empty latest: null.

Umieść swój kod w pliku History.kt. Plik Main.kt zawiera dostarczony kod wejścia/wyjścia i nie można go edytować.

Spróbuj swoich sił

fun main() {
    // Dostarczony kod wejścia/wyjścia: pozostaw go bez zmian
    val input = generateSequence(::readLine).toList()
    val limit = input[0].toInt()
    val words = History<String>(limit)
    for (w in input[1].split(" ")) words.add(w)
    val numbers = History<Int>(limit)
    for (n in input[2].split(" ")) numbers.add(n.toInt())
    println("words: ${words.all()}")
    println("latest word: ${words.latest}")
    println("numbers: ${numbers.all()}")
    println("average: ${numbers.average()}")
    println("empty latest: ${History<Char>(3).latest}")
}
quiz iconSprawdź się

Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.

Wszystkie lekcje w sekcji Programowanie obiektowe

Poćwicz samodzielnie: Edytor online Kotlin