Обобщение Java - переопределение абстрактного метода и возвращаемый тип подкласса - PullRequest
15 голосов
/ 23 июня 2011

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

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: добавлено расширение Суперкласса до SubClass, да

Ответы [ 3 ]

9 голосов
/ 23 июня 2011

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

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

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

Обратите внимание, что я добавил extends SuperClass в ваше определение SubClass.Тип возврата getSelf называется ковариантным типом возврата .

4 голосов
/ 23 июня 2011

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

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

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

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

2 голосов
/ 23 июня 2011

Вот как это сделать (Начиная с 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();
}

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

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

...