If you wanted to store an array of objects of type MyInterface
, are the following both acceptable and if so when would you use the second form over the first?
i) Using only an interface:-
List<MyInterface> mylist = new ArrayList<MyInterface>();
ii) Using a generic wildcard:-
List<? extends MyInterface> mylist = new ArrayList<? extends MyInterface>();
Edit:
As the answers so far have pointed out, number ii won't compile. What is the difference between i and a case iii where :-
iii) Using a generic wildcard only in the reference:-
List<? extends MyInterface> mylist = new ArrayList<MyInterface>();
In generic code, the question mark (?), called the wildcard, represents an unknown type. The wildcard can be used in a variety of situations: as the type of a parameter, field, or local variable; sometimes as a return type (though it is better programming practice to be more specific).
8. Java Generic Classes and Subtyping. We can subtype a generic class or interface by extending or implementing it. The relationship between the type parameters of one class or interface and the type parameters of another are determined by the extends and implements clauses.
Generics make a class, interface and, method, consider all (reference) types that are given dynamically as parameters. This ensures type safety. Generic class parameters are specified in angle brackets “<>” after the class name as of the instance variable.
It is possible to create a non-generic class that implements a generic interface, provided that the type parameters are provided.
Second one won't compile. Imagine:
A implements MyInterface
B implements MyInterface
Then the following would match your second expression, but won't compile:
// incorrect
List<A> mylist = new ArrayList<B>();
Correction: Wrong one too:
List<? extends MyInterface> mylist = new ArrayList<MyInterface>();
It is right in a sense it does compile, but you cannot add any subclasses of MyInterface to it. Confusing, but correct -- after I read the explanation. Same reason: wildcard can be viewed for example as:
// I know this is not compileable; this is internal compiler "thinking".
// Read it as "somewhere someone may instantiate an ArrayList<A> and pass
// it down to us; but we cannot accept it as something that could be
// potentially used as List<B>"
List<A> mylist = new ArrayList<MyInterface>();
So this won't work:
mylist.add(b);
and vice versa. Compiler refuses to do those potentially incorrect operations.
The option which allows you to add any subclass of MyInterface to mylist is:
List<MyInterface> mylist = new ArrayList<MyInterface>();
If you would like to store the ojects of type MyInterface
the better (and compilable) approach would be -
List<MyInterface> mylist = new ArrayList<MyInterface>();
But if you would like to use in the method parameter then you can use option 2 (bounded wildcard type) for API flexibility.
public void someMethod(List<? extends MyInterface> myInterfaces);
EDIT:
The above code will give the more flexibility API because Generic types are invariant, so if you have -
public class A implements MyInterface {
// some implementation
}
and if someMethod
has a parameter type List<MyInterface>
then it won't be able to take the List<A>
, this forces API users to create List
with type MyInterface
on the other side - List<? extends MyInterface>
will allow to pass List<A>
to someMethod
.. client usually has a List<ActualObject>
so it's more flexible to provide a parameter which will take any implementation of MyInterface
At the same time do not use wildcard types as return types like
public List<? extends MyInterface> someMethod();
If the user of a class has to think about wildcard types, there is probably something wrong with the class’s API.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With