Правильная сигнатура служебной функции для класса Array: Comparable <E>или Comparable ? - PullRequest
0 голосов
/ 09 января 2020

Я пытаюсь написать служебную функцию для класса Array.

Функция должна возвращать минимальный элемент для всех типов сопоставимых типов.

У меня вопрос, какая подпись должна функция имеет:

  1. public static <E> E min (Comparable**<E>**[] arr)
  2. public static <E> E min (Comparable**<? super E>**[] arr)

In Java массивы являются вариантами, и это означает, что если B расширяет A, то A [] и B [] тоже связаны, но ArrayList<A> и ArrayList<B> не имеют одинакового соединения.

Это полный код:

@SuppressWarnings("unchecked")
public static <E> E min (Comparable<E>[] arr){

    E min= null;

    if(arr.length > 0)          
        min = (E) arr[0];

    for (int i = 1; i < arr.length; i++) {

        if( (arr[i].compareTo((E) min)) < 0)
            min = (E) arr[i];
    }

    return min; 
}

Комментарий: I есть два класса A реализует Comparable A и B расширяет A

Когда подпись Comparable<? super E>, то вызов (от основного) к:

A aArr[] = new A[] {new A(1), new B(2), new B(-1)};
B bb = min(aArr);

- это ошибка компиляции: cannoot convert from ...A to ... B, но когда сигнатура min () равна Comparable<? super E>, тогда тот же вызов вполне подойдет.

Спасибо

Ответы [ 2 ]

1 голос
/ 09 января 2020

Вторая сигнатура работает, потому что A является суперклассом класса B, в то время как она соответствует условию подстановки ? super B.

Если вы хотите, чтобы ваша функция возвращала минимальное значение любого сопоставимого типизированного массива Вам просто нужно.

public static <E extends Comparable<E>> min (E[] arr)

Это позволит вам использовать метод для работы со всеми видами массивов, значения которых имеют сопоставимый тип. В вашем случае вы хотите, чтобы A и B были связаны. Поэтому вы также должны позволить вашему методу принимать параметры класса E и его суперклассов. Однако это необходимо только при попытке привести A к B, как в вашем примере. Это заставляет вас хотеть, чтобы ваш метод взял суперклассы E (поскольку A является суперклассом B) и все еще возвращает значение типа E.

public static <E extends Comparable<? super E>> min (E[] arr)
0 голосов
/ 09 января 2020

Ни одна из подписей не является "правильной" подписью для этого метода, IMO. Правильная подпись должна принимать E[], где E extends Comparable<? super E>:

public static <E extends Comparable<? super E>> E min (E[] arr){

    E min= null;

    if(arr.length > 0)
        min = arr[0];

    for (int i = 1; i < arr.length; i++) {

        if( (arr[i].compareTo(min)) < 0)
            min = arr[i];
    }

    return min;
}

Ваша текущая реализация неверно предполагает, что "классы, которые реализуют Comparable<T>, должны быть T или подклассом T». Это не обязательно правда. Вот почему вы должны подавить эти предупреждения.

В любом случае, вернемся к вашей реальной проблеме. На стороне вызывающего абонента вы делаете B bb = min(aArr). В случае Comparable<E> ошибка появляется, потому что компилятор не может определить, каким должен быть E. Это не может быть A, потому что A нельзя присвоить переменной типа B. Это также не может быть B, потому что вы даете ему A[], который не является Comparable<B>[].

Когда вы изменили его на Comparable<? super E>, E может быть B сейчас. Так как A[] совместим с Comparable<? super B>.

Но это работает действительно "хакерским" способом, потому что вы технически приводите каждый элемент в массиве к B, так как E является B, и из-за того, как стираются Java генерики, это не дает сбоя.

root вашей проблемы действительно лежит в строке B bb = min(aArr). Вы делаете ошибочное предположение, что минимум aArr имеет тип B. Почему ты так уверен? Это также может быть A, верно? С моим решением, приведенным выше, вам нужно привести результат к B, если вы так уверены, что это B:

B bb = (B)min(aArr);
...