Generics
A List can hold numbers, words or really anything. That’s why we call the List generic.
Generics are basically used to define which types a class can hold and which type an object currently holds.
Declaration-site variance
Section titled “Declaration-site variance”Declaration-site variance can be thought of as declaration of use-site variance once and for all the use-sites.
class Consumer<in T> { fun consume(t: T) { ... } }
fun charSequencesConsumer() : Consumer<CharSequence>() = ...
val stringConsumer : Consumer<String> = charSequenceConsumer() // OK since in-projection val anyConsumer : Consumer<Any> = charSequenceConsumer() // Error, Any cannot be passed
val outConsumer : Consumer<out CharSequence> = ... // Error, T is `in`-parameterWidespread examples of declaration-site variance are List<out T>, which is immutable so that T only appears as the return value type, and Comparator<in T>, which only receives T as argument.
Use-site variance
Section titled “Use-site variance”Use-site variance is similar to Java wildcards:
Out-projection:
val takeList : MutableList<out SomeType> = ... // Java: List<? extends SomeType>
val takenValue : SomeType = takeList[0] // OK, since upper bound is SomeType
takeList.add(takenValue) // Error, lower bound for generic is not specifiedIn-projection:
val putList : MutableList<in SomeType> = ... // Java: List<? super SomeType>
val valueToPut : SomeType = ... putList.add(valueToPut) // OK, since lower bound is SomeType
putList[0] // This expression has type Any, since no upper bound is specifiedStar-projection
val starList : MutableList<*> = ... // Java: List<?>
starList[0] // This expression has type Any, since no upper bound is specified starList.add(someValue) // Error, lower bound for generic is not specifiedSee also:
Syntax
Section titled “Syntax”- class ClassName<TypeName>
- class ClassName<*>
- ClassName<in UpperBound>
- ClassName<out LowerBound>
- class Name<TypeName:UpperBound>
Parameters
Section titled “Parameters”|Parameter|Details |---|---|---|---|---|---|---|---|---|--- |TypeName|Type Name of generic parameter |UpperBound|Covariant Type |LowerBound|Contravariant Type |ClassName|Name of the class
Remarks
Section titled “Remarks”Implied Upper Bound is Nullable
Section titled “Implied Upper Bound is Nullable”In Kotlin Generics, the upper bound of type parameter T would be Any?. Therefore for this class:
class Consumer<T>The type parameter T is really T: Any?. To make a non-nullable upper bound, explicitly specific T: Any. For example:
class Consumer<T: Any>