Using generics in Comparable - java

I am trying to implement generics in Java using Comparable<T> interface.
public static <T> T[] sort(T[] a) {
//need to compare 2 elements of a
}
Let's say, I want to override the compareTo method for the above type T in the Comparable interface. I.e. I need to compare two elements of my type T, how will I do it? I don't know what my T type will be.

You need to set a type constraint on your method.
public static <T extends Comparable<? super T>> T[] sort (T[] a)
{
//need to compare 2 elements of a
}
This forces the type T to have the compareTo(T other) method. This means you can do the following in your method:
if (a[i].compareTo(a[j]) > 0) }
}

Try using <T extends Comparable<T>> and then compareTo

Old question but...
As jjnguy responded, you need to use:
public static <T extends Comparable<? super T>> T[] sort(T[] a) {
...
}
Consider the following:
public class A implements Comparable<A> {}
public class B extends A {}
The class B implicitly implements Comparable<A>, not Comparable<B>, hence your sort method could not be used on an array of B's if used Comparable<T> instead of Comparable<? super T>. To be more explicit:
public static <T extends Comparable<T>> T[] brokenSort(T[] a) {
...
}
would work just fine in the following case:
A[] data = new A[3];
...
data = brokenSort(A);
because in this case the type parameter T would be bound to A. The following would produce a compiler error:
B[] data = new B[3];
...
data = brokenSort(B);
because T cannot be bound to B since B does not implement Comparable<B>.

Related

Java Generic Comparator

public class arr<T>
{
class comp <T extends Comparable<T>> implements Comparator<T>
{
public int compare(T lObj,T rObj)
{
return lObj.compareTo(rObj);
}
}
ArrayList<T> list;
Comparator<T> comparator;
public arr()
{
list = new ArrayList<T>();
comparator = new comp();
}
public void add(T data)
{
list.add(data);
}
public int getLength()
{
return list.size();
}
public T get(int index)
{
return list.get(index);
}
public void sort()
{
list.sort(comparator);
}
}
Hello, I am trying to make the sort function work but have a problem.
In the arr constructor, if I write
comparator = new comp<T>();
it gives me an error saying
"type argument T#1 is not within bounds of type-variable T#2 comparator =
new comp<T>(); ^
where T#1,T#2 are type-variables:
T#1 extends Object declared in class arr
T#2 extends Comparable<T#2> declared in class arr.comp"
And if I take out the type and write like this
comparator = new comp;
then it does work but gives me a warning that says
warning: [rawtypes] found raw type: arr.comp
comparator = new comp();
I can see what it means by raw types. I am not specifying the type, but somehow it works and if I try to fix the warning by specifying the type then, it throws an error. Could you please help me figure it out? I know... I am a noob my code must be a pain in your eyes. I am playing with generic comparators and trying many things to get familiar. Thank you.
Your code is confusing you, because the T defined by comp is hiding the T defined by arr. For the explanation below, I'll call them Tcomp and Tarr.
Tcomp is required to extend Comparable, but Tarr isn't required to do so, which means that Tarr cannot be "mapped" to Tcomp.
To fix, change Tarr so it is also required to extend Comparable:
public class arr<T extends Comparable<T>>
On a side note:
You comp class is an inner class, but it doesn't use anything from the outer class, so it should be a static nested class:
static class comp<T extends Comparable<T>> implements Comparator<T>
Alternatively, leave comp as an inner class, and let it reuse the T from the outer class:
class arr<T extends Comparable<T>>
{
class comp implements Comparator<T>
But, since Java (8 or higher) comes with an implementation of Comparator for comparing Comparable objects, you should use it:
public class arr<T extends Comparable<T>>
{
ArrayList<T> list;
Comparator<T> comparator;
public arr()
{
list = new ArrayList<T>();
comparator = Comparator.naturalOrder();
}
// rest of code
}

How to check whether Java generic type is subclass of Comparator?

When I try to complete a task, there's one case need to be handled: throw exception of generic type of class is not comparable. Refer to the following code for the detail.
public class C <T>
{
public C()
{
// throw exception if T is not comparable
}
}
You can enforce the generic to be a subclass of Comparator like so:
public class C <T extends Comparator> {
public C(){
}
}
As you see in the below code, it would be a good idea to add another generic (here it is K), which you supply to Comparator, since the generic of Comparator will otherwise default to Object.
public class C <K, T extends Comparator<K>> {
public C(){
}
}
You generally use this in the form of T x K, where T is the generic, x is super or extends and K is the class/interface.
Comparator docs
You should make sure that the generic parameter T is a Comparableby writing:
public class C <T extends Comparable>
There are two ways:
1) Make it T extends Comparable, so you know it will always be.
2) In the constructor, pass Class < T > as a parameter, so you'll know at runtime what T is. (because it's erased)
Add a generic constraint, that is would be better since it will be handle it at compile time rather than throw an exception on runtime.
class C <T extends Comparable>
You should verify that your parameter T is Comparable.
public class C <T extends Comparable>
This is the same if you want a generic type implements some interface.
public class C <T implements <interface what you want> >
Or if you want that were a superclass of another one.
public class C <T super <class what you want> >
If you always want the type T to implement Comparable you can enforce this as follows.
public class C<T extends Comparable<? super T>> {
public C() {
}
}
This is better than throwing an exception at runtime. It will not even compile if someone tries to write new C<some non-Comparable type>(). Note that Comparable is a generic type, so it should not be used without type parameters; it should not simply be
public class C<T extends Comparable>
If the type T will not always implement Comparable, but you want a specific constructor that will only work for Comparable types, then the answer is that you can't do this with constructors, but you can do it with a static method.
public class C<T> {
public C() {
// Constructor that works with any T
}
public static <T extends Comparable<? super T>> C<T> getNew() {
C<T> c = new C<>();
// Do stuff that depends on T being Comparable
return c;
}
}

How to understand the Java doc syntax

For example, I see
static <T extends Comparable<? super T>> void parallelSort(T[] a)
Sorts the specified array of objects into
ascending order, according to the natural ordering of its elements.
So I get this is a static method and what it does, but what does <T extends Comparable<? super T>> mean (return type, but what is it, is it the same way I would write in the code, or a syntax used in the documentation to show several possible values)
<T extends Comparable<? super T>> is not the return type. void is the return type. A generic specification before the return type is for type inference.
The argument (T[]) type is inferred from the call, and must be something that extends Comparable<? super T>
Suppose you have a class defined:
class Foo extends Comparable<Foo> { ... }
That means:
Foo[] fooArray = ...
parallelSort(fooArray);
is legal, and inside the parallelSort() method, T will be of type Foo (which implements the Comparable interface)
Here's a simple, less complicated example without the recursive type. In this case, it says it returns a list of the inferred type:
public static <T> <List<T>> myMethod(T arg) {
List<T> list = new ArrayList<T>();
list.add(arg);
return list;
}
The type is inferred from the argument:
List<String> list = myMethod("hi");

Nested compare() call - possible to change generics information?

private interface Internal {
<T extends Comparable<? super T>> void compare(final T left, T right);
}
private final Internal internal = ...;
public <T> void compare(final Comparable<T> left, final Comparable<T> right) {
this.internal.compare(left, right);
}
I'm seeing a compiler error on .compare(left, right):
Bound mismatch: The generic method compare(T, T) of type
MyClass.Internal is not applicable for the arguments
(Comparable<T>, Comparable<T>). The inferred type Comparable<T> is not a valid
substitute for the bounded parameter <T extends Comparable<? super T>>
Is there any reasonable way to accomplish the transition I'm trying to make - taking in Comparable from the public-facing method and using it in a type-safe manner in the internal implementation? Or do I need the same type information for my outer method as I have for the inner one?
Comparable is just defined as:
public interface Comparable<T>
It means that implementing classes can compareTo anything they want. So for example I can do this:
class Vague
implements Comparable<String> {
#Override
public int compareTo(String str) {
return 0;
}
}
When you have a type as:
<T extends Comparable<? super T>>
It means that T must be a Comparable that also compares to a T or superclass of T.
On the other hand, when you just have <T> and then Comparable<T> it can be a Comparable that compares to anything.
The class Vague is a Comparable<T> but not a T extends Comparable<? super T>. Obviously Vague is not a good Comparable.
So yes, these are inconvertible types and the method signatures will have to be made to match. <T extends Comparable<? super T>> is the type safe way to declare a Comparable parameter generically. It means two instances of T can be compared to each other.

In the following example, is "List<? extends T>" necessary, or will "List<T>" do the same thing?

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

Categories

Resources