2016-11-29 16 views
0

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

Вот что я делаю сейчас:

abstract class ParentClass<T extends ParentClass> extends RelativeLayout { 
    ... 
    public T aMethod(){ 
     return (T)this; 
    } 
} 

и

class ChildClass1 extends ParentClass<ChildClass1>{ 
... 
} 

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

+4

Это сломается, если я решит сделать это: 'class ChildClass2 расширяет ParentClass '. Теперь я не совсем понимаю, чего вы хотите достичь или почему вы хотите достичь этого. Если вы хотите соответствующим образом обновить свой вопрос, я могу дать ответ. –

+0

@JoeC У меня есть работы, но мне требуется, чтобы я включил «this» в родительский класс в T. Он уже должен знать, что «это» является экземпляром T, поэтому мне было интересно, было ли более элегантное решение что просто не было достаточно умным, чтобы думать. Либо тот, который не требовал от меня броска, либо тот, который возвращал дочерний экземпляр без использования дженериков вообще. –

+0

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

ответ

0

Проблема в том, что нет способа ссылаться на тип «этого самого класса». Вот почему вы должны использовать конструкции, такие как abstract class Base<T extends Base<T>>. Но, как многие из упомянутых в комментариях, ничто не запрещает вам определять Subclass1 extends <Subclass2>. Существует только синтаксический способ гарантировать, что T является «этим самым классом».

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

public abstract class Base<T extends Base<T>> { 

    protected Base() { 
     final Class<?> t = (Class<?>) ((ParameterizedType) getClass().getGenericSuperclass()) 
       .getActualTypeArguments()[0]; 
     if (!t.isInstance(this)) { 
      throw new IllegalArgumentException(); 
     } 
    } 

    public T getInstance() { 
     @SuppressWarnings("unchecked") 
     T thisIsT = (T) this; 
     return thisIsT; 
    } 
} 

Этот класс может быть реализованным:

public class Extension1 extends Base<Extension1> {} 

Но это не:

public class Extension2 extends Base<Extension1> {} 

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