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'