views:

3113

answers:

5

Please consider the following snippet:

public interface MyInterface {

    public int getId();
}

public class MyPojo implements MyInterface {

    private int id;

    public MyPojo(int id) {
        this.id = id;
    }

    public int getId() {
        return id;
    }

}

public ArrayList<MyInterface> getMyInterfaces() {

    ArrayList<MyPojo> myPojos = new ArrayList<MyPojo>(0);
    myPojos.add(new MyPojo(0));
    myPojos.add(new MyPojo(1));

    return (ArrayList<MyInterface>) myPojos;
}

The return statement does a casting that doesn't compile. How can I convert the myPojos list to the more generic list, without having to go through each item of the list?

Thanks

+17  A: 

Change your method to use a wildcard:

public ArrayList<? extends MyInterface> getMyInterfaces() {    
    ArrayList<MyPojo> myPojos = new ArrayList<MyPojo>(0);
    myPojos.add(new MyPojo(0));
    myPojos.add(new MyPojo(1));

    return myPojos;
}

This will prevent the caller from trying to add other implementations of the interface to the list. Alternatively, you could just write:

public ArrayList<MyInterface> getMyInterfaces() {
    // Note the change here
    ArrayList<MyInterface> myPojos = new ArrayList<MyInterface>(0);
    myPojos.add(new MyPojo(0));
    myPojos.add(new MyPojo(1));

    return myPojos;
}

As discussed in the comments:

  • Returning wildcarded collections can be awkward for callers
  • It's usually better to use interfaces instead of concrete types for return types. So the suggested signature would probably be one of:

    public List<MyInterface> getMyInterfaces()
    public Collection<MyInterface> getMyInterfaces()
    public Iterable<MyInterface> getMyInterfaces()
    
Jon Skeet
The 2nd solution is better one IMHO. Returning wild cards is generally considered bad practice, b/c it constrains the client code. In this case with ArrayList<? extends MyInterface> you could only read from the list, and could not add anything to it.
Julien Chastang
That may be what's wanted, of course - we just don't know. (It should almost certainly use List<T> instead of ArrayList<T> as well, or possibly just Iterable<T> or Collection<T>.)
Jon Skeet
Julien Chastang
Will edit the answer to reflect this.
Jon Skeet
+3  A: 

You should be doing:

public ArrayList<MyInterface> getMyInterfaces() {   
   ArrayList<MyInterface> myPojos = new ArrayList<MyInterface>(0);    
   myPojos.add(new MyPojo(0));    
   myPojos.add(new MyPojo(1));    
   return myPojos;
}
jschoen
A: 

In this case, I would do it like this:

public ArrayList<MyInterface> getMyInterfaces() {

    ArrayList<MyInterface> myPojos = new ArrayList<MyInterface>(0);
    myPojos.add(new MyPojo(0));
    myPojos.add(new MyPojo(1));

    return myPojos;
}

MyPojo ist of type MyInterface (as it implements the interface). This means, you can just create the List with the Interface you need.

Tobias Langner
A: 

Try to use interfaces everywhere except when constructing instances, and you problems will go away:

public List<MyInterface> getMyInterfaces()
{
    List<MyInterface> myInterfaces = new ArrayList<MyInterface>(0);
    myInterfaces.add(new MyPojo(0));
    myInterfaces.add(new MyPojo(1));

    return myInterfaces;
}

As others have said already, the use of MyInterface fixes your problem. It is also better to use the List interface instead of ArrayList for return types and variables.

starblue
The use of List isn't what fixes it there though - it's the use of MyInterface instead of MyPojo as the type argument.
Jon Skeet
Yes, that was misleading, fixed it now.
starblue
A: 

Choosing the right type from the start is best, however to answer your question you can use type erasure.

return (ArrayList<MyInterface>) (ArrayList) myPojos;

Peter Lawrey