I'm trying to create a kind of service locator class, where there is a
Map<Integer, ? extends ISomething>
but I can't later do
myMap.put(0x00, new SomethingImplementor())
As I get a Error:(18, 33) java: incompatible types: org.sample.SomethingImplementor cannot be converted to capture#1 of ? extends ISomething
My class structure is as follows:
public interface ISomething {
public void doSomething();
}
public class SomethingImplementor implements ISomething {
#Override public void doSomething() {...}
}
Why can't I create this map and put values into it?
You don't need the wildcard at all.
You can directly use
Map<Integer, ISomething>
and you can implement every subclass of ISomething.
Anyway, to work with wildcards in this case you should use super. With extends you don't know what type it will be so you can't add anything to the map.
List is an example of a bounded wildcard. The ? stands for an unknown type, just like the wildcards we saw earlier. However, in this case, we know that this unknown type is in fact a subtype of Shape. (Note: It could be Shape itself, or some subclass; it need not literally extend Shape.) We say that Shape is the upper bound of the wildcard.
There is, as usual, a price to be paid for the flexibility of using wildcards. That price is that it is now illegal to write into shapes in the body of the method. For instance, this is not allowed:
You should be able to figure out why the code above is disallowed. The type of the second parameter to shapes.add() is ? extends Shape-- an unknown subtype of Shape. Since we don't know what type it is, we don't know if it is a supertype of Rectangle; it might or might not be such a supertype, so it isn't safe to pass a Rectangle there.
Wildcards: http://docs.oracle.com/javase/tutorial/extra/generics/wildcards.html
Don't use the unknown type ?:
Map<Integer, ISomething> map;
Nothing is gained by using the unknown type, simply specifying ISomething is sufficient and the right choice.
Further, generic types must match exactly; ie ? extends ISomething is not the same type as ISomething
Related
I have created an interface called Identifier. And a class which implements Identifier interface is MasterEntity bean like below.
public class MasterEntity implements Identifier{
}
In DAO method, I wrote a method like below method signature.
public Identifier getEntity(Class<Identifier> classInstance){
}
Now from Service I want to call the method like below.
dao.getEntity(MasterEntity.class);
But am getting compilation error saying -
The method getEntity(Class<Identifiable>) in the type ServiceAccessObject
is not applicable for the arguments (Class<MasterEntity>)
I know if I use like below it will work.
public Identifier getEntity(Class classInstance){
But by specifying the Class of type Identifiable, how it can be done?.
Change DAO method signature to
public Identifier getEntity(Class<? extends Identifier> classInstance)
By declaring method as you described above you specify that the only applicable argument is Identifier.class itself. To be able to accept Identifier.class implementations, you should define generic type bounds.
List<? extends Shape> is an example of a bounded wildcard. The ? stands for an unknown type, just like the wildcards we saw earlier. However, in this case, we know that this unknown type is in fact a subtype of Shape. (Note: It could be Shape itself, or some subclass; it need not literally extend Shape.) We say that Shape is the upper bound of the wildcard.
Also you can take a look at this answer: https://stackoverflow.com/a/897973/1782379
Sorry guys, this might be a naive question.
I am a little bit confused by bounded type parameter and wildcard. What's the difference between <T extends String> and <? extends String>?
Thanks
I think you are mixing up some things here.
<T extends String> is used when you declare a generic class.
<? extends String> is used on instances from classes that are already generic.
Let’s take the interface “List” from the collections framework for example:
List <E> is the same like List <E extends Object> meaning that you can use the list with every datatype that inherits from Object.
The wildcard <?> can only be used on Classes that are already generic. Taking the example from above with List<E>.Let’s say you have a method that is using the List, but you don’t want to allow every datatype that inherits from Object.
You could use a distinct datatype like:
public void myMethod(List<String> list){
//…
}
But you could also use a range of datatypes that you want to allow:
public void myMethod(List<? extends String> list{
//..
}
In the second example you could use every datatype that is covariant with string i.e. is a child of string.
Tldr:
Bounds <T extends String> are used to declare the range of datatypes a generic class is supporting.
Wildcards <? extends String> are used on classes that are already generic and restrict/limit the given datatypes to a certain range.
The second one basically means: you really don't care about the actual type. You just care that it would extend String.
In other words: if your code does not need to use "T" anywhere; then you can make your intention more clear by "not at all mentioning that type name T".
For more technical background, one of the best resources is the work of Angelika Langer.
(For the purposes of this post, lets set aside java.util.Observable)
I was experimenting around with generics, and then wildcard types. The aim was to create a type-generic observable cache with deltas provided to the observers. Where this starts to go off the rails is I wanted to allow more generic observers to be used than the one specified in the Observable, e.g. Observer<Object> or some other common superclass.
I've since concluded that this is overly complex for my use case, but the problem itself continues to bother me since I clearly don't understand how to use type wildcarding properly.
So if we start with a simple observer interface:
public interface Observer<T> {
public void notifyChange(ChangeHolder<T> change);
}
And the associated ChangeHolder, in a full implementation this would be more complex, providing lists of added / updated / deleted objects, but this is sufficient to demonstrate the issue
public interface ChangeHolder<T> {
T getChange();
}
So with the Observer defined, I tried to implement the Observable abstract class:
public abstract class Observable<T> {
private Set<Observer<? super T>> observers = new HashSet<>();
public void addObserver(Observer<? super T> obs){
observers.add(obs);
}
public void change(ChangeHolder<T> changes){
for(Observer<? super T> obs : observers){
obs.notifyChange(changes);
}
}
}
And with that I could define some object caches, by declaring something like class TreeCache extends ObservableCache<Tree>, (From this point on I'll use Tree as an example class to be used as a T, assume it to be a simple POJO extending only from Object) and pass ChangeHolder<Tree> objects to TreeCache.change() when necessary. Unfortunately the compiler disagrees:
The method notifyChange(ChangeHolder<capture#2-of ? super T>) in the type Observer<capture#2-of ? super T> is not applicable for the arguments (ChangeHolder<T>)
Which is where my understanding ends.
Without the ChangeHolder class (if my notifyChange method just took a plain T instead) it works just fine since it's perfectly legal to pass a Tree to Observer.notifyChange(Object).
I inferred that I should be able to do the same with the ChangeHolder - ChangeHolder<T> should satisfy notifyChange(ChangeHolder<? super T>) in the same way that T satisfies notifyChange(? super T) but clearly I am misunderstanding something?
There is no wildcard in the signature notifyChange(ChangeHolder<T> change). Therefore the generic type of the passed argument must exactly match the generic type of the Observer instance.
Observer<? super T> means an Observer of some unknown type that is a supertype of T. Since the generic type of obs may not exactly match the generic type of changes, the notifyChange method is not applicable.
There are two possible fixes:
Change the signature to notifyChange(ChangeHolder<? extends T> change) so that the method works for subtypes.
Get rid of the wildcards everywhere, so that you have just <T> instead.
I prefer solution 1, as it is a good idea for signatures to be as general as possible.
I have the following interface
public interface Foo<T extends Bar> {
T getBar();
}
And the following class
public class FooFinder {
public Foo<? extends Bar> getFoo(final String fooName) {
return knownFoos.get(fooName);
}
private Map<String, Foo<? extends Bar>> knownFoos = new HashMap<>();
}
My question is this. Why is it required that I specify that getFoo returns a Foo<T extends Bar> and the values of knownFoos are Foo<T Extends Bar> when Foo can only ever be a Foo<T extends Bar> because of it's signature? I may naively believe that it has something to do with type erasure, but I'm not sure.
Addendum:
Take the Foo interface. T can only ever be a Bar or a subclass of Bar. The code and compiler make this clear. If we were to attempt the following
Foo<T extends Object> fooObj = new Foo<String>();
The compiler would tell you that String is not in the bound <T extends Bar>. So at compile time, we know that there is no Foo that can ever exist that is not bounded as T extends Bar. This is different from the List<T> example as there is no bound to T other than that it extends Object unless you specify otherwise.
With this in mind, if the compiler is intelligent enough to know the bounds of Foo can only be <T extends Bar>, why is it still required that I set the bound explicitly?
You don't have to as long as you don't mind using a different language.
Other languages make more use of a feature called type inference which does what you expect: look at the code and figure out stuff on its on. This of course comes at some cost. For example Scala is known for long compile times and sometimes confusing situations, when type inference doesn't inference the types the developer things it should.
With Java almost everything has to be specified manually (although there is now some type inference with the <> operator.
The alternatives you mentioned
Foo
Foo<T extends Bar>
Foo<? extends Bar>
are in fact different types, and you must choose wisely which to use.
Why is it required that I specify that getFoo returns a Foo< ? extends Bar>
As opposed to what? Returning a Foo which implicitly uses the generic Bar? That is not the same.
Let's use a concrete example:
List<? extends Number> getList();
This methods signature would tell you that it returns either a List<Integer> or a List<Float> or a List of any other subtype of Number. But the List will only contain objects of this one subtype. In this case the wildcard operator is used to signify to the caller that you just cannot tell him which subtype is used.
That is not the same as returning a List of Numbers, because a List of Numbers would be allowed to contain objects of any subtype of Number.
This distinction is important: If you returned a List<Number> the caller would be allowed to add any Number objects to the List. So the List would suddenly contain a mixture of Numbers whereas previously it only contained Integers. Using the wildcard operator prevents this, as the compiler cannot check whether the new Number is of the correct type.
And it is important that the compiler checks it. If it didn't you might run into ClassCastExceptions in other parts of your code, where the List is used with a concrete generic instead of the wildcard.
I am a little confused with something.
I have a class where its not a collection, but it does refer to generic objects:
public class XClass<E extends AnInterface>{
E instanceobject;
public void add(E toAdd){}
}
public interface AnInterface{}
public class A implements AnInterface{}
public class B implements AnInterface{}
I believe I read somewhere that <? extends AnInterface> is to be used (when declaring an instance of XClass) if you want multiple subtype-types in the generic object at the same time, whereas <T extends AnInterface> would only allow you to have a single type of subtype in the generic class at once?
However, I can just use:
XClass<AnInterface> xc = new XClass<AnInterface>();
A a = new A();
B b = new B();
xc.add(a);
xc.add(b);
and this way I can pass in multiple subtypes of Supertype to the generic class......
I am not seeing the purpose of using "?" and is there anything wrong with using the Interface as the generic parameter?
The reason why you can add objects of both type A and B is due to the fact that you parametized your XClass with the interface, so there is nothing wrong with adding two different classes that implement that interface.
If, on the other hand, you had defined XClass as:
XClass<A> xc = new XClass<A>();
then the expression xc.add(b); would give a compilation error, since all the objects added must have the same type as was declared, in this case, A.
If you declare you xc as, for instance:
XClass<? extends AnInterface> xc = new XClass<AnInterface>();
Then it's not legal anymore to add a or b, since the only thing we know is that xc is of some unknown but fixed subtype of AnInterface, and there is no way to know if that unknown type is A or B or anything else.
But let's say you're writing a method to accept a XClass type that you can iterate over the elements that were added before. Your only restriction (for the sake of the example), is that the items extend AnInterface, you don't care what the actual type is.
You can declare this method like:
public static void dummyMethod(XClass<? extends AnInterface> dummy){
//do stuff here, all the elements extend (implement in this case), AnInterface, go wild.
}
And now you can pass into this method anything like XClass<A>, XClass<B> or XClass<AnInterface>, and it will all be valid.
Keep in mind that you can't add to the object you pass, for the same reason above. We don't know what the unknown type is!
public static void dummyMethod(XClass<? extends AnInterface> dummy){
//do stuff here, all the elements extend (implement in this case), AnInterface, go wild.
dummy.add(new A()); //you can't do this, we have no idea what type ? stand for in this case
}
You can use E if you want to have an instance of XClass to use only one subclass of AnInterface and no other Classes implementing AnInterface that do not extend / implement E.
For example given
public class ClassOne implements AnInterface {} and public class ClassTwo implements AnInterface {}
If you were to use
public class XClass<E extends AnInterface> and <ClassOne>XClass xc = new <ClassOne>XClass() then you can only use an object of ClassOne in your add method not one of ClassTwo. Using ? would allow you to pass in any class implementing AnInterface, either ClassOne or ClassTwo.
Using Identifier E means "For this object I want to use type E and any subclasses", using ? means "I want to use any type that matches the the expression"
In your example you need type erasure in the method "add", so you should't use wildcards in your class.
Wildcards are only to be used when you do not need type erasure (i.e. you don't care about the type as long as it is a subclass of..) and also when you will need to subtype the generics itself.
The wildcard simply means that it will be some class that meets that criteria. So ? extends AnInterface means it will be one (and only one) class that extends AnInterface.
So it could be:
XClass<Impl1>
XClass<Impl2>
etc...
However, at runtime, you don't know what that class will be. For this reason calling methods which take the actual type as a parameter is inherently unsafe, since it's impossible for the compiler to know if the parameter is appropriate for the actual instantiated instance.
Take lists as an example. Something might be declared like this:
List<? extends Number> list = new ArrayList<Integer>();
What would happen if you try to do either of these:
list.add(new Double(0));
list.add((Number) new Long(1L));
It would not compile, because the generic parameter type is unknown at compile time. So the compiler can't tell if Double or Number would be appropriate to pass to the actual instance (in this case ArrayList<Integer>). This is when you get the infamous capture-of compile error.
This, however is permissible, since you know for certain at compile time that the list can take any instance of Number (which includes subclasses).
List<Number> list = new ArrayList<Number>();
list.add(new Double(0));
list.add((Number) new Long(1L));