简体   繁体   中英

Cast to Generic type java (why unchecked)

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 of List and this does not work without a cast.... Please explain, I only allow ArrayList in and no other subclass of List

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM