Projekcja gwiazdkowa i kiedy używać *
Stosuj projekcję gwiazdkową dla nieznanych typów generycznych i poznaj jej ograniczenia.
Projekcja gwiazdkowa i kiedy używać * to bezpłatna lekcja Kotlin Academy na CoddyKit. To lekcja 3 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Kotlin Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Kotlin Academy zawiera 4 lekcji w sumie.
Czym jest projekcja gwiazdkowa?
Projekcja gwiazdkowa (*) to sposób Kotlina na określenie „typu generycznego z nieznanym argumentem typu”. Jest bezpiecznym odpowiednikiem surowego typu lub nieograniczonego wildcarda <?> w Javie.
fun printList(list: List<*>) {
for (item in list) println(item)
}
fun main() {
printList(listOf(1, 2, 3))
printList(listOf("a", "b"))
printList(listOf(true, 42, "mixed"))
}Odczyt z typów z projekcją gwiazdkową
Z obiektu List<*> można odczytywać elementy jako Any?. Nie można dodawać elementów, ponieważ rzeczywisty typ jest nieznany.
fun process(list: List<*>) {
val first: Any? = list.firstOrNull()
println("First: $first, Size: ${list.size}")
// list.add("x") // compile error: can't write to List<*>
}
fun main() {
process(listOf(10, 20, 30))
}Gwiazda a out Any
List<*> i List<out Any?> są równoważne. Projekcja gwiazdkowa jest skróconym zapisem projekcji kowariantnej z górnym ograniczeniem.
fun sumStars(list: List<*>): Int = list.size
fun sumOut(list: List<out Any?>): Int = list.size
fun main() {
val l = listOf(1, "two", true)
println(sumStars(l)) // 3
println(sumOut(l)) // 3
}Gwiazda w parametrach funkcji
Użyj * w sygnaturach funkcji, gdy trzeba akceptować dowolny wariant generyczny, ale wywoływać tylko metody, które nie wymagają znajomości T.
fun containerInfo(map: Map<*, *>): String {
return "keys=${map.keys.size}, values=${map.values.size}"
}
fun main() {
val m = mapOf(1 to "one", 2 to "two")
println(containerInfo(m))
}Gwiazda z MutableList
W przypadku MutableList<*> można odczytywać elementy jako Any?, ale nie można niczego zapisywać — kompilator na to nie pozwala.
fun clearFirstElement(list: MutableList<*>) {
if (list.isNotEmpty()) {
list.removeAt(0) // OK: remove by index doesn't need T
// list.add("x") // Error: can't write unknown type
}
}
fun main() {
val m = mutableListOf(1, 2, 3)
clearFirstElement(m)
println(m) // [2, 3]
}Klasa z projekcją gwiazdkową
Podczas sprawdzania typu klasy generycznej w czasie działania użyj projekcji gwiazdkowej, ponieważ argumenty typów są wymazywane.
fun isListOfSomething(obj: Any): Boolean {
return obj is List<*> // OK with star
// obj is List<String> // Warning: cannot check erased type
}
fun main() {
println(isListOfSomething(listOf(1, 2))) // true
println(isListOfSomething("not a list")) // false
}Wiele parametrów z projekcją gwiazdkową
Funkcja może mieć wiele parametrów z projekcją gwiazdkową podczas pracy z parami lub mapami o nieznanych typach.
fun describeMap(map: Map<*, *>) {
map.forEach { (k, v) ->
println("${k?.javaClass?.simpleName} -> ${v?.javaClass?.simpleName}")
}
}
fun main() {
describeMap(mapOf("key" to 42, 1 to true))
}Kiedy NIE używać gwiazdy
Unikaj projekcji gwiazdkowej, gdy trzeba zapisywać do kolekcji lub gdy zamiast niej można użyć ograniczonego parametru typu — ograniczony parametr dostarcza więcej informacji.
// Bad: loses type information
fun addToStar(list: MutableList<*>, item: Any?) {
// list.add(item) // compile error
}
// Better: use bounded type parameter
fun <T : Any> addTyped(list: MutableList<T>, item: T) {
list.add(item)
}
fun main() {
val l = mutableListOf("a")
addTyped(l, "b")
println(l)
}Gwiazda przy sprawdzaniu typów i rzutowaniu
Użyj projekcji gwiazdkowej do wykonywania sprawdzeń instanceof dla klas generycznych, a następnie rzutuj na konkretny typ, aby wykonać właściwe operacje.
fun handleResponse(response: Any) {
if (response is List<*>) {
val list = response as List<*>
println("List with ${list.size} elements")
val first = list.firstOrNull()
if (first is String) println("First string: $first")
}
}
fun main() {
handleResponse(listOf("hello", "world"))
handleResponse(42)
}Praktyka: generyczny dyspozytor zdarzeń
Dyspozytor, który akceptuje dowolny obiekt Handler<*>, ale bezpiecznie obsługuje zdarzenia o określonych typach.
interface Handler<in T> { fun handle(event: T) }
class LogHandler : Handler<Any> {
override fun handle(event: Any) = println("Event: $event")
}
fun dispatch(handler: Handler<*>, event: Any) {
@Suppress("UNCHECKED_CAST")
(handler as Handler<Any>).handle(event)
}
fun main() {
dispatch(LogHandler(), "click")
dispatch(LogHandler(), 42)
}Gwiazda w kontekstach reified
Projekcja gwiazdkowa jest szczególnie często używana w kodzie refleksji i serializacji, gdzie typ w czasie działania jest sprawdzany za pomocą KClass<*>.
fun printClassName(klass: kotlin.reflect.KClass<*>) {
println(klass.simpleName)
}
fun main() {
printClassName(String::class) // String
printClassName(List::class) // List
printClassName(Int::class) // Int
}Szybkie sprawdzenie
Jaki typ otrzymuje się podczas odczytu z obiektu List<*>?
Podsumowanie
Projekcja gwiazdkowa (*) akceptuje dowolny wariant generyczny w dostępie tylko do odczytu. Używaj jej do sprawdzania typów, funkcji generycznych i refleksji. Unikaj jej, gdy trzeba zapisywać do kolekcji lub gdy ograniczony parametr typu zapewnia lepsze bezpieczeństwo typów.
Często zadawane pytania
Czy lekcja „Projekcja gwiazdkowa i kiedy używać *” jest bezpłatna?
Tak — pełny tekst „Projekcja gwiazdkowa i kiedy używać *” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Kotlin Academy, przejdź na CoddyKit PRO. Kurs Kotlin Academy zawiera 4 lekcji w sumie.
Co nauczysz się w „Projekcja gwiazdkowa i kiedy używać *”?
Stosuj projekcję gwiazdkową dla nieznanych typów generycznych i poznaj jej ograniczenia. Ćwiczysz Kotlin Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć Kotlin Academy?
Nie wymagamy żadnego doświadczenia. Kotlin Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 3 z 4.
Ile czasu zajmuje lekcja „Projekcja gwiazdkowa i kiedy używać *”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji Kotlin Academy?
Tak. Każda lekcja Kotlin Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- Funkcje generyczne i ograniczenia typów za pomocą where
- Wariancja deklarowana w miejscu deklaracji: in i out
- Projekcja gwiazdkowa i kiedy używać *
- Wymazywanie typów i parametry typów reified