In this case, type inference works as expected, and the T type parameter handles both Integer and String:
public class A {
public static <T> void func(T obj1, T obj2) {}
public static void main(String[] args) {
A.func(1, "One");
}
}
However, the same does not seem to apply in the following example, as a compilation error occurs:
class Test<T> {
private T object;
public Test(T object) {
this.object = object;
}
}
public class A {
public static <T> void func(Test<T> one, Test<T> two) {}
public static void main(String[] args) {
Test<Integer> one = new Test<>(1);
Test<String> two = new Test<>("Two");
A.func(one, two); //compilation error
//A.<Object>func(one, two);
}
}
Even though (for example) Test<Object> could handle both Test<Integer> and Test<String>, the T type parameter isn't inferred. Why does this happen?
Nope. Wrong.
Generics is invariant. That means only the exact type will do. A subtype will not do. In contrast, 'normal' java is covariant - a subtype will do whenever one of its parent types is required.
Try it. Program along - compile this stuff and run it:
The reason it's a compiler error is because that is nonsense. If it was allowed (and fortunately it is not!), then.. let's continue:
But.. we just messed up.
numbersandintsaren't clones of each other. They are references to the same list. It's like an address book entry: You and I have our own address books but we wrote the same address. There's 2 address books, 2 pages, both with the same address, so only one house. If you walk over to the address in your book and toss a brick through the window, and then I walk over to my address, i.. notice the broken window. Same here: Thatnumbers.add(dn)also changes whatintssees because they reference the same list. So, it's also added to the thingintspoints at which.. is a problem! We just added aDoubleto aList<Integer>.This is why generics are invariant.
In your first example it 'works' because java can infer
T is Objectand then all works well. The second example does not work because nothing can be inferred that works - invariance meansT is objectwill not actually work. Change it to this:Then it would work fine. Each question mark is its own thing, so, one can be different from the other one, and both
IntegerandStringare subtypes of Object, so T now can beObject.? extends Tis basically 'I want covariance, not invariance'.Which is fine. And the compiler will stop you from making boneheaded mistakes. Code along:
To stop you from ruining type safety, you can't add anything to a
List<? extends Whatever>(and remember that<?>is short for<? extends Object>, so also applies there). No.add()call works. Except literally.add(null)(wherenullis not 'some value that happens to resolve to null', no this is a compile time thing: Only literally the letters n, u, l, l - and that's only because thenullliteral is every type all at once).