In Kotlin I have found that, in contrast to Java, the following can be done using covariance:
ArrayList<Dog> listOfDogs = listOf(dog1, dog2)
ArrayList<Animal> animalList = listOfDogs // No compiler error
In my situation I have an interface Message:
public interface Message {
RawMessage toRawMessage();
}
For example I have an Int32
Message:
public interface Int32 extends Message {
// abstract methods
}
Now I have a method with a parameter type
of type Class<Message>
:
fun doSomethingWithType(type: Class<Message>) {
// Implementation
}
The problem is that I am trying to pass a Java class extending from Message like:
doSomethingWithType(Int32::class.java)
But this gives me the following compiler error:
Expected type mismatch:
required: Class<Message>
found: Class<Int32>
Why is this not working and how should I solve it?
The following is valid Kotlin code (assuming Dog
is a subclass of Animal
):
val listOfDogs: List<Dog> = listOf(dog1, dog2)
val listOfAnimals: List<Animal> = listOfDogs
The reason behind this is that List
is an Kotlin interface defined as:
public interface List<out E> : Collection<E>
Unfortunately you can't do the same in pure Java, but you can do this:
List<Dog> listOfDogs = new ArrayList<>();
List<? extends Animal> listOfAnimals = listOfDogs;
Now, doSomethingWithType
expects a Class<Message>
while you're providing Class<Int32>
, and Class
is not covariant in T
. In order to make that code compile you can do the following:
fun doSomethingWithType(type: Class<out Message>) { ... }
doSomethingWithType(Int32::class.java)
This will work as long as you'll only pull out T
from Class<T>
, i.e. Class
will only produce type T
.