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
Related
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.
I am trying to sort a list of type A named BinOrder in class B according to Class A's int r.
However i am receiving this error for the line Collections.sort(BinOrder);
The method sort(List<T>) in the type Collections is not applicable for the arguments (ArrayList<A>)
Class A:
public class A{
int s;
int r;
public A(int si, int ri) {
s=si;
r= ri;
}
}
Class B:
import java.util.ArrayList;
import java.util.Collections;
public class B implements Comparable<A> {
public Iterator<A> randomMethodName(int a) {
ArrayList<A> BinOrder = new ArrayList<A>();
A a = new A(1,3)
A a2 = new A(1,4)
BinOrder.add(a);
BinOrder.add(a2);
}
// sort array in increasing order of r
Collections.sort(BinOrder);
return BinOrder;
}
#Override
public int compareTo(A list) {
return null;
}
}
To be able to use the single-argument version of Collection.sort() on an ArrayList of A, A should implement the Comparable interface:
public class A implements Comparable<A> {
...
#Override
int compareTo(A rhs) {
...
}
}
Here's the signature of Collections.sort :
public static <T extends Comparable<? super T>> void sort(List<T> list)
A must implement Comparable for this method.
You try to pass BinOrder to this method, when BinOrder is of type ArrayList<A>, but since A does not implement Comparable<A>, it doesn't fit the signature of the method.
Either change A to implement Comparable, or use the sort method that accepts a Comparator :
public static <T> void sort(List<T> list, Comparator<? super T> c)
I'm trying to make it so that my class is only constrained to the upperbound Number. However, when I try to do a toString() method to get the smallest and largest values, I get the following message:
The method largest(ArrayList<T extends Comparable<T>>) in the type MyList is not applicable for the arguments (ArrayList<T extends Number>)
package p07;
import java.util.ArrayList;
public class MyList<T extends Number>
{
private ArrayList<T> l;
public MyList(ArrayList<T> l)
{
this.l=l;
}
public void add(T x)
{
l.add(x);
}
public static <T extends Comparable<T> > T smallest(ArrayList<T> l)
{
T lowest=l.get(0);
for(T index:l)
{
if(index.compareTo(lowest)<0)
{
lowest=index;
}
}
return lowest;
}
public static <T extends Comparable<T> > T largest(ArrayList<T> l)
{
T largest=l.get(0);
for(T index:l)
{
if(index.compareTo(largest)>0)
{
largest=index;
}
}
return largest;
}
public final String toString()
{
String str;
str="\nThe list is: ";
str+="\n"+l.toString();
str+="\nThe largest value is "+MyList.largest(l);
str+="\nThe smallest value is "+MyList.smallest(l);
return str;
}
}
Is there any way for me to keep my class constrained to the upper bound of the Numbers class without having to implement the Comparable interface for the entire class? I have a feeling the error is occurring because my methods are static, but I'm not sure. I only want to use Comparable for
smallest()
and
largest()
It doesn't make sense for your toString method to depend on T having a bound that your class does not enforce.
Something like that could be done with a static method.
static <T extends Number & Comparable<? super T>> String getString(MyList<T> list) {
....
}
This should work --
public class MyList< T extends Number & Comparable<? super T> >
public static <T extends Comparable<? super T> > T smallest(ArrayList<T> l)
public static <T extends Comparable<? super T> > T largest(ArrayList<T> l)
You may also remove all the ? super part; it should work fine without wildcards.
I do have a problem in the last line of execution though I pass derived data type. Not able to figure out. Thanks.
public class ExtendedDHvalue extends DHvalue {}
public class DerivedHolderUnique<T> {
private Class<? extends T> a;
public DerivedHolderUnique(Class<? extends T> a){
this.a = a;
}
public Class<? extends T> getA() {
return a;
}
public void setA(Class<? extends T> a) {
this.a = a;
}
public static void main(String[] args){
ExtendedDHvalue eDV = new ExtendedDHvalue();
DerivedHolderUnique<DHvalue> dhu = new DerivedHolderUnique<DHvalue>(eDV);
}
}
Your constructor takes parameter of type Class<? extends T> and you're passing an argument that extends T to it. You should change those two lines to:
Class<ExtendedDHvalue> eDV = ExtendedDHvalue.class;
DerivedHolderUnique<DHvalue> dhu = new DerivedHolderUnique<DHvalue>(eDV);
Your DerivedHolderUnique constructor requires a Class instance, not
an ExtendedDHvalue instance. This is what causes the compile-time error.
You should think if you actually want
private Class<? extends T> a;
or
private T a;
and then rework your DerivedHolderUnique class accordingly.
I tend to think you want the latter but you should know better.
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.