I am trying to learn Java Generics, and found the following code.
public static <T> void print(T a, T b){
System.out.println(a);
System.out.println(b);
}
public static void main(String[] args){
print(new ArrayList<String>(), 1);
}
Which works with no problem.
However when I change print method to the following, it gives me compiling errors.
public static <T> void print(List<T> a, T b){
System.out.println(a);
System.out.println(b);
}
Error:
GenericTest.java:9: error: method print in class GenericTest cannot be applied to given types;
print(new ArrayList<String>(), 1);
^
required: List<T>,T
found: ArrayList<String>,int
reason: no instance(s) of type variable(s) T exist so that argument type int conforms to formal parameter type T
where T is a type-variable:
T extends Object declared in method <T>print(List<T>,T)
1 error
Can anyone help me understand the errors?
The first thing you should understand is that, with the following method signature
public static <T> void print(T a, T b)
Both T must be the same type, that is to say both a and b will have the same infered type.
So why does it work for new ArrayList<String>() and 1? Because both parameters can actually be represented as Serializable, which is the nearest common super type of ArrayList and Integer:
ArrayList implements the Serializable interface.1 can be boxed into an Integer, which is also Serializable.So in this case, the compiler will infer T as Serializable.
In the second case, with the signature
public static <T> void print(List<T> a, T b)
There is no common super type T that would be valid for both List<String> and Integer. It is true that both String and Integer are Serializable, but since generics aren't polymorphic, it doesn't work.
Edit: It doesn't get resolved to Object as I had mentioned but to Serializable. See Tunaki's correct answer for the reason.
In your first case, T is resolved to the most specific type which can refer to both your arguments.
And in your example, it will get resolved to ObjectSerializable, since ArrayList and Integer are both ObjectSerializable sub-types.
But in your second example, you have a List<T> as the parameter...
Now, when you call it with ArrayList<String>, the type T is resolved to a String. It cannot be resolved to any other type because an ArrayList<Object>ArrayList<Serializable> is NOT a supertype of ArrayList<String>
You call the method in following ways :
print(new ArrayList<String>(), "SimpleString");
or
print(new ArrayList<Integer>(),5)
because <T> is a type and it cannot be both String and integer at same time.
Your call could work if you do something like this :
public static <T, K> void print(List<T> a, K b){
System.out.println(a);
System.out.println(b);
}
public static void main(String[] args){
print(new ArrayList<String>(),1);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With