Java - Is "extends Object" really necessary on some Collections method specifications? [duplicate] - java

I've seen the wildcard used before to mean any object - but recently saw a use of:
<? extends Object>
Since all objects extend Object, are these two usages synonymous?

<?> and <? extends Object> are synonymous, as you'd expect.
There are a few cases with generics where extends Object is not actually redundant. For example, <T extends Object & Foo> will cause T to become Object under erasure, whereas with <T extends Foo> it will become Foo under erasure. (This can matter if you're trying to retain compatibility with a pre-generics API that used Object.)
Source: http://download.oracle.com/javase/tutorial/extra/generics/convert.html; it explains why the JDK's java.util.Collections class has a method with this signature:
public static <T extends Object & Comparable<? super T>> T max(
Collection<? extends T> coll
)

Although <?> is supposed to be a shortcut for <? extend object>, there is a tiny difference between the two.
<?> is reifiable while <? extend object> is not. The reason they did this is to make it easier to distinguish reifiable type. Anything that looks like <? extends something>,<T>,<Integer> are nonreifiable.
For example, this code would work
List aList = new ArrayList<>();
boolean instanceTest = aList instanceof List<?>;
but this gives an error
List aList = new ArrayList<>();
boolean instancetest = aList instanceof List<? extends Object>;
for more info read Java generics and collections by Maurice Naftalin

<?> is a shorthand for <? extends Object>.
You may read below shared link for more details.
<?>
"?" denotes any unknown type, It can represent any Type at in code for. Use this wildcard if you are not sure about Type.
ArrayList<?> unknownList = new ArrayList<Number>(); //can accept of type Number
unknownList = new ArrayList<Float>(); //Float is of type Number
Note: <?> means anythings. So It can accept of Type which are not inherited from Object class.
<? extends Object>
<? extends Object> means you can pass an Object or a sub-class that extends Object class.
ArrayList<? extends Number> numberList = new ArrayList<Number>(); //Number of subclass
numberList = new ArrayList<Integer>(); //Integer extends Number
numberList = new ArrayList<Float>(); // Float extends Number
T – used to denote type
E – used to denote element
K – keys
V - values
N – for numbersRef:

Related

What is the point of stating that a type wildcard must extend Object? [duplicate]

I've seen the wildcard used before to mean any object - but recently saw a use of:
<? extends Object>
Since all objects extend Object, are these two usages synonymous?
<?> and <? extends Object> are synonymous, as you'd expect.
There are a few cases with generics where extends Object is not actually redundant. For example, <T extends Object & Foo> will cause T to become Object under erasure, whereas with <T extends Foo> it will become Foo under erasure. (This can matter if you're trying to retain compatibility with a pre-generics API that used Object.)
Source: http://download.oracle.com/javase/tutorial/extra/generics/convert.html; it explains why the JDK's java.util.Collections class has a method with this signature:
public static <T extends Object & Comparable<? super T>> T max(
Collection<? extends T> coll
)
Although <?> is supposed to be a shortcut for <? extend object>, there is a tiny difference between the two.
<?> is reifiable while <? extend object> is not. The reason they did this is to make it easier to distinguish reifiable type. Anything that looks like <? extends something>,<T>,<Integer> are nonreifiable.
For example, this code would work
List aList = new ArrayList<>();
boolean instanceTest = aList instanceof List<?>;
but this gives an error
List aList = new ArrayList<>();
boolean instancetest = aList instanceof List<? extends Object>;
for more info read Java generics and collections by Maurice Naftalin
<?> is a shorthand for <? extends Object>.
You may read below shared link for more details.
<?>
"?" denotes any unknown type, It can represent any Type at in code for. Use this wildcard if you are not sure about Type.
ArrayList<?> unknownList = new ArrayList<Number>(); //can accept of type Number
unknownList = new ArrayList<Float>(); //Float is of type Number
Note: <?> means anythings. So It can accept of Type which are not inherited from Object class.
<? extends Object>
<? extends Object> means you can pass an Object or a sub-class that extends Object class.
ArrayList<? extends Number> numberList = new ArrayList<Number>(); //Number of subclass
numberList = new ArrayList<Integer>(); //Integer extends Number
numberList = new ArrayList<Float>(); // Float extends Number
T – used to denote type
E – used to denote element
K – keys
V - values
N – for numbersRef:

Why ListList<? super E> is List<? extends List<? super E>> but not List<List<? super E>>

I have a generic interface interface ListList<E> extends List<List<E>>. For some reasons, I can't cast ListList<? super T> to List<List<? super T>>. Is there any way of doing it and why it doesn't work?
By this moment I've already tried the following:
Simple assignment, this way I've managed to assign ListList<? super T> to List<? extends List<? super T>> (1), but when I try to assign ListList<? super T> to List<List<? super T>> I get Incompatible types compile-time error (1.1).
Explicit type conversion, it doesn't work because of the same Incompatible types compile-time error (2).
Casting to raw type ListList, it works (3), but I don't like raw types.
Adding all elements from ListList<? super T> to List<? extends List<? super T>>, it works (4), but I need a more general solution which works not only with ListList<E>, but with any generic type.
Here is my code:
ListList<? super T> var = new ArrayListList<>();
List<? extends List<? super T>> work = var; // (1)
List<List<? super T>> notWork = var; // (1.1)
List<List<? super T>> explicit = (List<List<? super T>>) var; // (2)
List<List<? super T>> raw = (ListList) var; // (3)
List<List<? super T>> copy = new ArrayList<>(); // (4)
copy.addAll(var); // (4)
I've expected ListList<? super T> to be List<List<? super T>>, but it appeared to be List<? extends List<? super T>>. I need to know why it is and how I can cast it to List<List<? super T>> without raw types and copying of elements.
At first, it looks like these assignments should all succeed, but they don't because of the inner wildcard ? super T. If we remove those wildcards, then all the assignments compile.
public static <T> void test() {
ListList<T> var = new ArrayListList<>();
List<? extends List<T>> work = var; // Compiles
List<List<T>> notWork = var; // Compiles
List<List<T>> explicit = (List<List<T>>) var; // Compiles
List<List<T>> raw = (ListList) var; // Compiles with warning
List<List<T>> copy = new ArrayList<>(); // Compiles
copy.addAll(var); // Compiles
}
I still get the unchecked conversion warning for (3), but they all still compile.
At first glance it looks like declaring the interface
ListList<E> extends List<List<E>>
makes a ListList equivalent to a List of Lists. However what you have done is take a nested type parameter and made it the main type parameter. The reason that that makes a difference is nested wildcards don't perform wildcard capture.
A nested wildcard here means "a list of lists of any type matching the bound", but a main-level wildcard here means "a 'listlist' of a specific yet unknown type matching the bound".
One cannot add an object that is a supertype of the lower bound to a collection, because the type parameter -- a specific yet unknown type -- may be the actual bound.
List<? super Integer> test2 = new ArrayList<>();
test2.add(2); // Compiles; can add 2 if type parameter is Integer, Number, or Object
test2.add((Number) 2); // Error - Can't add Number to what could be Integer
test2.add(new Object()); // Error - Can't add Object to what could be Integer
Because Java's generics are invariant, the types must match exactly when type parameters are involved, so similar cases for ListList all fail to compile.
// My assumption of how your ArrayListList is defined.
class ArrayListList<E> extends ArrayList<List<E>> implements ListList<E> {}
ListList<? super Integer> llOfSuperI = new ArrayListList<>();
llOfSuperI.add(new ArrayList<Integer>()); // capture fails to match Integer
llOfSuperI.add(new ArrayList<Number>()); // capture fails to match Number
llOfSuperI.add(new ArrayList<Object>()); // capture fails to match Object
However, a List of List compiles with all 3 cases.
List<List<? super Integer>> lOfLOfSuperI = new ArrayList<>();
lOfLOfSuperI.add(new ArrayList<Integer>()); // no capture; compiles
lOfLOfSuperI.add(new ArrayList<Number>()); // no capture; compiles
lOfLOfSuperI.add(new ArrayList<Object>()); // no capture; compiles
Your ListList is a different type than a List of Lists, but the differing generics behavior of where the type parameter is defined means that there is different generics behavior. This is why you cannot directly assign a ListList<? super T> to a List<List<? super T>> (1.1), and also why you can't cast it (2). You can cast to a raw type to get it to compile (3), but that introduces the possibilities of ClassCastException in future use of the casted object; that is what the warning is about. You can assign it to a List<? extends List<? super T>> (1), introducing another wildcard to capture a subtype relationship, but that introduces a wildcard to be captured; you won't be able to add anything useful to that list.
These differences have arisen only because a wildcard introduces wildcard capture and the associated differences. Without using a wildcard, a ListList<E> is equivalent to a List<List<E>> and as shown at the top of this answer, shows no problems compiling the code.
If you want all of your sub-lists to use the same exact type parameter, then go ahead and use your ListList interface, but don't use any wildcards. This forces the exact same type parameter for all lists that are added to your ListList, i.e. a ListList<Integer> can only hold List<Integer>s.
If you want all of your sub-lists to simply match a wildcard, e.g. contain a List<Number>, List<Integer>, and List<Object> in the same list, then just use a List<List<? super T>> to avoid wildcard capture.

Using addAll() on List<? extends E> a and b doesn't work

Why doesn't this compile?
List<? extends Number> a = new ArrayList<>();
List<? extends Number> b = new ArrayList<>();
a.addAll(b);
Because it wouldn't be safe.
List<? extends Number> should be read as some list where the element type extends Number. So in runtime a could be a List<Long> and b could be a List<BigInteger>. In that case, a.addAll(b) would mean "add all BigIntegers to the list of Longs" which, if allowed, obviously wouldn't be type safe.
https://google.github.io/guava/releases/19.0/api/docs/com/google/common/collect/Iterables.html
What really worked for me was Guava:
com.google.common.collect.Iterables.concat(...)
List<? extends Number> means
Items in this List have all the same class. Not only do they extend
Number, but are all the same type.
Due to type erasure during compile, the byte code interpreter does not know (and cannot infer), whether the ? of a and the ? refer to the same class.

Java nested generic type

How come one must use the generic type Map<?, ? extends List<?>> instead of a simpler Map<?, List<?>> for the following test() method?
public static void main(String[] args) {
Map<Integer, List<String>> mappy =
new HashMap<Integer, List<String>>();
test(mappy);
}
public static void test(Map<?, ? extends List<?>> m) {}
// Doesn't compile
// public static void test(Map<?, List<?>> m) {}
Noting that the following works, and that the three methods have the same erased type anyways.
public static <E> void test(Map<?, List<E>> m) {}
Fundamentally, List<List<?>> and List<? extends List<?>> have distinct type arguments.
It's actually the case that one is a subtype of the other, but first let's learn more about what they mean individually.
Understanding semantic differences
Generally speaking, the wildcard ? represents some "missing information". It means "there was a type argument here once, but we don't know what it is anymore". And because we don't know what it is, restrictions are imposed on how we can use anything that refers to that particular type argument.
For the moment, let's simplify the example by using List instead of Map.
A List<List<?>> holds any kind of List with any type argument. So i.e.:
List<List<?>> theAnyList = new ArrayList<List<?>>();
// we can do this
theAnyList.add( new ArrayList<String>() );
theAnyList.add( new LinkedList<Integer>() );
List<?> typeInfoLost = theAnyList.get(0);
// but we are prevented from doing this
typeInfoLost.add( new Integer(1) );
We can put any List in theAnyList, but by doing so we have lost knowledge of their elements.
When we use ? extends, the List holds some specific subtype of List, but we don't know what it is anymore. So i.e.:
List<? extends List<Float>> theNotSureList =
new ArrayList<ArrayList<Float>>();
// we can still use its elements
// because we know they store Float
List<Float> aFloatList = theNotSureList.get(0);
aFloatList.add( new Float(1.0f) );
// but we are prevented from doing this
theNotSureList.add( new LinkedList<Float>() );
It's no longer safe to add anything to the theNotSureList, because we don't know the actual type of its elements. (Was it originally a List<LinkedList<Float>>? Or a List<Vector<Float>>? We don't know.)
We can put these together and have a List<? extends List<?>>. We don't know what type of List it has in it anymore, and we don't know the element type of those Lists either. So i.e.:
List<? extends List<?>> theReallyNotSureList;
// these are fine
theReallyNotSureList = theAnyList;
theReallyNotSureList = theNotSureList;
// but we are prevented from doing this
theReallyNotSureList.add( new Vector<Float>() );
// as well as this
theReallyNotSureList.get(0).add( "a String" );
We've lost information both about theReallyNotSureList, as well as the element type of the Lists inside it.
(But you may note that we can assign any kind of List holding Lists to it...)
So to break it down:
// ┌ applies to the "outer" List
// ▼
List<? extends List<?>>
// ▲
// └ applies to the "inner" List
The Map works the same way, it just has more type parameters:
// ┌ Map K argument
// │ ┌ Map V argument
// ▼ ▼
Map<?, ? extends List<?>>
// ▲
// └ List E argument
Why ? extends is necessary
You may know that "concrete" generic types have invariance, that is, List<Dog> is not a subtype of List<Animal> even if class Dog extends Animal. Instead, the wildcard is how we have covariance, that is, List<Dog> is a subtype of List<? extends Animal>.
// Dog is a subtype of Animal
class Animal {}
class Dog extends Animal {}
// List<Dog> is a subtype of List<? extends Animal>
List<? extends Animal> a = new ArrayList<Dog>();
// all parameterized Lists are subtypes of List<?>
List<?> b = a;
So applying these ideas to a nested List:
List<String> is a subtype of List<?> but List<List<String>> is not a subtype of List<List<?>>. As shown before, this prevents us from compromising type safety by adding wrong elements to the List.
List<List<String>> is a subtype of List<? extends List<?>>, because the bounded wildcard allows covariance. That is, ? extends allows the fact that List<String> is a subtype of List<?> to be considered.
List<? extends List<?>> is in fact a shared supertype:
List<? extends List<?>>
╱ ╲
List<List<?>> List<List<String>>
In review
Map<Integer, List<String>> accepts only List<String> as a value.
Map<?, List<?>> accepts any List as a value.
Map<Integer, List<String>> and Map<?, List<?>> are distinct types which have separate semantics.
One cannot be converted to the other, to prevent us from doing modifications in an unsafe way.
Map<?, ? extends List<?>> is a shared supertype which imposes safe restrictions:
Map<?, ? extends List<?>>
╱ ╲
Map<?, List<?>> Map<Integer, List<String>>
How the generic method works
By using a type parameter on the method, we can assert that List has some concrete type.
static <E> void test(Map<?, List<E>> m) {}
This particular declaration requires that all Lists in the Map have the same element type. We don't know what that type actually is, but we can use it in an abstract manner. This allows us to perform "blind" operations.
For example, this kind of declaration might be useful for some kind of accumulation:
static <E> List<E> test(Map<?, List<E>> m) {
List<E> result = new ArrayList<E>();
for(List<E> value : m.values()) {
result.addAll(value);
}
return result;
}
We can't call put on m because we don't know what its key type is anymore. However, we can manipulate its values because we understand they are all List with the same element type.
Just for kicks
Another option which the question does not discuss is to have both a bounded wildcard and a generic type for the List:
static <E> void test(Map<?, ? extends List<E>> m) {}
We would be able to call it with something like a Map<Integer, ArrayList<String>>. This is the most permissive declaration, if we only cared about the type of E.
We can also use bounds to nest type parameters:
static <K, E, L extends List<E>> void(Map<K, L> m) {
for(K key : m.keySet()) {
L list = m.get(key);
for(E element : list) {
// ...
}
}
}
This is both permissive about what we can pass to it, as well as permissive about how we can manipulate m and everything in it.
See also
"Java Generics: What is PECS?" for the difference between ? extends and ? super.
JLS 4.10.2. Subtyping among Class and Interface Types and JLS 4.5.1. Type Arguments of Parameterized Types for entry points to the technical details of this answer.
This is because the subclassing rules for generics are slightly different from what you may expect. In particular if you have:
class A{}
class B extends A{}
then
List<B> is not a subclass of List<A>
It's explained in details here and the usage of the wildcard (the "?" character) is explained here.

Java Generic List<List<? extends Number>>

How come in java we cannot do:
List<List<? extends Number>> aList = new ArrayList<List<Number>>();
Even though this is OK:
List<? extends Number> aList = new ArrayList<Number>();
Compiler error message is:
Type mismatch: cannot convert from ArrayList<List<Number>> to List<List<? extends Number>>
In Java, if Car is a derived class of Vehicle, then we can treat all Cars as Vehicles; a Car is a Vehicle. However, a List of Cars is not also a List of Vehicles. We say that List<Car> is not covariant with List<Vehicle>.
Java requires you to explicitly tell it when you would like to use covariance and contravariance with wildcards, represented by the ? token. Take a look at where your problem happens:
List<List<? extends Number>> l = new ArrayList<List<Number>>();
// ---------------- ------
//
// "? extends Number" matched by "Number". Success!
The inner List<? extends Number> works because Number does indeed extend Number, so it matches "? extends Number". So far, so good. What's next?
List<List<? extends Number>> l = new ArrayList<List<Number>>();
// ---------------------- ------------
//
// "List<? extends Number>" not matched by "List<Number>". These are
// different types and covariance is not specified with a wildcard.
// Failure.
However, the combined inner type parameter List<? extends Number> is not matched by List<Number>; the types must be exactly identical. Another wildcard will tell Java that this combined type should also be covariant:
List<? extends List<? extends Number>> l = new ArrayList<List<Number>>();
I'm not very familiar with Java syntax but it seems that your issue is this:
Covariance & Contravariance
You should definitely use the ? type wildcard when appropriate, do not avoid it as a general rule. For example:
public void doThingWithList(List<List<? extends Number>> list);
allows you to pass a List<Integer> or a List<Long>.
public void doThingWithList(List<List<Number>> list);
allows you to only pass arguments declared as List<Number>. A small distinction, yes, but using the wildcard is powerful and safe. Contrary to how it may seem, a List<Integer> is not a subclass, or is not assignable, from List<Number>. Nor is List<Integer> a subclass of List<? extends Number, which is why the code above does not compile.
Your statement does not compile because List<? extends Number> is not the same type as List<Number>. The former is a supertype of the latter.
Have you tried this? Here I'm expressing that the List is covariant in its type argument, so it will accept any subtype of List<? extends Number> (which includes List<Number>).
List<? extends List<? extends Number>> aList = new ArrayList<List<Number>>();
Or even this. Here the type parameter for the ArrayList on the right-hand side is the same as the type parameter on the left-hand side, so variance is not an issue.
List<List<? extends Number>> aList = new ArrayList<List<? extends Number>>();
You should be able to just say
List<List<Number>> aList = new ArrayList<List<Number>>();
I tend to avoid the ? type wildcard whenever possible. I find that the expense incurred in type annotation is not worth the benefit.
List<List<? extends Number>> aList = new ArrayList<List<? extends Number>>();
aList.add(new ArrayList<Integer>());

Categories

Resources