Generic defined using an interface instead of class
How can I specify that I want any object that implements the A
interface to be allowed inside of the List
in a type-safe manner? I want to be able to invoke a given method of A over all of the objects, regarding what Class
type they are.
public interface A (){}
List<? extends A> myList = new ArrayList<? extends A>();
I am getting: Cannot instantiate the type ArrayList<? extends A>
If I leave the generic off of the instantiation side it works fine, but I have to specify @SuppressWarnings({ "rawtypes", "unchecked" })
to make the compiler hush up abo开发者_StackOverflow中文版ut the warnings.
To see why it doesn't make sense to instantiate a new ArrayList<? extends A>()
, in fact we can equivalently create a new ArrayList<B>()
with any arbitrary class or interface B
(even one that is not related to any of your objects) that implements A
, and the resulting created ArrayList can be safely assigned to a variable of type ArrayList<? extends A>
. Then you might wonder, oh, this is stupid, because the objects I want to put into it are not of class B, so how can this be the same? But it is the same, because you cannot put anything into a reference of type Something<? extends A>
anyway. This is why it doesn't make sense to create a new ArrayList<? extends A>()
.
How can I specify that I want any object that implements the A interface to be allowed inside of the List in a type-safe manner? I want to be able to invoke a given method of A over all of the objects, regarding what Class type they are.
That's exactly what ArrayList<A>
is. It allows all instances of A
(of course all objects that implement A
are instances of A
) and you can use any methods of A
on them. Something like this is what you want:
List<A> myList = new ArrayList<A>();
Something like List<? extends A>
is only used in cases when you will get a List object from some other code, and you don't know (or care) what exactly is the generic parameter they created it with. (In such a case you cannot put objects into the List.) This is completely different from your case here, where you are creating the List object, so you decide and therefore know exactly what generic parameter is used.
The issue is not related to binding a type parameter to an interface, but that you can't instantiate a parameterized type with a wildcard. new ArrayList<? extends A>()
or even new ArrayList<?>()
doesn't make sense because you're not telling the compiler what the instantiated List
actually holds. new ArrayList<A>()
on the other hand would make sense.
just List<A>
is fine this allows objects that implement A in the list and that all objects in the list implement A
I think you are looking for:
List<? super A> myList = new ArrayList<A>();
- List<? extends A> myList ... that is telling the compiler that it is a list of some unspecified type and the unspecified type extends A. You can't put any A in this list because it might not be the right exact type. All the compiler knows is that any object in this list must be an A. I think you want List<? super A> myList. This is telling the compiler that List is of some unspecified type of which A extends. Now the compiler can let me put any A in the list.
- new ArrayList<? extends A>(); is just plain wrong.
You want
List <A> collection = new ArrayList <A> ();
By using the wildcard you are suppressing information to the compiler. You say you want to be able to both read and write to the 'List'. A generic '? super A' lets you write to the collection but not read from it. A generic '? extends A' lets you read from the collection but not write to it. Putting just 'A' in the generic parameter lets you both read from and write to the collection. See the free chapter from Joshua Bloch's seminal Effective Java on generics at http://java.sun.com/docs/books/effective/generics.pdf.
精彩评论