1

I have the following sort method in a clone of ArrayList:

@SuppressWarnings({"rawtypes", "unchecked"})
public void sort(Comparator<? super E> c){
    if(c == null){
        // Use ascending order (only works if types are comparable)
        class ascComparator<T> implements Comparator<T> {
            public int compare(T a, T b) {
                // This will raise an exception if the types are not comparable
                return ((Comparable)a).compareTo(b);
            }
        }
        c = new ascComparator<E>();
    }
    // Cast the internal array to comparable then call merge sort
    sorter.mergeSort((Comparable[])array, c);
}

The sorter object is an instance of Sort:

public class Sort {
    @SuppressWarnings("unchecked")
    public <E extends Comparable<E>> E[] mergeSort(E[] list, Comparator<? super E> c){
        ...
    }
}

I get the following error on the sorter.mergeSort line:

The method mergeSort(E[], Comparator<? super E>) in the type Sort is not applicable for the arguments (Comparable[], Comparator<capture#8-of ? super E>)

I'm not sure why this is happening as both the parameter and argument have type Comparator<? super E>.

Henry
  • 3,472
  • 2
  • 12
  • 36
  • Does `E extends Comparable` from the signature of `mergeSort` do something well-defined? – gkhaos Feb 26 '22 at 23:10
  • I use a `Comparator` to compare items in `mergeSort`. Is it not required? – Henry Feb 26 '22 at 23:12
  • 1
    @gkhaos [The meaning of >](https://stackoverflow.com/questions/8537500/java-the-meaning-of-t-extends-comparablet) – Kayaman Feb 26 '22 at 23:20
  • 2
    There is no reason to do _anything_ with `Comparable` except when creating `ascComparator`. There should be no other mention of `Comparable` in your code. I recommend starting there. – Louis Wasserman Feb 26 '22 at 23:45
  • Read https://stackoverflow.com/a/1540223/139985 for an explanation of why the `c` parameter is declared as `Comparator super E> c` rather than `Comparator extends E> c` in `List.sort`. – Stephen C Feb 27 '22 at 00:35

2 Answers2

1

Thanks to everyone for their comments. I've now fixed it.

@SuppressWarnings("unchecked")
public void sort(Comparator<? super E> c){
    if(c == null){
        // Use ascending order (only works if types are comparable)
        class ascComparator<T> implements Comparator<T> {
            public int compare(T a, T b) {
                // This will raise an exception if the types are not comparable
                return ((Comparable<T>)a).compareTo(b);
            }
        }
        c = new ascComparator<E>();
    }
    // Cast the internal array to E then call merge sort
    sorter.sort((E[]) array, c);
}

As Kayaman said, I shouldn't use rawtypes so I've given ascComparator parameter T. I've also casted array to E instead of Comparable as it didn't do what I thought it did. I've also changed Sort:

@SuppressWarnings("unchecked")
private <E> E[] mergeSort(E[] list, Comparator<E> c){
    ...
}

As pointed out by Louis Wasserman I don't need the Comparable type cast.

Henry
  • 3,472
  • 2
  • 12
  • 36
  • I've just found that it works, I'd appreciate it if you showed me how to do it properly. I don't see where I'm not using generics. – Henry Feb 26 '22 at 23:07
  • I can't use `T` as it's not defined and using `E` gives `The method mergeSort(E[], Comparator super E>) in the type Sort is not applicable for the arguments (Comparable[], Comparator)`, hence why I used the raw type before. – Henry Feb 26 '22 at 23:32
  • `T cannot be resolved to a type` – Henry Feb 26 '22 at 23:34
  • If I don't use comparable I get `The method mergeSort(E[], Comparator) in the type Sort is not applicable for the arguments (Object[], Comparator)` – Henry Feb 26 '22 at 23:34
  • If I cast it to `E[]` then I get `The method mergeSort(E[], Comparator>) in the type Sort is not applicable for the arguments (E[], Comparator)` – Henry Feb 26 '22 at 23:35
  • Then how do I do it? – Henry Feb 26 '22 at 23:37
  • First of all we are lacking some informations here to give you proper help. The suppression of the warning is a big code smell - why do you need the casts at all? Each cast could raise a ClassCastException, that's what the warning is for. You can prevent the warning by a preceding if with an instanceof operator - but what is your action, if the condition fails? What type is the "internal class array" that you mentioned in your call to `.sort`? And if `sorter` is an instance of `Sort`, but that class declares a `mergeSort` method - how will that code ever compile? – cyberbrain Feb 27 '22 at 17:15
  • 1
    The names of your sorting methods do not match, `sort` vs `mergeSort`. Further, your `ascComparator` is obsolete. Just use `if(c == null) c = (Comparator super E>)Comparator.naturalOrder();` – Holger Mar 09 '22 at 13:12
1

Problem comes due to the ? inside the <? super E> - two different ? could be different types and are handled like that. You can see that from the message part "capture#8-of ?".

Also your mixing of raw types and unchecked casts will not help to solve your problem. In your code you have to casts to Comparable without the type parameter.

cyberbrain
  • 3,433
  • 1
  • 12
  • 22
  • I've used `? super E` because that's what the docs for the `List` interface use. I'm not sure how to change my generics to avoid errors, because not using raw types causes a very similar error. – Henry Feb 26 '22 at 23:21