Generic upperbound with List vs Array or Object - java

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

Java: misunderstanding generics and wildcards

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.

Whats wrong with this Collections.sort(List<T> lst) [duplicate]

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)

Trying to constrain to the upperbound of the Number class without implementing Comparable for the entire class

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.

Generic Class and passing derived data type

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.

Signature of Collections.min/max method

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.

Categories

Resources