I cant figure out why does this code work without error.
static <T> int compare(T t1, T t2) {
return 0;
}
public static void main(String[] args) {
compare(new Thread(), new StringBuilder());
}
Because when we have something like this:
static <T> void fromArrayToCollection(T[] a, Collection<T> c) {
return;
}
public static void main(String[] args) {
fromArrayToCollection(new Thread[] {}, new ArrayList<StringBuilder>()); // error
}
We have an error. Why doesn't compiler check match of both arguments in first example? Sorry for stupid question.
Generics are invariant
Generics are invariant, not covariant.
This means that, while you can do something like this:
Dog dog = new Dog();
Animal animal = dog; // Dog works for Animal, classes are covariant
You can not do this:
List<Dog> dogs = List.of(new Dog());
List<Animal> animals = dogs; // Error, generics are invariant
So List<Dog>
is not of type List<Animal>
. But Dog
is of type Animal
.
Of course this makes sense, since animals
would accept Cat
s, but dogs
not.
Explanation
In your first code, you did not specify the type to use, such as:
compare<Foo>(...)
so you let the compiler deduce the type. It searches a type which Thread
and StringBuilder
have in common, which is Object
.
So T
resolves to Object
there, which is fine:
static int compare(Object t1, Object t2) {
return 0;
}
In your second example it can not pick Object
, because Collection<Object>
behaves different to Collection<StringBuilder>
, since generics are invariant. So it is unable to find a type that matches, thus an error occurs.
Also see Why are arrays covariant but generics are invariant?.