Kotlin Generics

Filed Under: Kotlin

In this tutorial, we’ll be looking in Kotlin Generics and Variances.


Generics are a powerful feature that allows us to define a common class/method/property that can be operated using different types while keeping a check of the compile-time type safety.
They are commonly used in Collections.
A generic type is a class or interface that is parameterized over types. We use angle brackets (<>) to specify the type parameter. To understand Generics, we need to understand types.
Every class has a type which is generally the same as the class.
Though, in Kotlin a nullable type such as String? won’t be considered a class type.
Same goes for a List<String> etc.

An example of Kotlin Generic classes is given below:

fun main(args: Array<String>) {
    var a = A("")
    var b: A<Int> = A(1) //explicit

class A<T>(argument: T) {
    var result = argument

We’ve instantiated the class using explicit types as well as allowing the compiler to infer them.


Variance is all about substituting a type with subtypes or supertypes.
The following thing works in Java:

Number[] n = newNumber[2];
n[0] = newInteger(1);
n[1] = newDouble(47.24);

This means Arrays in Java are covariant.

Convariant means, substituting:
Subtypes are acceptable.
Supertypes are not.

So using the covariant principle the following Java code works as well:

Integer[] integerArray = {1,2,3};
Number[] numberArray = integerArray;

The Number class is the parent of Integer class hence the inheritance and subtyping principle works above.
But the above assignment is risky if we do something like this:

numberArray[1] = 4.56 //compiles successfully

This would lead to a runtime exception in Java since we cannot store a Double as an Int.

Kotlin Arrays stays away from this principle by making arrays invariant by default.

Invariant means, substituting:
Subtypes are not allowed.
Supertypes are not allowed.

So the above runtime error won’t occur with Kotlin Arrays.

val i = arrayOf(1, 2, 3)
val j: Array<Any> = i //this won't compile.

Hence, one of the major differences in variances between Kotlin and Java is:

Kotlin Arrays are invariant. Java Arrays are covariant.

Applying the above concepts DON’T COMPILE when used with Generics and Collections for both Java and Kotlin.

import java.util.ArrayList;
import java.util.List;

public class Hi {

    public static void main(String[] args) {
        List<String> stringList= new ArrayList<>();
        List<Object> myObjects = stringList; //compiler error


By default, the Generic types are invariant. In Java, we use wildcard characters to use the different type of variances.
There are two major types of variances besides invariant.

  • Covariant
  • Contravariant


A ? extends Object is a wildcard argument which makes the type as covariant.
Our previous java code now works fine.

public class Hi<T> {

    public static void main(String[] args) {

        Hi<Integer> j = new Hi();
        Hi<Object> n = j; //compiler error
        Hi<? extends Object> k = j; //this works fine



The third statement is an example of Covariance using wild card arguments.

The modifier out is used for applying covariance in Kotlin.

fun main(args: Array<String>) {

    val x: A<Any> = A<Int>() // Error: Type mismatch
    val y: A<out Any> = A<String>() // Works
    val z: A<out String> = A<Any>() // Error
class A<T>

In Kotlin, we can directly annotate the wildcard argument on the parameter type of the class. This is known as declaration-site variance.

fun main(args: Array<String>) {
    val x: A<Any> = A<Int>()

class A<out T>

The above Kotlin code looks more readable than the Java one.

fun main(args: Array<String>) {
    var correct: Container<Vehicle> = Container<Car>()
    var wrong: Container<Car> = Container<Vehicle>()

open class Vehicle
class Car : Vehicle()
class Container<out T>
To sum up Covariance in Kotlin:
Use out
Used to set substitute subtypes. Not the other way round


This is just the opposite of Covariance. It’s used to substitute a supertype value in the subtypes.
It cannot work the other way round.
It uses the in modifier

fun main(args: Array<String>) {
    var correct: Container<Car> = Container<Vehicle>()
    var wrong: Container<Vehicle> = Container<Car>()

open class Vehicle

class Car : Vehicle()

class Container<in T>

Kotlin in is equivalent to <? super T> of Java.
Kotlin out is equivalent to <? extends T> of Java.

This brings an end to this tutorial on Kotlin Generics and Variance.


  1. Chris says:

    This is one of the best Explanations I’ve seen about Kotlin Generics in a While 馃憤. It’s easier to understand. Thank You!!

    1. Anupam says:

      Glad you liked it!

Comments are closed.

Generic selectors
Exact matches only
Search in title
Search in content