Java generics - переопределение абстрактного метода и возвращающий тип подкласса

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

public abstract class SuperClass{
  public abstract SuperClass getSelf();
}

public class SubClass extends SuperClass{
  @Override
  public SubClass getSelf(){
    return this;
  }
}

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

public abstract class SuperClass{
  public abstract <? extends SuperClass> getSelf();
}

public class SubClass extends SuperClass{
  @Override
  public SubClass getSelf(){
    return this;
  }
}

Спасибо за любую помощь.

edit: добавлено расширение SuperClass в SubClass, duh

Ответы

Ответ 1

Это будет работать:

public abstract class SuperClass{
  public abstract SuperClass getSelf();
}

public class SubClass extends SuperClass{
  @Override
  public SubClass getSelf(){
    return this;
  }
}

Примечание. Я добавил extends SuperClass в ваше определение SubClass. Возвращаемый тип getSelf называется ковариантным типом возврата.

Ответ 2

Как насчет этого:

public abstract class SuperClass<T extends SuperClass<?>> {
   public abstract T getSelf();
}

public class SubClass extends SuperClass<SubClass> {
     public SubClass getSelf() {
         return this;
     }
}

Я знаю, что он довольно повторяющийся и ничто не ограничивает тип как тот же экземпляр SubClass, потому что также AnotherSubClass удовлетворяет оценке, но по крайней мере он должен делать трюк.

Ответ 3

Вот как это сделать (поскольку JDK 1.5 есть эта вещь, называемая ковариантными типами возврата, где возможно что-то подобное).

abstract class SuperClass<T extends SuperClass<T>>{
  public abstract T getSelf();
}

class SubClass extends SuperClass<SubClass> {
  public SubClass getSelf() { return this; }
}

public class Generics {
  public static void main(String[] args) {
    System.out.println(new SubClass().getSelf());
  }
}

Обратите внимание на подобное общее определение класса с Enum (http://download.oracle.com/javase/1,5.0/docs/api/java/lang/Enum.html)

Посмотрите, что происходит за кулисами (используя javap SuperClass SubClass):

class SubClass extends SuperClass{
    SubClass();
    public SubClass getSelf();
    public SuperClass getSelf();
}

abstract class SuperClass extends java.lang.Object{
    SuperClass();
    public abstract SuperClass getSelf();
}

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

Btw, обратите внимание, что public SuperClass getSelf(); в классе SubClass фактически является синтетическим методом.