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.
Related
I'm trying to create a map like this
Map<String, Class<abstractClass>> map = HashMap<String, Class<abstractClass>>();
For its input, I tried
map.put("exampleString", childClass.class);
But this doesn't work, the IDE says wrong 2nd argument type.
Found: java.lang.Class<childClass>, required java.lang.Class<abstractClass>
Even though there's an inheritance relationship between them.
Does anyone know how to solve this problem?
Thanks in advance!
You need a generic wildcard:
Class<? extends abstractClass>
This is because generic parameters by default are invariant. You could only put abstractClass.class in the map before the change.
By adding <? extends abstractClass>, you are making the generic parameter contravariant. In other situations, you can change extends to super to achieve covariance. There is an acronym for remembering when to use extends and when to use super, called PECS.
It looks to me that the childClass.class does not extend / implement the abstract class.
Please show the childClass signature.
Are you sure you don't just want:
Map<String, abstractClass> map = HashMap<String, abstractClass>();
map.put("exampleString", childClass);
?
What you have is you are taking the actual meta signature of the class and putting it into a map, instead of the actual reference to a class
Actually I solved this problem by changing
Class<abstractClass>
into
Class<? extends abstractClass>
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'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
I'm writing a generic function in java, however, I can't seem to tell if there's any way of setting a list of classes that a Generic Object must be in.
Something like this:
public static <T in {String.class, Integer.class, Long.class}> Collection<T> test(Collection<T> val);
You can have Bounded Type Parameters like this for example:
public static <T extends String & Runnable> Collection<T> test(Collection<T> val);
But your example will not work since you have several classes and Java does not support Multiple inheritance.
Also, your examples String, Integer and Long are final so they will not possible to extend anyway.
No. You can't do that in java.
What you desire is an "OR" bound. Java allows "AND" bounding, eg:
List<T extends Runnable & Comparable<T>>
But the analogous "OR" is not supported:
List<T extends Integer | String> // doesn't compile
When you think about it, it doesn't make any sense. Use separate classes/methods for each type bound.
Unfortunately you can't do what you're trying to do in Java - if it allowed you to specify a generic from a list, you'd be able to write a function which operated either on Integers or ArrayLists, which makes no sense as they don't share common functionality. If you want to limit your method to certain types, either find a base class/interface which they all inherit from supporting the functionality you need (public static <T extends BaseClass> Collection<T> test(Collection<T> val);) or write a set of oveloaded methods, one for each type you want to support.
Well you can and can not at the same time.
In your specific example it is impossible.
But such an example would work:
public <T extends CharSequence & Comparable & Closeable> void go(){
For your case I would go with:
public <T extends Number & CharSequence> void go() // same rule applies as extend a class and implement as many interfaces as you want
You cannot do that. Generics is only for enforcing type safety (guaranteeing that the type can perform a particular method, etc.). There is no type-safety requirement that correspond to such an "OR" bound. Requirements on type safety only require an "AND" bound.
This code has an error in it but I dont know how I can go about correcting it:
public class Point<T extends Number super Integer>{
}
Super is only valid with wildcards, not with named type parameters.
Let's imagine the compiler allowed that. There are only two types that can be said to extend Number and be a supertype of Integer, those are Number and Integer.
I'm struggling to see what benefit you would get in doing this rather than a straightforward non-generic Point type with int fields.
If the real case is more involved and you want a generic Point that could use Doubles, Integers etc., sure, use T extends Number if the Number restriction helps to avoid mistakes.
However, just having T extends Number does not give you access to +, -, *, etc. You might want the type class pattern for that, which involves having a separate dictionary of operations passed from the point where the generic type is created to where the numeric operations happen.
E.g.,
interface NumericOperations<T extends Number> {
T plus(T x, T y);
T subtract(T x, T y);
T multiply(T x, T y);
...
}
You would need to define instances of that type class, e.g., public static final NumericOperations intOperations = new NumericOper.....;
..and pass those instances around to get at plus, minus etc., within Point's methods.
public class Point<T extends Number>{
}
or this
public class Point<T extends Integer>{
}
You can't use super like that. See here: java generics super keyword
You can only use the super keyword with a wildcard.
You should take a look at the PECS principle : Provider Extends Consumer Super.
The super keyword is used in generics methods for consumer generic objects.
Example :
public void copyList(List<? extends Number> elementsToBeCopied,
List<? super Integer> listToBeFilled) {...}
Remark : Integer is a final class and cannot be extended, so the extends keyword is unnapplicable.
This article shows a good example of how super and extends can be used.