Code:
List<? extends Integer> ints= new ArrayList<Integer>();
ints.add(new SomeType());
I'm trying to reason why we cant add to ints formally. Please check the correctness.
Compiler always matched question mark to anonymous type CAP#n, where n is the ordinal number of wildcard declaration in the source code. From the fact that this wildrcard with extends implies that compiler internally assigned CAP#1 (in that case) just to anonymous type of null. But i'm not sure in this reason. Consider
List<? super Integer> ints= new ArrayList<Integer>();
ints.add(new Object());//error
In this case we have that compiler internally creates a new anonymous type, who marked CAP#2, such that only instance of all Integer's supertype is "instance of" CAP#2.
Question Do I understand the principle of wildcard's working correct now?
Let's try to look at the presented problem in different view, from java.util.List
public interface List<E> extends Collection<E> {
*
*
boolean add(E e);
*
*
}
When you specify List<? extends Integer>, the argument for add() becomes '? extends Integer'. From that description, the compiler cannot know which specific sub type of Integer is required there, so it won't accept any type of Integer.
The usage of List<? super Integer> tells to compiler that the it's possible to add to the list everything that is super type of Integer, addition of other types will violate static type safety.
You can thus begin to think of subtypes and supertypes bounds in terms of how you can "write" (pass into a method) to a generic type, and "read" (return from a method) from generic type.
Basically your technical description is right but I think that my explanation is more reasonable from static type safety point of view.
Hope it helps you.
Let's ignore the fact that Integer is final for purposes of this discussion.
When you give a variable the type of List< ? extends Integer >, the compiler does not allow you to call any method of List which has the generic type parameter as an argument to a method. These parameters are in what is known as contravariant position, and if the compiler would allow you to do what you are trying to do, Java's type system would be even more unsound than it already is. All the compiler knows is that the element type of the List is some unknown subtype of Integer, internally called CAP#1. Now attempting to call add( CAP#1, int ) with anything at all as first parameter will fail. The only exception is null, simply because unlike any other value in Java, null is a member of every reference type, so it must be a member of CAP#1. Note that the compiler will allow you to call any method of a List< ? extends Integer > that has no generic type inputs but possibly produces generic type outputs.
Contrary to the answer given by #Maxim Kirilov, when you give a variable the type of List< ? super Integer >, the compiler does not allow you to add any supertype of Integer. All it knows is that the unknown type is some supertype of Integer, internally called CAP#2, and that therefore anything which is an Integer or any subtype S of Integer can be added to the list (because no matter what CAP#2 turns out to be, S is a subtype of Integer which is a subtype of CAP#2, so add( CAP#2, int ) will accept an S in the first parameter).
By contrast, you are trying to call the method with an Object, which is not a subtype of Integer. The compiler rejects an attempt to pass an Object where a CAP#2 is required (as explained above).
Related
Consider the following code sample:
#SafeVarargs
public static <U> Object[] sortedCopy(Comparator<? super U> comparator, U... values) {
U[] copy = Arrays.copyOf(values, values.length);
Arrays.sort(copy, comparator);
return copy; //copy is implicitly cast to Object[] -> no heap pollution
}
public static <U> Object[] sortedCopy(U... values) {
return sortedCopy(Comparator.naturalOrder(), values); //why does this compile???
}
I would have expected the compiler to reject the line in sortedCopy(U...), with the following reasoning:
The return type of Comparator.naturalOrder() is Comparator<T>, where T is a generic type parameter of this method that must fulfill the constraint T extends Comparable<? super T>. Since the method does not accept any arguments, and its invocation in the above code does not explicitly specify a type for T (like Comparator.<U>naturalOrder(), which would not compile because U does not extend Comparable), T has to be inferred another way. The only way I can see to infer T is by the method signature of sortedCopy(Comparator<? super U>, U...). The compiler knows the type of values and can thus infer U, and in turn can also infer bounds for T, namely the bounded wildcard ? super U. But then, the compiler should realize that any ? super U can never meet the requirement for T specified by Comparator.naturalOrder(), which is T extends Comparable<? super T>, because U itself does not extend Comparable<? super U>, so any supertype of U cannot either.
What confuses me is that the compiler does generate an error when I change the signature from sortedCopy(U...) to sortedCopy(U[]). I suppose this has to do with the fact that, in the second case, U is present at runtime as the type of the array, whereas in the first case, it is not. But I still don't understand why that would make the method call in question valid, because:
As I understand it, a varargs parameter of a generic type is converted to an Object[] if the values passed to the method as vararg arguments are of a generic and therefore non-reifiable type, which, if I understand correctly, is the case in the above code because U from sortedCopy(U...) is non-reifiable. But even then, why does the compiler not realize that Object does not extend Comparable<? super Object>?
The previous argument talks about runtime types. However, we're still pre-compilation, so speculations about runtime-types should not even be relevant in this context, because, while U might not be present anymore at runtime, the compiler still knows it and should be able to check whether the equality constraints are fulfilled, regardless of whether the method parameter is an array or a vararg.
So why does the line in question from the above code sample still compile?
Beside that, I would also be grateful for feedback in case the #SafeVarargs annotation of the method sortedCopy(Comparator<? super U>, U...) is inappropriate. I believe it is, but I'm not confident about it.
Varargs can be a bit sneaky. What I'm seeing in my IDE is that it's regarding sortedCopy(U... values) as being a recursive method, meaning that it's not selecting the overloaded argument with a Comparator as its first argument.
If you change this from varargs to array parameters, and pass in an int[], you'd get the compilation failures that you would expect.
Error:(12, 16) no suitable method found for sortedCopy(java.util.Comparator<T>,U[])
method Foo.<U>sortedCopy(java.util.Comparator<? super U>,U[]) is not applicable
(inferred type does not conform to upper bound(s)
inferred: U
upper bound(s): java.lang.Comparable<? super U>,U,java.lang.Object)
method Foo.<U>sortedCopy(U[]) is not applicable
(cannot infer type-variable(s) U
(actual and formal argument lists differ in length))
Error:(18, 47) no suitable method found for sortedCopy(java.util.Comparator<T>,int[])
method Foo.<U>sortedCopy(java.util.Comparator<? super U>,U[]) is not applicable
(inference variable U has incompatible bounds
equality constraints: int
upper bounds: java.lang.Object)
method Foo.<U>sortedCopy(U[]) is not applicable
(cannot infer type-variable(s) U
(actual and formal argument lists differ in length))
If you pass in an Integer[], or if you pass in only the vararg form, you get only the first error.
There are rules around picking the most specific method available to the lexer. Specifically, you're getting burned by this rule:
A type S is more specific than a type T for any expression if S <: T.
In more detail:
The subtypes of a type T are all types U such that T is a supertype of U, and the null type.
From this, we infer that, because the generic is not well-bound, it is accepting a Comparable as part of your vararg. This is why my IDE picks it up as a recursive method, and why when I run it I get a StackOverflowError.
This issue actually goes away if you properly bound the generic to <U extends Comparable<U>> to ensure that it doesn't pick up anything you can't realistically sort on...
public static <U extends Comparable<U>> Object[] sortedCopy(Comparator<? super U> comparator, U... values) {
U[] copy = Arrays.copyOf(values, values.length);
Arrays.sort(copy, comparator);
return copy;
}
public static <U extends Comparable<U>> Object[] sortedCopy(U... values) {
return sortedCopy(Comparator.naturalOrder(), values);
}
...with the caveat that you might now have heap pollution, and it'd be simpler and more concise to introduce a fixed-arity method instead.
it would seem to me the function is calling itself in the scenario that cocerns to you.
in the second method, you can replace U with Object and everything fits there, since it is a varargs.
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.
While studying up on Java8 Streams, I came across the following code snippet:
Predicate<? super String> predicate = s -> s.startsWith("g");
Since the generic parameter is a lower bound, I figured this would not compile. The way I see it, if an Object is a supertype to a String, then passing in an Object type should break it, since Object does not have a startsWith() function. However, I was surprised to see it work without any problems.
Further yet, when I tweaked the predicate to take an upper bound:
<? extends String>,
it would not compile.
I thought I understood the meaning of upper and lower bounds, but obviously, I am missing something. Can anyone help explain why the lower bound works with this lambda?
Lambda argument type is exact, it cannot be ? super or ? extends. This is covered by JLS 15.27.3. Type of a Lambda Expression. It introduces the ground target type concept (which is basically the lambda type). Among other things it's stated that:
If T is a wildcard-parameterized functional interface type and the lambda expression is implicitly typed, then the ground target type is the non-wildcard parameterization (§9.9) of T.
Emphasis mine. So essentially when you write
Predicate<? super String> predicate = s -> s.startsWith("g");
Your lambda type is Predicate<String>. It's the same as:
Predicate<? super String> predicate = (Predicate<String>)(s -> s.startsWith("g"));
Or even
Predicate<String> pred = (Predicate<String>)(s -> s.startsWith("g"));
Predicate<? super String> predicate = pred;
Given the fact that lambdas type arguments are concrete, after that normal type conversion rules apply: Predicate<String> is a Predicate<? super String>, or Predicate<? extends String>. So both Predicate<? super String> and Predicate<? extends String> should compile. And both actually work for me on javac 8u25, 8u45, 8u71 as well as ecj 3.11.1.
I just tested it, the assignment itself compiles. What changes is whether you can actually call predicate.test().
Let's take a step back and use a placeholder GenericClass<T> for explanation. For type arguments, Foo extends Bar and Bar extends Baz.
Extends:
When you declare a GenericClass<? extends Bar>, you are saying "I don't know what its generic type argument actually is, but it's a subclass of Bar." The actual instance will always have a non-wildcard type argument, but in this part of the code you don't know what the value of it is. Now consider what that means for method invocations.
You know what you've actually got is either a GenericClass<Foo> or a GenericClass<Bar>. Consider a method that returns T. In the former case, its return type is Foo. In the latter, Bar. Either way, it's a subtype of Bar and is safe to assign to a Bar variable.
Consider a method that has a T parameter. If it's a GenericClass<Foo>, then passing it a Bar is an error - Bar is not a subtype of Foo.
So, with an upper bound you can use generic return values, but not generic method parameters.
Super:
When you declare a GenericClass<? super Bar>, you are saying "I don't know what its generic type argument actually is, but it's a superclass of Bar." Now consider what that means for method invocations.
You know what you've actually got is either a GenericClass<Bar> or a GenericClass<Baz>. Consider a method that returns T. In the former case, it returns Bar. In the latter, Baz. If it returns a Baz, then assigning that value to a Bar variable is an error. You don't know which it is, so you can't safely assume anything here.
Consider a method that has a T parameter. If it's a GenericClass<Bar>, then passing it a Bar is legal. If it's a GenericClass<Baz>, then passing it a Bar is still legal because Bar is a subtype of Baz.
So, with a lower bound you can use generic method parameters, but not generic return values.
In summary: <? extends T> means you can use generic return values but not parameters. <? super T> means you can use generic parameters but not return values. Predicate.test() has a generic parameter, so you need super.
Another thing to consider: The bounds stated by a wildcard are about the actual type argument of the object. Their consequences on the types that you can use with that object are the opposite. An upper bound wildcard (extends) is a lower bound on the types of variables you can assign return values to. A lower bound wildcard (super) is an upper bound on the types you can pass in as parameters. predicate.test(new Object()) will not compile because, with a lower bound of String, it will only accept subclasses of String.
More explanations: Guidelines for Wildcard Use.
Consider the following code:
List<? extends Integer> lst= new ArraList<Integer>();
lst.add(5);//Compile error
lst.get(5);//OK
In the second string we have compile error, because we must guaranted have method add(int) in all potencial subtypes of List<? extends Integer> and compiler know that its null only, third string returns unknow type and compiler cast him to Object, isnt it?
PECS. Producer extends, Consumer super.
List<? super Integer> lst= new ArrayList<Integer>();
lst.add(5);// No Compile error
The list is a consumer now, you put objects into it...
Also this
lst.get(5);
Is a different cake... You provide the Integer index of which you want to get... (Not to mention what Sotirios mentioned: the return type will be Object in this case. Also, in this role, the list is a provider...)
Once you have a List<? extends Integer>, the compiler doesn't know whether it's Integer or a subtype. The compiler can't ensure the type safety of adding anything except null (really, passing anything to a method taking a generic type parameter, including the add method), so it disallows it. This occurs despite the fact that Integer is final and no subclasses are allowed.
For the get method, the compiler knows that the return type is some kind of Integer, so it allows the call and places an implicit cast to Integer.
You cannot add anything except null to a List bounded by a wildcard because you never know the underlying type.
List<? extends Integer> lst= new ArrayList<Integer>();
lst.add(5); // Compile error
lst.get(5); // 5 is just the index
You can however get an element because you know it must be an Integer (in this case).
It's hard to explain with Integer because it's a class that cannot be extended. But take this
public class Foo {}
public class Bar extends Foo {}
public class Zoop extends Foo {}
What could you add to
List<? extends Foo> fooList = new ArrayList<Zoop>(); // could come from a method
?
The list is declared as ? extends Foo even though the runtime object's generic type is Zoop. The compiler therefore cannot let you add anything. But you are guaranteed to be operating on Foo objects, so you can retrieve them fine.
Why is the following legal when String & Integer are not super classes of Object ?
List<? super Object> mylist = new ArrayList<Object>();
mylist.add("Java"); // no compile error
mylist.add(2);
I'm aware that wild card guidelines use lower bounded wild cards and super for 'out' variables but it seems that Object doesn't function as a 'lower bound' in this case.
Also is this the only way to allow addition of any type into a list ?
It's really simple. Remember that in Java, an instance of a subtype is also an instance of its supertypes.
Look at the signature of add
public boolean add(E e)
That means whatever you pass something whose type is E or any subtype of E.
You have a List<? super Object>. So you can pass to myList.add() anything whose type is ? super Object (an unknown type which could be Object or supertype thereof) or any subtype thereof.
Is Integer a subtype of all types contained by ? super Object? Of course. Integer is a subtype of Object, which is a subtype of all types contained by ? super Object (of course, in this case, only Object satisfies this).
You're confusing the type parameter with the things you can pass to methods. The type argument of List<? super Object> is an unknown type that is a supertype of Object, so Integer or String cannot be the actual type parameter. In fact, in this case the only valid actual type argument would be Object. But what you're asking when you pass something to the method is, is the thing I'm passing a subtype? And the answer is yes.
I agree that it's confusing, but here's what's happening.
In this line of code:
List<? super Object> mylist...
You're saying that myList is a List, where each element can be of a type that is Object or a superclass of Object. However, you're only declaring the type of myList here.
What the wildcard does is restricts your implementation of myList.
Then, you do this:
List<? super Object> mylist = new ArrayList<Object>();
Now what you're doing is instantiating an ArrayList<Object>. Your lower bound wildcard is used to check that this is valid. It is valid, because Object matches ? super Object. At this point, you have a List<Object> and your ensuing method calls are permitted.
It's because Object is a superclass for Integer and String. You're interpreting the generic relationship the other way around.
Edit
Think about this situation:
List<? extends myClass> listOfMyClass = new ArrayList<Object>();
In this case, you'll end up with a list of Object type elements but that have to respect the restriction added by the declaration of the listOfMyClass list.
You'll be able to add any object that belongs to the myClass hierarchy to the list. The ArrayList that's implementing the List interface will hold (and return) Object type elements when requested.
Of course, you can define this:
List<? extends myClass> listOfMyClass = new ArrayList<mySuperClass>();
As you might now, the ArrayList must contain objects with the same type or a supertype of myClass and, in this case, that's the mySuperClass. This list will return mySuperClass objects qhen requested.
Taking ClassX as a class that does not belong to the mySuperClass hierarchy, the following line won't compile:
List<? extends myClass> listOfMyClass = new ArrayList<ClassX>();
That's because ClassX is not a superclass of myClass.