Trouble Understanding Comparable<T> cast - java

I just wrote a method that takes two arguments: 1. An array list of any type that extends Number, and 2. a number of the same type. This method should return an array list of all numbers less than the second argument.
My class is called Quiz3FinalQuestion<T extends Comparable>>
My method I wrote looks like this,
public static <T extends Number> ArrayList<T> lessThan(ArrayList<T> lst, T number) {
ArrayList<T> arLst = new ArrayList<>();
for (T obj: lst) {
if (((Comparable<T>) obj).compareTo(number) < 0)
arLst.add(obj);
}
return arLst;
}
It works as expected, but if I didn't have the Java pre-compiler telling me to cast obj to type Comparable, this wouldn't have run. I'm assuming that the number parameter gets cast in the Comparable version of compareTo. So when I add an obj to my arLst, the object should get cast back into type T, right?
Also, are there any simpler ways to compare wrapper class objects of unknown type T?

You can enforce that T also extends Comparable<? super T>:1
public static <T extends Number & Comparable<? super T>>
ArrayList<T> lessThan(ArrayList<T> lst, T number) {
...
}
Then you can remove the cast.
1. See e.g. Explanation of generic <T extends Comparable<? super T>> in collection.sort/ comparable code? for why we don't just use Comparable<T>.

Related

Java Generics - Class a Subclass of itself?

I'm currently reading Java Generics, and I am a bit stuck when it comes to Wildcards.
I have been given this method from the Collections class:
public void <T> copy(List<? super T> dest, List<? extends T> src) {
for(int i = 0; i < src.size(); i++) {
dest.set(i, src.get(i));
}
}
I have then been told that it is possible to call the method like this:
List<Object> objs = new ArrayList<Object>();
List<Integer> ints = new ArrayList<Integer>();
Collections.copy(objs, ints);
As the type parameter has been left to the compiler to determine, the book says the compiler chooses the type parameter to be Integer.
But how is that possible?
If it were taken to be Integer, this would mean that in the method declaration -
List<? extends T> would translate to List<Integer extends Integer>.
Is this a mistake, or are there different rules when regarding Generics? I have googled around and the majority of results say that a class cannot be a subclass of itself.
No, it's not an error.
? extends Integer means: any class that is or extends Integer (or implements Integer, if Integer was an interface).
The same goes for ? super Integer, which means: any class that is Integer or is a superclass or super-interface of Integer.

Java Generics and templates

I have the following Java class definition:
import java.util.*;
public class Test {
static public void copyTo(Iterator<? extends Number> it, List<? extends Number> out) {
while(it.hasNext())
out.add(it.next());
}
public static void main(String[] args) {
List<Integer> in = new ArrayList<Integer>();
for (int i = 1; i <= 3; i++) {
in.add(i);
}
Iterator<Integer> it = in.iterator();
List<Number> out = new ArrayList<Number>();
copyTo(it, out);
System.out.println(out.size());
}
}
That's it, I define the method copyTo using wildcards in Java. I define List<Number> out but Iterator<Integer> it. My thinking is I can define the iterator as Iterator<? extends Number> and that would type match. However that's not the case:
Test.java:13: error: no suitable method found for add(Number)
out.add(it.next());
^
method List.add(int,CAP#1) is not applicable
(actual and formal argument lists differ in length)
method List.add(CAP#1) is not applicable
(actual argument Number cannot be converted to CAP#1 by method invocation conversion)
method Collection.add(CAP#1) is not applicable
(actual argument Number cannot be converted to CAP#1 by method invocation conversion)
where CAP#1 is a fresh type-variable:
CAP#1 extends Number from capture of ? extends Number
1 error
So I went ahead and I defined yet another definition for the copyTo method:
static public void copyTo(Iterator<? super Integer> it, List<? super Integer> out) {
while(it.hasNext())
out.add(it.next());
}
It doesn't work either. What would be the correct say of using wildcards in this case?
First of all you want to impose a constraint by adding a type variable to the method itself since by using wildcards you can't impose a constraint between the two arguments, then you must thing about variance of the types involved in your method:
you want as an input an Iterator<X> where X is at least the type of the numeric type you want to copy (or a subtype)
you want as output a List where Y is at most the type of the numeric type (or a super type)
These constraints are different and must be expressed differently:
static public <T> void copyTo(Iterator<? extends T> it, List<? super T> out) {
while(it.hasNext())
out.add(it.next());
}
Which is basically "I accept an Iterator of T or a subtype of T and I output to a List of T or a supertype of T"
If a method signature involves two or more wildcards, and the logic of your method requires them to be the same, you need to use a generic type parameter instead of wildcards.
static public <T extends Number> void copyTo(Iterator<? extends T> it, List<? super T> out) {
while(it.hasNext())
out.add(it.next());
}
Here I have used PECS (producer extends, consumer super). out is consuming Ts (so super), whereas the iterator is producing Ts, so extends.
EDIT
As #Cinnam correctly points out in the comments, you can get away with
static void copyTo(Iterator<? extends Integer> it, List<? super Integer> out)
These signatures are effectively equivalent because Integer is final, so any class that is a super class of some class extending Integer must be a super class of Integer.
However, the two signatures are not equivalent as far as the compiler is concerned. You can test this by trying
static <T extends Number> void copyTo1(Iterator<? extends T> it, List<? super T> out) {
copyTo2(it, out); // doesn't compile
}
static void copyTo2(Iterator<? extends Integer> it, List<? super Integer> out) {
copyTo1(it, out);
}
This does not compile, showing that as far as the compiler is concerned, the version with the type parameter is more general.

Difference in Generic Signature in Java

We have made in a tutorial an example with the following signture (as part of an interface)
<T> List<Comparable<T>> sort(Collection<Comparable<T>> c, boolean ascending);
We have found it nearly impossible to implement that method without warnings:
public <T> List<Comparable<T>> sort(Collection<Comparable<T>> c, boolean ascending) {
List<T> list = new ArrayList<T>();
Collections.sort(list);
return list;
}
The error in the line Collections.sort(list) we get is:
Bound mismatch: The generic method sort(List<T>) of type Collections is not
applicable for the arguments (List<T>). The inferred type T is not a valid
substitute for the bounded parameter <T extends Comparable<? super T>>
However, it works for the following signature:
<T extends Comparable<T>> List<T> sort(Collection<T> c, boolean ascending);
With that signature, the code above (implementation of sort) just works as expected. I would like to know what is the reason for that.
A list of Comparable<T>s is a list of objects which are comparable with Ts. One could not say if these objects themselves are Ts. Thus it's impossible to compare two elements with each other.
Ts, which happen to be comparable with other Ts, can be compared with each other. And so sorting a list of such Ts is possible.
Collections.sort expects a List<T extends Comparable<? super T>>, i.e. the compiler needs to be able to tell that the element type T of the list it is sorting extends Comparable<E> where E is T, a superclass of T or an interface implemented by T. Your first signature with public <T> List<Comparable<T>> sort doesn't enforce this, so you can't Collections.sort a List<T>. You could make it work by saying
List<Comparable<T>> list = new ArrayList<Comparable<T>>();
to match the type that your sort method returns, but the problem with this is that it's rather inflexible - it can only sort a Collection<Comparable<Foo>>, not a Collection<Bar> where Bar implements Comparable<Foo>. The most flexible approach would be to stick with the new ArrayList<T>() but use a signature like
<T extends Comparable<? super T>> List<T> sort(Collection<T> c, boolean ascending);
which places the minimum restriction on T to make the sort valid - it would work with Bar extends Foo implements Comparable<Foo>, which your second signature doesn't allow (that would require Bar implements Comparable<Bar>).

What is static <T> List<T> methodName (List<? super T> input)

I have the following code but i am confused with all the generics.
public static <T> List<T> backwards (List<? super T> input) {
List<T> output = new ArrayList<T>();
return output;
}
My understanding is that I have a public method named backwards which creates an arraylist implementing the List interface and returning the arraylist. My question is what actually I am saying to the compiler with the following part......
static <T> List<T> backwards (List<? super T> input)
You are saying to the compiler:
<T>
"I'm declaring an arbitrary type T for this method, which can be anything (non-primitive) for each call of the method."
List<T>
"This method will return a List containing elements of that type T."
List<? super T> input
"This method will take a parameter called input, which is a List containing elements of type T, or any super-type of T. For example, if T is Integer, input could be a List<Integer>, List<Number>, or List<Object>."
In addition to Paul's answer, that probably makes it more clear, if you have some classes that in its definition declares Generic parameter, you can write generic method like
public class SampleClass<T>{
public static List<T> backwards (List<? super T> input)
}
otherwise, if your class doesn't declare generic parameter(or you want to define extra parameters), you should define your method in this way:
public class SampleClass{
public static <T> List<T> backwards (List<? super T> input){...}
}
This is how you declare Generic Methods. Please read the following part and it will give you everything you need.
http://docs.oracle.com/javase/tutorial/extra/generics/methods.html

java Generics Wildcard

I have a question on the use of wildcards in Java's generic types: what is the basic difference between List<? extends Set> and List<T extends Set>? When would I use either?
Two reasons:
To avoid unnecessary casts:
You have to use the T variant for cases like this:
public <T extends Set> T firstOf(List<T> l) {
return l.get(0);
}
With ? this would become:
public Set firstOf2(List<? extends Set> l) {
return l.get(0);
}
...which doesn't give the same amount of information to the caller of the firstOf method. The first version allows the caller to do this:
SubSet first = firstOf(listOfSubSet);
while with the second version, you are forced to use a cast to make it compile:
SubSet first = (SubSet)firstOf(listOfSubSet);
To enforce matching argument types:
public <T extends Set> boolean compareSets(List<T> a, List<T> b) {
boolean same = true;
for(T at : a) {
for (T bt: b) {
same &= at.equals(bt);
}
}
return same;
}
There is no direct equivalent using ? instead of T for this. Note that due to Java's single-dispatch, in the above version, the compiler will call at's equals(T) method which may well differ from at's equals(Set) or equals(Object) method.
The difference here is that in the second version, you have a type variable T that refers to the specific subtype of Set that the List contains. You need this in cases where you need to ensure that something else is the same type as the type contained in the list. A couple simple examples:
// want to ensure that the method returns the same type contained in the list
public <T extends Set> T something(List<T> list) {
...
}
// want to ensure both lists contain the exact same type
public <T extends Set> List<T> somethingElse(List<T> first, List<T> second) {
...
}
Simple rule: Use a type variable T extends Foo in your method signature if the same type is necessary in two places. Method parameters are each one place and the method return type is another place. Use the wildcard ? extends Foo if you just need to ensure you're dealing with "something that is a Foo" in one place.
Aside: don't use the raw type Set.
You use List<? extends Set> when you declare a varlable. For example:
List<? extends Number> l = new ArrayList<Integer>();
List<T extends Number> can be used in class or methode declaration. This will allow you to write T instead of <? extends Number> later on in the function.
public <T extends Number> int addAll(List<T> list) {
int result = 0;
for (T t : list) {
result += t.intValue();
}
return result;
}
We use wildcards to specify that the type element matches anything. The ? stands for unknown type.
List<? extends Set> is an example of a bounded wildcard and that states that the list can accept any subtype of a Set (e.g. HashSet)
List<T extends Set>, on the other hand is, allows T to be bounded to a type that extends Set.
I use wildcards when I need a collection of data irrespective pf it's exact type.
A wildcard type G<? extends A> is a super type of any G<Ai> where Ai is a subtype of A
In another word, G<? extends A> is the union type of G<A0>, ..., G<An>.

Categories

Resources