Reputation: 27306
Why does the following code compile cleanly without any warnings, even with xlint:all
?
class A<V> {
public V v;
public <V> A() {
}
public static <V> A<V> create() {
return new A<V>();
}
}
public class FooMain {
public static void main(String args[]) {
A.create().v = 5;
A.create().v = "a string";
}
}
running:
javac -Xlint:all src/FooMain.java
results in a clean compile without any warnings (unchecked, etc.). What is the type parametrization of the instance of the generic class A
that gets's created on the first line and what on the second? And how does the compiler determine the type? By looking at the type of the r-values?
Upvotes: 9
Views: 152
Reputation: 55233
In both of the statements, the compiler does not have enough information to infer the type argument for V
. When this happens, it defaults to V
's upper bound, which is Object
.
The assignments are valid because both 5
and "a string"
are assignable to Object
.
We can show that the type of A.create().v
is Object
by trying to assign it to a more specific type:
Integer i = A.create().v; // Type mismatch: cannot convert from Object to Integer
The error is the same, even if we assign a more specific type first (the result of an assignment expression is the type of the assigned variable):
Integer i = (A.create().v = 5); // same error
Note that a "type witness" can be used to explicitly specify generic type arguments, in the case that they aren't inferred:
Integer i = A.<Integer>create().v; // valid
A.<String>create().v = 5; // incompatible types
A.<Integer>create().v = "a string"; //
These are contrived examples just to demonstrate compiler behavior, but a type witness is occasionally useful, for example:
static void m(List<String> list) { }
public static void main(String args[]) {
m(Collections.emptyList()); // error
m(Collections.<String>emptyList()); // valid
}
Upvotes: 4
Reputation: 1717
Due to these two statement
A.create().v = 5;
A.create().v = "a string";
Compiler will easily resolve in the first case <V>
by <Integer>
and in the second case <V>
by <String>
Upvotes: 1