Consider the following code:
public final class Algorithm {
public static <T extends Comparable<? super T>>
T max(List<? extends T> list, int begin, int end)
{
// ...
}
}
Is the List<? extends T> list parameter declaration equal to List<? extends Comparable<? super T>> list?
There is a very slight difference.
List<? extends T> means
a List of objects of an unknown type that is either T or a subclsss of T
List<? extends Comparable<? super T>> means
a List of objects of an unknown type that is either Comparable<? super T> or an implementation of Comparable<? super T>.
Let's consider this class hierarchy: A and B are unrelated classes that both implement Comparable<A> and are both final. Yes, I know this situation is contrived.
If, from the return value, T is inferred to be A, you can only pass a List<A> to a parameter of type List<? extends T>. However, you can pass a List<A>, as well a List<B> to a parameter of type List<? extends Comparable<? super T>>.
Here is an example demonstrating my point:
public static void main(String[] args) {
List<A> aList = Collections.singletonList(new A());
List<B> bList = Collections.singletonList(new B());
A a = f(aList);
A b = f(bList); // doesn't compile
A c = g(bList);
A d = g(bList);
}
public static <T extends Comparable<? super T>> T f(List<? extends T> list) {
return null;
}
public static <T extends Comparable<? super T>> T g(List<? extends Comparable<? super T>> list) {
return null;
}
final class A implements Comparable<A> {
#Override
public int compareTo(A o) {
return 0;
}
}
final class B implements Comparable<A> {
#Override
public int compareTo(A o) {
return 0;
}
}
In reality though, very rarely do things like class B implements Comparable<A> happen, so for the most part, the two types in question are the same.
Related
class A<T extends Comparable<? super T>> {
Supplier<T> supp;
A(Supplier<T> supp) {
this.supp = supp;
}
static <T extends Comparable<? super T>> A<T> of(Supplier<T> supp) {
return new A<T>(supplier);
}
<U> A<U> map(Function<? super T, ? extends U> mapper) {
return A.of(() -> mapper.apply(this.supp.get()));
}
}
When I compile, I get error saying:
type argument U is not within bounds of type-variable T
where U,T are type-variables:
U extends Object declared in method <U>map(Function<? super T,? extends U>)
T extends Comparable<? super T> declared in class A
I feel that I need to make U in mapper extend something, but I am not really sure how, I have tried U extends Comparable, etc. but they don't work.
I'm sorry if this has been asked somewhere else, but my search engine skills are failing me.
I thought I had an understanding on generics, but this is another thing that's throwing a wrench in my thought process. Why is T extends Comparable valid for class B which extends A for arrays and B objects, but not List
public class Example {
public static void main(String[] args) {
B[] values = new B[1];
sort(values); // this is OK
sort(new B()); // this is OK
List<B> b = new ArrayList<>();
sort(b); // not allowed
}
public static <T extends Comparable<T>> void sort(T[] a) {
}
public static <T extends Comparable<T>> void sort(T a) {
}
public static <T extends Comparable<T>> void sort(List<T> a) {
}
}
class A implements Comparable<A> {
#Override
public int compareTo(A a) {
return 0;
}
}
class B extends A {
}
Because List<B> is not a subtype of List<A> and you're using A's compareTo implementation.
So you need to add ? super below
public static <T extends Comparable<? super T>> void sort(List<T> a) {
}
By taking T to be B, you get B extends Comparable<? super B>
This is valid since
B extends Comparable<A> and
A super B
Can I declare the following in Java?
public class NewIterator<E extends Comparable<? super E>> implements Iterator<E> {
NewIterator(Iterator<? extends E & Comparable<? super E>> iterator){
...
}
I am getting an error saying
Multiple markers at this line
- Incorrect number of arguments for type Iterator<E>; it cannot be parameterized with arguments <? extends E, Comparable<? super E>>
- Syntax error on token ",", ; expected
- Syntax error on token "&", , expected
- Syntax error on token ")", ; expected
By defining your class as
class NewIterator<E extends Comparable<? super E>> implements Iterator<E> {
you say that E has to implement Comparable<? super E>.
Now in the constructor you try to repeat that and allow subtypes of E.
NewIterator(Iterator<? extends E & Comparable<? super E>> iterator){
...
}
If you do just
public NewIterator(Iterator<? extends E> iterator) {
}
You should get what you want because E already defines that it's a type that implements the comparable interface.
Example
class IntegerNumber {}
class PositiveNumber extends IntegerNumber implements Comparable<IntegerNumber> {}
class OddPositiveNumber extends PositiveNumber {}
private NewIterator<PositiveNumber> newIterator;
void foo() {
Iterator<PositiveNumber> iterator = createIteratorFrom(
new PositiveNumber(1),
new OddPositiveNumber(7)
);
this.newIterator = new NewIterator(iterator);
}
If you use PositiveNumber in NewIterator<E extends Comparable<? super E>> you can replace E by PositiveNumber. So your constructor accepts Iterator<? extends PositiveNumber>. You can now create an iterator over any subclass of PositiveNumber but since that class inherits from PositiveNumber it must also inherit the Comparable<IntegerNumber> interface.
I understand that
List<? extends T>
allows for the list to be any sub-type of T (or T itself), and that
List<T>
only allows for lists of the type T. However, take a look at the following method signature:
public static <T extends Object & Comparable<? super T>> T findMax(List<? extends T> myList, int begin, int end){
And the following classes:
public class ClassA{
}
public class ClassB extends ClassA implements Comparable<ClassA>{
public int compareTo(ClassA s){
//do comparison
}
}
public class ClassC extends ClassB{
}
Let's assume T is ClassB, and I want to pass a sub-type of T (ClassC) for my list:
public static void main(String[] args){
List<ClassC> myC = new ArrayList<ClassC>();
ClassC a = findMax(myC, 2, 3);
}
In this case, how does java infer that T is ClassB, and not ClassC? And if it isn't able to infer ClassB (and actually infers ClassC instead) then wouldn't the following method signature (without the "List") be equivalent?
public static <T extends Object & Comparable<? super T>> T findMax(List<T> myList, int begin, int end){
Thanks,
Jack
Firstly, ? extends Object adds no value, because everything extends Object, so these two methods are equivalent:
public static <T extends Object & Comparable<? super T>> T findMax(List<T> myList, int begin, int end)
public static <T extends Comparable<? super T>> T findMax(List<T> myList, int begin, int end)
Having made that simplification, your question is basically are these equivalent:
public static <T extends Comparable<? super T>> T findMax(List<T> myList, int begin, int end)
public static <T extends Comparable<? super T>> T findMax(List<? extends T> myList, int begin, int end)
They are (not* the same.
The reason is, with the second method, you can pass in a List with a type that's a subclass of the returned type, whereas in the first method the List's type must be the same type as the returned type.
The way type inference works, T is always going to be inferred to the type param of the list you call the function with, so the additional liberty given by <? extends T> will never be used. You can write List<T> with the same result.
Answering to the subtler point raised by bohemian, the inferred type will be assignable to any supertype as well, so once again no flexibility is added by the longer signature.
how does java infer that T is ClassB, and not ClassC?
I don't follow you here. Generics is a compile type technique.
The erasure of public static <T extends Object & Comparable<? super T>> T findMax(List<? extends T> myList, int begin, int end) is to Object i.e.
this compiles to public static Object findMax(List myList, int begin, int end)
When you instantiate the list List<ClassC> myC = new ArrayList<ClassC>(); and pass it to the method, the compiler ensures type safety, essentially that the pass list complies with the declaration. In this case Class C implements a Comparable and you could return back Class B since the compiler would accept it.
Generics do not exist at runtime.
Update after comment:
This public static <T extends Object & Comparable<? super T>> T findMax(List<? extends T> myList, int begin, int end)
is not the same as:
public static <T extends Object & Comparable<? super T>> T findMax(List<T> myList, int begin, int end)
This is not about type inference. The compiler would make the same type inference here either it was T or ? extends T in this specific case.
The difference lies in the contract. The public static <T extends Object & Comparable<? super T>> T findMax(List<? extends T> myList, int begin, int end) declares a method that guarantees not to modify your collection (at least not a way that would corrupt it).
The List<? extends T> myList essentially makes list a read-only list inside the body of findMax which can not add any instance in the list (either T or subtype of T) except null.
If you declared List<T> myList then it is not a read-only list and one could add elements in your list e.g. inside findMax you could do: myList.add(myList.get(0)); This is not possible with the declaration of findMax as List<? extends T> myList
In Java, the Collections class contains the following method:
public static <T extends Object & Comparable<? super T>> T min(Collection<? extends T> c)
Its signature is well-known for its advanced use of generics,
so much that it is mentioned in the Java in a Nutshell book
and in the official Sun Generics Tutorial.
However, I could not find a convincing answer to the following question:
Why is the formal parameter of type Collection<? extends T>, rather
than Collection<T>? What's the added benefit?
Type inference is a tricky topic that I'll admit that I don't know that much about. However, examine this example:
public class ScratchPad {
private static class A implements Comparable<A> {
public int compareTo(A o) { return 0; }
}
private static class B extends A {}
private static class C extends B {}
public static void main(String[] args)
{
Collection<C> coll = null;
B b = Scratchpad.<B>min(coll);
}
public static <T extends Object & Comparable<? super T>> T min(Collection<? extends T> c) {
return null;
}
//public static <T extends Object & Comparable<? super T>> T min(Collection<T> c) {
// return null;
//}
}
Consider that the first signature of min() allows the call to compile whereas the second does not. This isn't a very practical example, since one must ask why I would be explicitly typing the method to <B>, but perhaps there is an implicit inference where B would be the inferred type.
One benefit of the ? is that it prohibits additions of items to the Collection
I think it actually doesn't give you anything more for this method, however its a good habit to get into when T is part of the class and not just a static method.
They are including it here so it can become the new convention where every generic should be extended by ?
A class of T should follow PECS: What is PECS (Producer Extends Consumer Super)?
But a static method doesn't need to (at least the parameters, the return value should always)
This is to support a legacy signature of the method in Java 1.4 ( and before ).
Prior to Java 5 the signature for these methods was
public static Object min ( Collection c );
With multiple bounds the erasure rules make the first bound the raw type of the method, so without Object & the signature would be
public static Comparable min ( Collection c );
and legacy code would break.
This is taken from O'Reilly's Java Generics and Collections book, chapter 3.6
Building on the comments I put on Mark's answer, if you have something like
class Play {
class A implements Comparable<A> {
#Override
public int compareTo(A o) {
return 0;
}
}
class B extends A {
}
class C extends A {
}
public static <T extends Object & Comparable<? super T>> T min(
Collection<? extends T> c) {
Iterator<? extends T> i = c.iterator();
T candidate = i.next();
while (i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) < 0)
candidate = next;
}
return candidate;
}
public static List<? extends A> getMixedList() {
Play p = new Play();
ArrayList<A> c = new ArrayList<A>();
c.add(p.new C());
c.add(p.new B());
return c;
}
public static void main(String[] args) {
ArrayList<A> c = new ArrayList<A>();
Collection<? extends A> coll = getMixedList();
A a = Play.min(coll);
}
}
It's clearer that min returns an object of type A (the actual signature is <A> A Play.min(Collection<? extends A> c) ). If you leave min(Collection<T>) without the extends part then Play.min(coll) will have the following signature <? extends A> ? extends A Play.min(Collection<? extends A> c) which isn't as clear.