Компилятор считает, что тип Comparable не является Comparable

Итак, у меня есть класс, который реализует Comparable (для краткости у меня есть фиктивный метод)

public class MarkovEntry<T extends Chainable> implements Comparable<MarkovEntry<T>>
{
    // Compare two rows by ID
    public int compareTo(MarkovEntry<T> e)
    {
        return 0;
    }
}

И метод в другом классе, который принимает Comparable (опять же, фиктивный метод)

public class ArrayOps
{
    public static int binSearch(ArrayList<Comparable> list, Comparable c)
    {
        return 0;
    }
}

Тем не менее, когда я пытаюсь вызвать свой метод следующим образом

int index = ArrayOps.binSearch(entries, newEntry);

Где записи представляют собой ArrayList из MarkovEntry, а newEntry - это MarkovEntry, компилятор говорит мне

actual argument java.util.ArrayList<com.company.MarkovEntry<T>> cannot be converted 
to java.util.ArrayList<java.lang.Comparable> by method invocation.

Что здесь происходит? MarkovEntry специально реализует Comparable — почему компилятор этого не распознает?

Мой класс Chainable также реализует Comparable, если это как-то связано.


person user2926428    schedule 02.05.2014    source источник


Ответы (1)


Дженерики немного странные в этом

ArrayList<SuperType>

на самом деле не является супертипом

ArrayList<SubType>

например ArrayList<Number> не является супертипом ArrayList<Integer>. Это связано с тем, что если бы такая связь сохранялась, вы могли бы заменить ArrayList<Number> на ArrayList<Integer>, что затем позволило бы выполнять операции, которые были бы незаконными, если бы вы не сделали замену.

Чтобы быть более конкретным, скажем, вы сделали это:

ArrayList<Number> list = new ArrayList<Integer>();

Тогда вы сможете вставить Double в list, потому что для компилятора list это ArrayList<Number>! Как видите, это нарушает гарантии, которые должны предоставлять дженерики, поэтому это не разрешено.


Вам нужен общий метод:

public static <T extends Comparable<? super T>> int binSearch(ArrayList<T> list)

По сути, вы можете генерировать методы так же, как вы можете генерировать классы.

Дополнительную информацию можно найти здесь: http://docs.oracle.com/javase/tutorial/extra/generics/methods.html

person awksp    schedule 02.05.2014
comment
Здесь нет необходимости в общем методе; Просто используйте шаблон: int binarySearch(ArrayList<? extends Comparable> list) - person fabian; 02.05.2014
comment
Подождите, а разве Comparable не нужно параметризовать? - person awksp; 02.05.2014
comment
для достижения наилучших результатов используйте <T extends Comparable<? super T>> - person newacct; 03.05.2014
comment
binSearch(ArrayList<? extends Comparable<?>> list) не будет типобезопасным - person newacct; 03.05.2014
comment
@newacct Я знал, что чего-то не хватает... Спасибо! - person awksp; 03.05.2014