Java Abstract Class Внедрение интерфейса с универсалами

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

public abstract class MyClass implements Comparable <MyClass>
Подклассы

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

public abstract class MyClass implements Comparable <? extends MyClass>

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

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

Ответ 1

Это немного слишком многословно, по моему мнению, но работает:

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;
    }

}

Ответ 2

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

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

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

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

Ответ 3

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

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

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

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

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

Ответ 4

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

Сначала добавьте 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);

Ответ 5

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

}

public class SubClass extends MyClass<SubClass> {

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

}

Ответ 6

Нашел другое решение:

  • Определите интерфейс в полях, которые составляют comaprable (например, ComparableFoo)
  • Внедрить интерфейс в родительский класс
  • Внедрить Comparable в родительском классе.
  • Напишите свою реализацию.

Решение должно выглядеть следующим образом:

public abstract class MyClass implements ComparableFoo,Comparable<ComparableFoo> {
    public int compareTo(ComparableFoo o) {
    // your implementation
    }
}

Это решение подразумевает, что больше вещей может реализовать ComparableFoo - это, вероятно, не так, но тогда вы кодируете интерфейс и выражение generics просто.

Ответ 7

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

public abstract class MyClass implements Comparable <Object>

и выполните проверку экземпляра при переопределении compareTo в MySubClass:

@Override
public int compareTo(Object o) {
    if (o instanceof MySubClass)) {
        ...
    }
    else throw new IllegalArgumentException(...)
}

аналогично 'equals' или 'clone'