What's the difference between these generic declarations? - java

How would you describe – in plain english – the difference between the contents of these lists?
I'm looking for a simple comparison that can be used as a reference.
/* 1 */ List< List< Dog>>
/* 2 */ List< List<? extends Dog>>
/* 3 */ List<? extends List< Dog>>
/* 4 */ List<? extends List<? extends Dog>>
The generic declarations with super are similar. So what about these:
/* 5 */ List<? super List<? extends Dog>>
/* 6 */ List<? extends List<? super Dog>>
Related questions & resources
Explanation of the get-put principle
Generics : List<? extends Animal> is same as List<Animal>?
http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html
http://docs.oracle.com/javase/tutorial/java/generics/

A List whose elements are lists of dogs
A List whose elements are lists of a type that extends Dog
A List whose elements are a single subtype of a list of dogs
A List whose elements are a single subtype of a (list of a type that extends Dog)
A List whose elements are a single supertype of a (list of a type that extends Dog)
A List whose elements are a single subtype of a (list of a type that super Dog)
Where "subtype", "supertype", "super", and "extends" are the "generic" versions (i.e. also includes the bounding type)
Examples with Number and subtypes, because why not. Replace Dog with Number.
List<List<Number>> might look like a 2D array of Number elements. Pretty simple.
List<List<? extends Number>> might look like a 2D array, where each row is a different subtype of number. For example, the first row might be a List<Integer>, the second row might be a List<Double>, etc.
List<? extends List<Number>> might be a List<ArrayList<Number>>, List<List<Number>>, List<LinkedList<Number>>, etc. The Number has to stay, because generics are invariant, but you can have List or any of its subtypes as the "overall" type of the elements. You can only pick one of List or its subtypes though, and the one you pick you have to stay with.
List<? extends List<? extends Number>> is similar to List<? extends List<Number>>, except now you can pick Number or any of its subclasses as the elements of the "overall" 2D array. So you can have List<List<Integer>>, List<ArrayList<Integer>>, List<LinkedList<Double>>, etc. As before, you can only pick one of List's subtypes and one of Number's subtypes.
(tricky!) List<? super List<? extends Number>> appears to be equivalent to List<List<? extends Number>>, List<Collection<? extends Number>>, etc. but not List<List<Number>> or anything concrete where a subtype of Number is used. I think this is because List<Number> isn't considered a supertype of List<? extends Number>, which I suppose makes sense due to generics being invariant. List<Object> as well as raw types (List<List>, List<Collection>, etc.) also works.
Same thing as 4, except you get either List<Number> or List<Object> (and apparently List<Serializable>) as the inner list.
As #MadProgrammer said, due to PECS (Producer-Extends-Consumer-Super), any time you have a ? extends for your generic type you won't be able to update the list, only retrieve items from it. So no add()-ing and no set()-ing.

The first one is concrete: it's a List of Lists of Dog, and nothing else.
The second one is abstract on the innermost declaration: it's a List of Lists of some class that inherits from Dog -- say Poodle. It might be a List<ArrayList<Poodle>>.
The third one is abstract on the inner list declaration: its a List of some sort of container that inherits from List -- maybe ArrayList -- of Dog. Then you might have List<ArrayList<Dog>>.
The fourth one is abstract on both: its a List of some kind of container derived from List, filled with some animal that inherits from Dog -- maybe List<ArrayList<Poodle>>.

Replace each "<" by "of".
Whenever there is a "? extends X", insert "or one of its subclasses" after X.

Related

Does wildcard <? super Number> refer to a superclass like Object or a subtype like Integer? [duplicate]

This question already has answers here:
What is PECS (Producer Extends Consumer Super)?
(16 answers)
Closed 5 months ago.
I am confused by whether wildcards <? super Number> refers to a superclass like Object or a subtype like Integer. In "Java OCP 17 Developer Complete Study Guide" by Jeanne Boyarsky and Scott Selikoff, (Chapter 9 Collections and Generics)
Generics allow you to specify wildcards. <?> is an unbounded wildcard
that means any type. <? extends Object> is an upper bound that means
any type that is Object or extends it. <? extends MyInterface> means
any type that implements MyInterface.
<? super Number> is a lower bound that means any type that is Number or a super class. A compiler error results from code that attempts
to add an item in a list with an unbounded or upper-bounded wildcard
A super class as I understand, is a parent of Number.
But then, why cannot one do this?
import java.util.ArrayList;
import java.util.List;
public class Bewildered {
static class A {}
static class B extends A {}
static class C extends B {}
public static void main(String[] args) {
List<? super B> listBs = new ArrayList<>();
listBs.add(new A());
}
}
compile error:
java: incompatible types: Bewildered.A cannot be converted to capture#1 of ? super Bewildered.B
Because you're thinking about what generics means in the wrong way.
List<? super B> does not mean: "A list that contains Bs or anything that is a supertype of B".
Because that would be utterly useless. Object is a supertype of B. All things are objects. So it's a list of absolutely anything, there's absolutely nothing useful about this list.
No, what List<? super B> means: There is a type. A specific type. It's just.. this code doesn't know what it is. We do know that it is either B or some supertype of B. (So, it's B, or A, or Object, we don't know. The caller picked one of these 3 types). This list is constrained; it cannot contain anything that is not this unknown type.
The point is, you can do this:
List<B> bees = new ArrayList<B>();
List<? super B> list = bees; // legal!
list.add(new A()); // um...
B bee = bees.get(0); // oh no!
See how this goes wrong? There's only one list here - bees and list are both just variables that refer to the exacrt same list. So you if you call list.add, you're modifying the one list that both bees and list are pointing at, so you also add it to bees.
So what's the point of <? super B>?
You can call .add(new B()). Because that works for all legal choices. Whatever the caller picked - if they gave you a List<B>, it works. If it's a List<A>, works. List<Object>? Still acceptable.
No other types fit the bill for <? super B>, so we've exhausted the options: They all 'work out'.

What is the ideal way of sorting Serializable list Java

I have a List<? extends Serializable> which contains an Integer list and I want it to be sorted. I can't use the Collection.sort() here. There is an exception saying
The inferred type capture#2-of ? extends Serializable is not a valid
substitute for the bounded parameter >
What would be the ideal way ?
List<? extends Serializable> list = Arrays.<Integer> asList(2, 3);
Here we're creating a List<Integer> but we're throwing away the compiler's knowledge that the elements are Integer. All the compiler knows about list is that it contains elements of type Serializable.
Collections.sort(list);
... won't compile. There is no method called Collections.sort() that accepts a single element of any of the types list has. There is Collections.sort(List<?
extends Comparable>), but our list doesn't fit this.
However we can use Collections.sort(List<T> list, Comparator<? super T> c) - we just need to supply a Comparator<? extends Serializable>.
And that's the problem. There's nothing about Serializable that makes sense to compare on. All you can do is an unsafe cast:
Collections.sort(list, Comparator.comparing(x -> (Integer) x));
You know this will work, because you've arranged that list actually contains Integer -- but casting like this is a code smell. If your class needs its input to be a list of Integer then pass in a List<Integer>.
Collections.sort(list, Comparator.comparing(x -> (Comparable) x));
... also works, but has the same smell.

Confused by the following data type

List<? extends List<? extends ObservationInteger>>
Just to give you a background which probably has nothing to do with the question. Trying to use the JAHMM library to build and score HMM's.
One of the parameters to the functions mentions the above as the datatype and I have no idea what it means.
From what I understand with help from a friend
List<? extends ObservationInteger> means a List of instances of any classes extending "ObservationInteger" which is a valid class in the library.
It is the outer List<? extends List<?... that is confusing me.
Can someone throw some light on this?
List<? extends List... means that it can be List of any Collections implementing List interface.
List<List<? extends ObservationInteger>> list = new ArrayList<List<ObservationInteger>>(); - compiler error because without ? extends compiler requires exact match:
List<List<? ObservationInteger>> list = new ArrayList<List<? extends ObservationInteger>>(); - OK
but this looks better
List<? extends List<? ObservationInteger>> list = new ArrayList<List<ObservationInteger>>(); - OK
It means any Class implementing List Interface with instances of any Class implementing List Interface with instances of any classes extending "ObservationInteger"
It is a List of Objects, which are all instances of a class that extends List.Because those objects are instances of Lists, each of them happens to contain a certain amount of Objects, which are all instances of a class that extends ObservationInteger.
It's a list of lists of things. Visualize it as a two-dimensional structure (rows & columns).
The ? extends means it is also valid for any subtypes of List and any subtypes of ObservationInteger.

Why is this such use of generic and wildcard not allowed?

This code
static void writeTo(List<? super Apple> apples) {
apples.add(new Apple());
apples.add(new Jonathan());
}
The author of this code stated that
The argument apples is a List of some type that is the base type of Apple; thus you know that it is safe to add an Apple or a subtype of Apple. Since the lower bound is Apple,
Jonathan is a subclass of Apple.
But when I tried this
List<Jonathan> loj = new ArrayList<Jonathan>();
listSuper(loj);
It gave me this error
The method listSuper(List<? super Apple>) in the type Basket<T> is not applicable for the arguments (List<Jonathan>)
Where listSuper looks like this
static void listSuper (List<? super Apple> cont) {}
How does the two differ?
Also what confuses me on the first code that I posted is that
I thought ? super T means that any base type of T. but from the looks of it he added a subtype of T. I am confused.
List<? super Apple> means a List you can add an Apple to (and since Jonathan is an Apple, you can put Jonathans into a List of that type as well).
It can be List<Apple>, List<Fruit> or List<Object>, but not List<Jonathan>, since you cannot put arbitrary Apples into List<Jonathan>. As you can see, in this case ? can be an Apple or any of its superclasses.
List<? extends Apple> means a List you can get an Apple from. It can be List<Apple> or List<Jonathan>, but not List<Fruit>, since List<Fruit> is not guaranteed to contain only Apples.
This explanation is known as "producer - extends, consumer - super" rule: if parameter acts as a consumer of elements, it should be declared with super, and vice versa.
Jonathan is a subtype of Apple, not a supertype. It would match <? extends Apple> but does not match <? super Apple>
The author of the code was wrong. You can't pass a subclass of Apple to a method that takes ? super Apple, only Apple itself and superclasses of Apple. If you want to be able to add subclasses of Apple, you need to use ? extends Apple.
The type parameter must be a supertype of Apple, not a subclass, which is what Jonathan is. So, for instance, this would be valid:
List<Fruit> loj = new ArrayList<Fruit>();
listSuper(loj);
How does the two differ?
Also what confuses me on the first code that I posted is that I
thought ? super T means that any base type of T. but from the looks of
it he added a subtype of T. I am confused.
You must distinguish between (1) what you can insert into a generic list and (2) what can be sent as an argument to method with a generic list parameter.
You can insert subtypes of Apple into apples because the bound type parameter is a base class which has the ability to reference all its subtypes.
If Jonathan isn't a super type of Apple, then it's generically incorrect to try and send a list of Jonathan to that method, since I'd be allowed to insert Apples into a list of Jonathans. Then you'd have references of type Jonathan accessing the properties and methods of objects it knows nothing about, which isn't type-safe.

Why is returning List<? extends T> read-only and returning List<? super T> write-only? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
What is a difference between <? super E> and <? extends E>?
Some Java programmers on a team I'm on are writing functions that return objects of type List<? extends T> to make read-only lists and return objects of type List<? super T> to make write-only lists.
In Java, what makes List<? extends T> read-only and List<? super T> write-only?
please read up on "producer extends, consumer super" (PECS) - I may need to do the same :)
Read only:
In case you would like to ensure that a method takes as a parameter a collection of items ( using generics) - when you use List<? extends T> - the list can contain any subtype of T but cannot add to the collection since it does not know at runtime the specific type of T that the List contains.
Write only:
For List<? super T>, the list can contain T regardless of the actual parameterized type (using super will allow that to happen).
Hope it helps.
You can get a T from a List<? extends T>, but the only thing you can put into it is a null literal. You can put a T into a List<? super T>, but the only thing you can get from it is an Object (which is then unsafe to cast down to T).
So, the restrictions make these pretty good, though imperfect, reminders of the intention. With a List<? extends T>, you can't put most things into it -- so it's kinda read-only. And with a List<? super T>, you can't get things out of it very usefully -- so it's kinda write-only.
Note that neither one of these is actually read- or write-only. I noted some of the ways you can get things into or out of them above, and with the "read-only" construct, you can still call remove functions, either on the object itself or on its iterator.
The definition List<? extends T> means "a List<X> implementation, where X must be T or a subclass/implementation thereof. In other words, your only guarantee is that objects already stored in the list will fit in a variable of type T. However, since the list may have been declared for a class extending or implementing T, you have no guarantee that objects of type T itself will fit into the list.
Simple example: List<String> is a List<? extends T> if T is Object. You can safely draw Object-type objects from it, but you can obviously not put other Object-type objects in it, unless they are definitely strings.

Categories

Resources