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 Object
Serializable
, since ArrayList
and Integer
are both Object
Serializable
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