I was going through generics in Java and I'm having trouble trying to understand where I would use the following two.
I understand that the first myList would ensure that the list only contains elements of type Integer and all it's superclasses. Now I'm trying to figure out where myList2 would fit in here.
List<? super Integer> myList;
List<Class<? super Integer>> myList2;
Edit: It's not a duplicate of the question being linked...since this is clearly regarding the use of ? vs Class<? whereas the other question is about super vs extend
The first one, 'myList' may contain integer values. Example: myList.add(200);
The second one, 'myList2' may contain classes of type integer. Example: myList2.add(Integer.class);
Update:
As correctly pointed out in the comments, due to the "super" keyword being applied, in addition to objects/ classes of type Integer, all superclasses of the type Integer (that is: Number and Object) can be contained as well.
The first list contains objects of Integer and its superclasses.
The second one contains class objects (or simply classes) of Integer and its superclasses, i.e:
Integer.class;
Number.class;
You can read more about the differences here: The difference between Classes, Objects, and Instances
Related
There is the unmodifiableList method in the Collections class. It returns a List<T> but in the parameters it accepts List<? extends T>.
So if I understand this right then this method accepts a List which has T objects or objects that inherited from T class.
But I don't understand why the <? extends T> part in the parameter. I mean the parameter determines the return type of the method. If the method is called with List<Animal> then the return will be List<Animal> so it is going to be the same. Why we need this <? extends T>? Why don't we need just List<T> in the parameter list? I don't understand this.
If you could provide an example I would be happy about it.
Thank you in advance!
So if I understand this right then this method accepts a List which has T objects or objects that inherited from T class
This is oversimplifying matters.
a List<Number> can contain solely integers. The point of a List<Number> is that it is constrained to contain only number instances. Not that each instance MUST be Number and specifically Number - that would be impossible, as Number is abstract (no instances of Number itself can possibly exist, only instances of some subclass of it). The only difference between a List<Integer> containing only integers and a List<Number> containing only integers, is that you can add, say, a Double instance to that List<Number>, but you can't add it to a List<Integer>.
Because a method that takes, as argument, a List<Something> could invoke .add(), the type system needs to worry about the difference. It needs to do so even if this method does not, in fact, call add at all, and never intends to. The type system doesn't know that, and you're free to change the body of a method in some future version without that breaking backwards compatibility, thus, it matters. Even if you feel like it does not.
That then also explains your question:
If you have some method that demands a List<Number>, then you may provide a List<Integer> to Collections.unmodifiableList, and that's fine - Collections.uL will give you that List<Number>. This would ordinarily be broken, in that you can invoke .add(someDouble) which you should not be doing to a list of integers, but .add doesn't work on an unmodifiable, so it's fine.
List<? extends T> means it also accepts lists of subtypes.
Imagine having a class Plant and a class Tree that extends Plant.
You could create an unmodifiable List of Plants using a List<Tree> because Collections.unmodifiableList accepts lists of any subtype of T.
If it was List<T>, it would accept a List<Plant> as a parameter in order to create an unmodifiable List<Plant> but you could not create an unmodifiable List<Plant> using a List<Tree> as parameter.
List<? extends Number> l = new ArrayList<Integer>();
I have the above line of code.
The object 'l' can refer any objects which can be Number any of its sub types.
I know that we can not add anyting to the above list.
Then what is the use of "? extends any_object" since we can not add anything to it ?
In what kind of context it is used ?
Can anyone please explain.
Thanks!!
It’s most useful for method arguments. Consider this:
public void printFormatted(Collection<? extends Number> values) {
NumberFormat format = new DecimalFormat("0.000");
for (Number value : values) {
System.out.println(format.format(value));
}
}
If I declare the method with Collection<Number>, callers must pass a Collection (or List or Set) whose generic type is known to be Number. They cannot pass Collection<Integer>, because Collection<Integer> is not a subclass of Collection<Number> and in fact is not polymorphically compatible with Collection<Number>.
By declaring the method with Collection<? extends Number>, I am saying that callers can pass Collection<Number>, or Collection<Integer>, or Collection<Double>, etc. List<Integer> or Set<Integer> is also acceptable, since the class is polymorphic, even though the generic type is not.
One of possible examples:
When you pass such method as argument, you can iterate over elements of such such list and use methods appropriate to Number class. You need to be aware that you cannot add any elements to such list. You are able to use list.get() method and that way, you're sure that you will get an instanceof Number class.
Such list is then called a producer. If you would need to add elements to list, instead of retrieving them, you would use <? super Number>. That rule is called PECS (Producer Extends Consumer Super).
I understand that one reason Lower-bounded wildcards exist is so that a collection is not immutable when adding new elements.
E.g.
List<? extends Number> obj = new ArrayList<>();//Now this list is immutable
obj.add(new Integer(5));//Does not compile
List<? super Number> objTwo = new ArrayList<>();//This list is mutable
objTwo.add(new Integer(5));//Compiles
The following does not compile because I tried to get the long value of numbers.
Q1: What methods would I be able to use? Only Objects methods?:
public void testLowerBounds(List<? super Number> numbers){
if (!numbers.isEmpty()){
System.out.println(numbers.get(0).longValue());//Does not compile
}
}
How my question came about:
I am currently learning about streams and the book specifies the following stream method:
Optional<T> min(Comparator<? super T> comparator)
And implements it as follows:
Stream<String> s = Stream.of("monkey", "ape", "bonobo");
Optional<String> min = s.min((s1, s2) -> s1.length()—s2.length());
Q2: How is the comparator allowed to use string methods when is used?
If I had to answer Q2: I would say that optional is specifying "You have to pass me an implementation of Comparator that has a generic type "String" or something that implements "String". Would I be correct in saying this?
Looking forward to your response.
First of all, you should not confuse wildcard type parameters with mutability. Having a wildcard in a List’s element type does not prevent modifications, it only imposes a few practical restrictions to what you can do with the list.
Having a list declared like List<? extends Number> implies that the referenced list has an actual element type of Number or a subclass of Number, e.g. it could be a List<Integer> or List<Double>. So you can’t add an arbitrary Number instance as you can’t know whether it is compatible to the actual element type.
But you can still add null, as the null reference is known to be compatible with all reference types. Further, you can always remove elements from a list, e.g. call remove or clear without problems. You can also call methods like Collections.swap(list, index1, index2), which is interesting as it wouldn’t be legal to call list.set(index1, list.get(index2)) due to formal rules regarding wildcard types, but passing the list to another method that might use a non-wildcard type variable to represent the list’s element type works. It’s obviously correct, as it only sets elements stemming from the same list, which must be compatible.
Likewise, if you have a Comparator<Number>, you can call Collections.sort(list, comparator), as a comparator which can handle arbitrary numbers, will be able to handle whatever numbers are actually stored in the list.
To sum it up, having ? extends in a collection’s element type does not prevent modifications.
As said, you can’t insert arbitrary new elements into a list whose actual element type might be an unknown subclass of the bound, like with List<? extends Number>. But you are guaranteed to get a Number instance when retrieving an element, as every instance of subtype of Number is also an instance of Number. When you declare a List<? super Number>, its actual element type might be Number or a super type of Number, e.g. Object or Serializable. You can insert arbitrary Number instances, as you know it will be compatible to whatever actual element type the list has, as it is a super type of number. When you retrieve an instance, you only know that it is an instance of Object, as that’s the super type of all instances. To compare with the ? extends case, having a ? super declaration does not prevent reading, it only imposes some practical limitations. And likewise, you can still pass it to Collections.swap, because, regardless of how little we known about the actual type, inserting what we just retrieved from the same list, works.
In your second question, you are confusing the sides. You are now not looking at the implementation of min, but at the caller. The declaration of min(Comparator<? super T> c) allows the caller to pass any comparator being parameterized with T or a super type of T. So when you have a Stream<String>, it is valid to pass a Comparator<String> to the min method, which is exactly, what you are implementing via the (s1, s2) -> s1.length()—s2.length() lambda expression (though, I’d prefer Comparator.comparingInt(String::length)).
Within the implementation of min, there is indeed no knowledge about what either, T or the actual type argument of the Comparator, is. But it’s sufficient to know that any stream element that is of type T can be passed to the comparator’s compare method, which might expect T or a super type of T.
I'm having difficulty understanding wildcards in Java generics. Specifically I have the following questions:
If we have a LinkedList<?>, why can we not add an Object to it? I understand that it doesn't know the type of the list, but wouldn't adding an Object to the list have us covered in any situation?
Similar to the question above, if we have LinkedList<? extends Number>, why can we not add a Number to it?
Finally, if we have LinkedList<? super Number>, why can we add an Integer to the list, shouldn't we only be able to add things that are a superclass of Number?
I guess I'm trying to understand how wildcards work in general, I've read the Oracle tutorials on them, and a few other things, but I don't understand why they work I suppose.
You're confusing objects and types.
Unlike simple generic parameters, wildcards describe the type of the generic parameter.
A List<? super Number> isn't a list of superclasses of Number; it's a list of some unknown type, where that type is a superclass of number.
A LinkedList<?> might be a LinkedList<Car>.
Since an Object is not a Car, you can't add an Object to it.
In fact, since you don't know anything about what type the list contains, you can't add anything to it. (except null)
Similarly, a LinkedList<? extends Number> might be a List<Long>, so you can't add an Integer to it. (since an Integer is not a Long)
On the other hand, a List<? super Number> is definitely allowed to contain Number or any derived class, since it can only be a list of one of Number's superclasses (eg, List<Object>)
I am having a hard time to understand the concept of generics wild cards.
As per my understanding <?> type unknown is introduced to resolve the co-variance not supported in generics and it should fit any type of collection and <?extends T> means that you can have collection of types T or the class which extends T.<?super T> means you can have collection of types T or super(s) of T.
Please correct me, if the above is wrong.
When I try to write it like this:
import java.util.*;
public class Gclass {
static Gclass t;
public void write(List< ?super String > lw){
lw.add("b");
}
public void read(List< ? extends String> lr){
String s=lr.get(2);
System.out.println(s);
}
public static void main(String[] args) {
t=new Gclass();
List<String> l=new ArrayList<String>();
l.add("a");
l.add("");
System.out.println(l);
t.write(l);
System.out.println(l);
t.read(l);
System.out.println(l);
}
}
It works but my places of doubt are:
As per my understanding both (extends and super) includes the type declared, so in this particular case as my List is of type String. I could interchange the extends and super, but I get compilation error?
In case of write ? super Object is not working? It should work as it is super of String?
I did not check for read as String can not be extended, but I think I'm also missing a concept here.
I've read all answers on SO related to this problem, but am still not able to have a good understanding about it.
String is indeed a bit of a bad example as it is a final class, but consider something like Number instead.
If a method takes a parameter of type List<? extends Number> then you can pass it a List<Number> or a List<Integer> or a List<BigDecimal> etc. Within the method body it is therefore fine to take things out of the list (as you know they must be instances of Number) but you can't put anything in because you don't know whether or not it's safe (the compiler can't let you risk putting an Integer into a List<Float>, for example).
Conversely if the method takes List<? super Number> then you can pass it a List<Number> or List<Object> - you can't take anything out of this list because you don't know what type it is*, but you do know that it'll definitely be safe to put a Number in.
* technically you can take things out but the only type you can assign them to is Object
As per my understanding both(extends and super) includes the type declared(String here), so in this particular case as my List is of type String... I could interchange the extends and super but i get compilation error?
You're right that both ? extends String and ? super String includes String. But you are missing the point that, ? super String also includes CharSequence, Object, which is not in bounds of ? extends String. You can add a String to a List<? super String>, b'coz whatever type that list is of, it can definitely refer to a String. But, you cannot add say an Integer to a List<? extends Number>, because the list can be a List<Float> actually.
In case of write ? super Object is not working? It should work as it is super of String?
Object is a super class of String will fit in where you have ? super String, and use Object for that. So, ? super String can capture Object, but ? super Object cannot capture String, as String is not a super type of Object. Think of it like this: "Actual type replaces the ?, and it must satisfy the rules attached to that ?.
List<? super String> means that lw holds a value of List with type argument which is String or it's superclass, so you can add a String value "b" (because it can be casted to list's type argument).
List<? extends String> means that lw holds a value of List with type argument which is String or it's subclasses, so values from lw can be casted to String.