Given this generic function:
<T> List<T> function() { return null; }
Why does this compile
开发者_如何学运维List<String> l = function();
While this does not?
List<String> l = (List<String>) function();
Because when you do a cast like this:
(List<String>) function()
the compiler can't infer the type parameter for the function()
call, and falls back on binding T
to Object
.
While in
List<String> l = function();
it can infer the correct type for T
.
Note that you may cast if you circumvent the job of the type inference by explicitly providing the type:
import java.util.List;
class Test {
public static <T> List<T> function() { return null; }
public static void main(String[] args) {
List<String> l = (List<String>) Test.<String>function();
// ^^^^^^^^^^^^^
}
}
I don't know the exact type inferencing rules for generic parameters. They are however specified in JLS Section 15.12.2.7.
It looks like type inference happens after the cast is attempted (by the compiler).
The type of the expression is determined by the left side of the expression, which is not yet "parsed" when the cast is attempted. And the cast itself fails because, with not-yet-inferred type, the result (of the method invocation) is of type List<Object>
Section 15.12.2.7 of the JLS indicates that type inference happens last.
The first one uses type inference, using the type of the variable the result is assigned to.
In the second one, the result of the call is not assigned to anything (before the cast is done), so the most generic type is returned (List<Object>
), and a List<Object>
can't be cast to a List<String>
.
This is because javac needs to infer T, but T does not appear in argument types.
static<T> T foo(){ .. }
foo(); // T=?
Only in 2 cases, javac can infer T from the context
String s = foo(); // #1: assignment
String bar(){
return foo(); // #2: return
In other cases, javac won't, and T is simply inferred as Object
List<String>
doesn't extend List<Object>
. So You can't cast it.
You can specify T in next way
List<String> l = this.<String>function();
That's because compiler can't infer the parameterized type of the method function()
, so it binds T
to Object
. You can't cast List<Object>
to List<String>
.
The question is not exact.
List<String> m = (List<String>)function();
produces warning "Type safety: Unchecked cast from Object to List" that is correct because all casts to generic types are unsafe.
精彩评论