1

Кажется, что вы обычно реализовали интерфейс java.lang.Comparable без указания параметра типа.Почему невозможно одновременно использовать Comparable <T>?

public abstract class Area implements Comparable { 
    @Override 
    public int compareTo(Object other) { 
     if (other instanceof Area) 
      return new Double(getArea()).compareTo(other.getArea()); 
     return -1; // or something else 
    } 
    abstract public double getArea(); 
} 

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

public abstract class Area implements Comparable<Area> { 
    @Override 
    public int compareTo(Area other) { 
     // ... 

Если я хочу представить еще один класс, чтобы сравнить Area с, я думал, что я мог бы сделать следующее:

public abstract class Area implements Comparable<Area>, Comparable<Volume> { 
    @Override 
    public int compareTo(Area other) { 
     // ... 
    } 
    @Override 
    public int compareTo(Volume other) { 
     // ... 
    } 
} 

Но Java компилятор говорит мне:

Area.java:2: error: repeated interface 
public abstract class Area implements Comparable<Area>, Comparable<Volume> { 
                   ^
Area.java:2: error: Comparable cannot be inherited with different arguments: <Area> and <Volume> 
  1. Существуют ли какие-либо недостатки, указывающие аргумент типа для общего интерфейса?
  2. Почему Java не позволяет мне эту множественную реализацию?

Примечание: Я использую Java версии 1.7.0_45

+0

Я думаю, что лучший вопрос: почему вы думаете, что это было бы полезно? И как будет 'newYork.compareTo (одиннадцать)' быть яблоками для яблок? :-) – haraldK

ответ

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

  2. Это связано с type erasure. Comparable<Area> и Comparable<Volume> - это, по сути, тот же класс для виртуальной машины и, вскоре после проверки действительности, также для компилятора.

Если вы хотите, чтобы реализовать два различных сравнимых интерфейсы, просто использовать Comparator с для них - это обычно легче поддерживать, чем состав наследования в классах.

Для некоторых приложений (отличия генериков во время выполнения) вы также можете попробовать их подклассифицировать, например. ComparableArea extends Comparable<Area>ComparableVolume extends Comparable<Volume>, но в этом конкретном случае это вызовет больше проблем, чем решение IMO, поскольку вы все равно получите ошибку Comparable cannot be inherited with different arguments - но по крайней мере вы могли бы дифференцировать эти интерфейсы, например. instanceof.

+2

Согласен. Если OP хочет иметь возможность сравнивать несколько элементов, которые не одного типа и не имеют общего суперкласса, лучше просто написать «Компаратор», который знает, как это сделать.Ваши классы 'Area' не должны (IMO) знать, что существуют классы' Volume', и как сравнивать себя. Если * они сделали *, то не будет ли ваш класс 'Volume' также реализовывать оба' Comparable'? Вы можете видеть, как это быстро выйдет из-под контроля, поскольку вы добавляете больше типов. –

+0

@CraigOtis Я полностью согласен; Я добавлю это в качестве примечания к моему ответу. – vaxquis

0

Я думаю, что в этом случае Java говорит, что связанные классы могут быть сопоставимыми, но с использованием искусственного компаратора мы можем делать больше сравнений между несвязанными классами. Итак, мы должны реализовать общий интерфейс связанных классов (классы в рамках одной иерархии наследования). В случае, если мы хотим добавить искусственную реализацию, добавьте интерфейс, который можно передать (так что у вас есть пара семейств интерфейсов, таких как Comparable и Comparator).