Абстрактный класс Java, реализующий интерфейс с универсальными шаблонами

Я пытаюсь определить абстрактный класс, реализующий Comparable. Когда я определяю класс со следующим определением:

public abstract class MyClass implements Comparable <MyClass>

подклассы должны реализовать compareTo (объект MyClass) . Вместо, Я хочу, чтобы каждый подкласс реализовал compareTo (SubClass object) , принимая объект своего собственного типа. Когда я пытаюсь определить абстрактный класс с помощью чего-то вроде:

public abstract class MyClass implements Comparable <? extends MyClass>

Он жалуется, что «Супертип не может указывать какой-либо подстановочный знак».

Есть ли решение?

64
задан Cem 28 August 2010 в 23:41
поделиться

4 ответа

На мой взгляд, это слишком многословно, но работает:

public abstract class MyClass<T extends MyClass<T>> implements Comparable<T> {

}

public class SubClass extends MyClass<SubClass> {

    @Override
    public int compareTo(SubClass o) {
        // TODO Auto-generated method stub
        return 0;
    }

}
44
ответ дан 24 November 2019 в 16:00
поделиться

Помимо механических трудностей, с которыми вы сталкиваетесь при объявлении подписей, цель не имеет особого смысла. Вы пытаетесь установить ковариантную функцию сравнения, которая ломает всю идею создания интерфейса, который могут адаптировать производные классы.

Если вы определяете некоторый подкласс SubClass таким образом, что его экземпляры можно сравнивать только с другими экземплярами SubClass, то как SubClass удовлетворяет контракту, определенному МойКласс? Напомним, что MyClass говорит о том, что его и любые производные от него типы можно сравнивать с другими экземплярами MyClass. Вы пытаетесь сделать это неверным для SubClass, что означает, что SubClass не удовлетворяет контракту MyClass: вы не можете заменить SubClass для MyClass, поскольку требования SubClass более строгие.

Эта проблема сосредоточена на ковариантности и контравариантности, а также на том, как они позволяют изменять сигнатуры функций посредством вывода типа. Вы можете смягчить требование к типу аргумента, приняв более широкий тип, чем требует сигнатура супертипа, и вы можете усилить требование к возвращаемому типу, обещая возвращать более узкий тип, чем требует сигнатура. подпись супертипа. Каждая из этих свобод по-прежнему допускает совершенную замену супертипа производным типом; вызывающий объект не может заметить разницу при использовании производного типа через интерфейс супертипа, но вызывающий объект, использующий производный тип, конкретно может воспользоваться этими свободами.

Ответ Вилли учит кое-чему об общих объявлениях, но я призываю вас пересмотреть свою цель, прежде чем принимать технику за счет семантики.

19
ответ дан 24 November 2019 в 16:00
поделиться

Я не уверен, что вам нужен захват:

Сначала добавьте compareTo в абстрактный класс...

public abstract class MyClass implements Comparable <MyClass> {

@Override
public int compareTo(MyClass c) {
...
}    
}

Затем добавьте реализации...

public class MyClass1 extends MyClass {
...
}

public class MyClass2 extends MyClass {
...
}

Вызов сравнения вызовет метод супертипа ...

MyClass1 c1 = new MyClass1();
MyClass2 c2 = new MyClass2();

c1.compareTo(c2);
1
ответ дан 24 November 2019 в 16:00
поделиться

см. собственный пример Java:

public abstract class Enum<E extends Enum<E>> implements Comparable<E>
    public final int compareTo(E o)

комментарий seh: обычно аргумент правильный. но дженерики усложняют отношения типов. подкласс не может быть подтипом MyClass в решении Вилли....

SubClassA является подтипом MyClass, но не подтипом MyClass

type MyClass определяет контракт для compareTo(X), который должны соблюдать все его подтипы. там нет проблем.

3
ответ дан 24 November 2019 в 16:00
поделиться
Другие вопросы по тегам:

Похожие вопросы: