0

I'm modifying open JDK to add features and I've run into this twice with no good solution.

There's a class named JCStatement which extends JCTree.

Issue: I want to cast a List<JCStatement> into a List<JCTree>.

It's clear that a class can reference one of its extensions, but when I have it on a List, it just doesn't work.

I used: (List<JCTree>)((List<?>)params) to cast, which works, but doesn't build on ant. IDE gives me the following warning:

Type safety: Unchecked cast from List<capture#1-of ?> to List<JCTree>

So this must be worked around somehow.

I appreciate any help.

Erick Robertson
  • 32,125
  • 13
  • 69
  • 98
Adriano
  • 389
  • 3
  • 11
  • you cannot use typecasting, there are methods that can help you, for example `Collections.copy(List dest, List src)`. Find these methods and choose the best for you. Sorry for bad answer, cannot find them at this moment – alaster May 29 '12 at 16:28
  • I edited this to remove the extra example, which was un-necessary, and to cleanup the title question. – Erick Robertson May 29 '12 at 16:39
  • alaster, your solution almost worked, but I'd need a way to instantiate a `List` with enough space for the copy, List.nil() doesn't work. – Adriano May 29 '12 at 16:51

5 Answers5

2

You cannot make this cast.

What happens if you cast a List<JCStatement> to a List<JCTree> and then you add a JCTree (non JCStatement) object to that list? It breaks the List<JCStatement> type safety.

Erick Robertson
  • 32,125
  • 13
  • 69
  • 98
ControlAltDel
  • 33,923
  • 10
  • 53
  • 80
  • +1 Edited for clarity. If OP explains why he thinks this is the solution, we can try to help him find a better solution. He hasn't provided enough information for us to know the way to solve the problem. – Erick Robertson May 29 '12 at 16:43
  • There are no other objects I'm supposed to insert into the List, adding one would probably break the compiler in some point. – Adriano May 29 '12 at 16:53
2

If you know you won't add any elements to the list -- so it will be type-safe -- then Collections.unmodifiableList(List<? extends E>) will return a List<E>.

This is totally type-safe and legit, because it enforces the guarantee that you'll never add an illegal element to the list, and it's provided by the JDK.

Louis Wasserman
  • 191,574
  • 25
  • 345
  • 413
1

Would something like this work for you?

import java.util.ArrayList;
import java.util.List;

class A {
}

class B extends A {
}

class C extends A {
}

public class Program {
    public static void foo(List<? extends A> list) {
    }

    public static void main(String[] args) {
        List<A> listA = new ArrayList<A>();
        List<B> listB = new ArrayList<B>();
        List<C> listC = new ArrayList<C>();
        List<? extends A> listX = (List<? extends A>) listB;
        List<? extends A> listY = (List<? extends A>) listC;

        foo(listA);
        foo(listB);
        foo(listC);
        foo(listX);
        foo(listY);
    }
}
William Brendel
  • 31,712
  • 14
  • 72
  • 77
  • No, even worse: `The method appendList(List) in the type ListBuffer is not applicable for the arguments (List)` – Adriano May 29 '12 at 16:35
  • Oh sorry, I didn't realize that you don't have any control over the method signature in this case. My code sample would work if you were able to change the method signature to accept a `List extends JCTree>` instead of `List`. I'll leave this answer here *just in case* someone's finds it helpful. – William Brendel May 29 '12 at 16:42
1

This seems to be an issue with the List, or generic types collections as general.

Simplest solution ever:

ListBuffer<JCTree> ls = new ListBuffer<JCTree>();
for(JCVariableDecl v : params){ ls.append(v); }
return ls.toList();
Adriano
  • 389
  • 3
  • 11
0

You can do it if you're really really sure it's safe by casting through the Raw Type

List<Number> listA = new LinkedList<Number>();
List<Integer> listB = new LinkedList<Integer>();
listA = (List<Number>)(List) listB;

I cannot imagine myself ever thinking that's a good solution to a problem, but it will do what you want, and there are some irritating limitations to compile time generics :)

There will always be a warning for a Unsafe cast, because what you're doing is in fact unsafe. There is no way for the compiler to make it safe, you have to be sure of that yourself.

Affe
  • 47,174
  • 11
  • 83
  • 83