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


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

public abstract class MyClass implements Comparable <MyClass>

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

public abstract class MyClass implements Comparable <? extends MyClass>

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

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

7 62

7 ответов:

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

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

}

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

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

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

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

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

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

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

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

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

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

во-первых, добавьте compareTo в абстрактный класс...

public abstract class MyClass implements Comparable <MyClass> {

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

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

public class MyClass1 extends MyClass {
...
}

public class MyClass2 extends MyClass {
...
}

вызов compare вызовет метод super type...

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

c1.compareTo(c2);
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;
    }

}

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

  1. определить интерфейс на полях, которые составляют comaprable (например ComparableFoo)
  2. реализовать интерфейс на родительском классе
  3. реализовать сопоставимый на родительском классе.
  4. напишите свою реализацию.

решение должно выглядеть так:

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

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

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

public abstract class MyClass implements Comparable <Object>

и сделать проверку instanceof при переопределении compareTo в MySubClass:

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

аналогично 'равно' или 'Клон'