T extends Comparable <T>

I have the following class.

class MyClass<T> 

It uses the following constructor.

 MyClass(Comparator<T> comparator, Collection<? extends T> data) 

And he has a field that is set in the constructor as follows:

 this.data = Collections.unmodifiableCollection(data); 

In the special case, when T implements Comparable, I do not want to require the transfer of a comparator, since I can just use the natural order. So I thought I should use this constructor:

 public <T extends Comparable<T>> MyClass(Collection<T> data) 

But there seems to be a type mismatch: cannot convert from Collection<T> to Collection<? extends T> Collection<T> to Collection<? extends T> to the above assignment operator. I tried all kinds of things: adding more general options, etc., but no one works. I can't seem to specify a binding that states: if you have a type T that implements Comparable, do the direct thing.

Any ideas?

Thanks.

+6
source share
3 answers

Unfortunately, I do not think that such a system "if Comparable do this else do that" is possible with a system such as Java.

You can separate Comparable and non-Comparable cases into separate classes and hide them behind the interface, something like this:

 interface Interface<T> { public void processData(); } class MyClass<T> implements Interface<T> { private final Collection<? extends T> data; MyClass(Comparator<T> comparator, Collection<? extends T> data) { this.data = data; } public void processData() { // ... } } class MyCompClass<T extends Comparable<T>> implements Interface<T> { private final Collection<? extends T> data; MyCompClass(Collection<? extends T> data) { this.data = data; } public void processData() { // ... } } class Factory { static <T extends Comparable<T>> Interface<T> create(Collection<? extends T> data) { return new MyCompClass<T>(data); } static <T> Interface<T> create(Comparator<T> comparator, Collection<? extends T> data) { return new MyClass<T>(comparator, data); } } 

But this can lead to a lot of duplicate code. Another option is to leave MyClass, which requires a comparator in its constructor, and build this comparator in the factory:

 class MyClass<T> { private final Collection<? extends T> data; MyClass(Comparator<T> comparator, Collection<? extends T> data) { this.data = data; } public void processData() { // ... } } class Factory { static <T extends Comparable<T>> MyClass<T> create(Collection<? extends T> data) { return new MyClass<T>(new Comparator<T>() { public int compare(T o1, T o2) { return o1.compareTo(o2); } }, data); } static <T> MyClass<T> create(Comparator<T> comparator, Collection<? extends T> data) { return new MyClass<T>(comparator, data); } } 
+3
source

I agree that this seems impossible as a direct solution

 class MyClass<T> { Collection<? extends T> data; public MyClass(Comparator<T> comparator, Collection<? extends T> data) { this.data = data; } public <E extends T & Comparable<T>> MyClass(Collection<E> data) { this.data = data; } } 

rejected by the compiler with

You cannot specify an optional Comparable<T> binding when the first binding is a type parameter

See also Why can't I use a type argument in a type parameter with a few constraints? (in particular, Chris Povirkaโ€™s answer).

As for the decisions, I agree with Chris B.

0
source

You can use the usual constructor for the first case and the factory method for the second:

 class MyClass<T> { Collection<? extends T> data; Comparator<? super T> comparator; public MyClass(Comparator<? super T> comparator, Collection<? extends T> data) { this.data = data; this.comparator = comparator; } public static <T extends Comparable<? super T>> MyClass<T> fromComparable(Collection<T> data) { return new MyClass<T>(Collections.reverseOrder(Collections.reverseOrder()), data); } } 
0
source

Source: https://habr.com/ru/post/900004/


All Articles