I wonder why the following cast is unchecked:
== Update 1 ==
I know that we have type erasure at runtime. Mind the input parameter is a ArrayList
and not some random list. ArrayList
implements List
and RandomAccess
. I know this cast will not work with LinkedList
or MySpecialArrayList
. but the parameter of this method forbids that. I know (until people remove List
or RandomAccess
from ArrayList
the cast will not fail at runtime, but why is the cast unchecked?
== End update 1 ==
private static <L extends List<GenericTokenType<?>> & RandomAccess> L castArrayList(ArrayList<GenericTokenType<?>> instance) {
return (L) instance;
}
I simplified this to [still warning]
private static <L extends List> L castArrayList(ArrayList instance) {
return (L) instance;
}
and [no warning]
private static List castArrayList(ArrayList instance) {
return (List) instance;
}
Why does this not work. L
is a List
(not the runtime type, but the compiler should get that.
To rephrase the question: Why doesn't it work with a generic parameter return type? Thanks
In your first and second example, you're casting an ArrayList
to a type called L
. According to the generic constraints, L
must also implement the List
interface. Therefore, L
might be ArrayList
, LinkedList
, Stack
or Vector
, or some other class that you create that implements List
.
So far so good, right?
Now let's suppose L
is an ArrayList
the expression is equivalent to:
(ArrayList) instance
Obviously that will work.
But what if L
is LinkedList
?
(LinkedList) instance
That doesn't work because you can't force an array list to be a linked list! They are different data structures!
Why does the third work then?
In the third example, you're stating explicitly that "I want this ArrayList
to be List
". That works because the type you're casting instance
to is certain. ArrayList
implements List
, so it must be compatible with it!
The Method will not compile as
LinkedList
is a subtype ofList
and this does not work without a cast.... Please explain, I only allowArrayList
in and no other subclass ofList
Well, yes you only allow ArrayList
to be passed in to the method. But the return type of the method is L
. From the generic constraints, we know that L
can be any type that implements List
. However, you can't convert ArrayList
to any type that implements List
by casting.
L
will be erased to List
, since that is the lower bound. However, the uncheckedness comes from the fact that L
can technically be a subclass of List
, but due to type erasure, only a cast to (at most) List
can be performed. The actual cast will be performed later when the concrete type is available.
You can see this nicely in bytecode too:
public static void main(java.lang.String[]) throws java.lang.Exception;
Code:
0: new #2 // class java/util/ArrayList
3: dup
4: invokespecial #3 // Method java/util/ArrayList."<init>":()V
7: invokestatic #4 // Method castArrayList:(Ljava/util/ArrayList;)Ljava/util/List;
// Cast is done here, after returning
10: checkcast #2 // class java/util/ArrayList
13: astore_1
14: return
public static <L extends java.util.List> L castArrayList(java.util.ArrayList);
Code:
0: aload_0
// No 'checkcast' here
1: areturn
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.