Попытки объединить цепочку методов с расширениями классов

Я пытаюсь объединить цепочку методов с расширениями класса и методом, определенным в базовом классе. Однако я изо всех сил пытаюсь заставить его работать, так как я еще не очень хорошо знаком с дженериками. Может ли кто-нибудь помочь мне заставить это работать? Это было бы очень признательно. Спасибо!

Текущая ситуация:

public abstract class A<T extends A<?>> extends F // the base class, all others extend this one (either direct or indirect)
public T isLoaded() { // method defined in class A
    // Omitted
    return (T) this;
}

public class B extends A<B> // One of the classes that extends the base class
public D tapButton() // Method defined in class B

public class C extends A<C> // Another class that extends the base class, also has a child itself
public C setAmount(int amount) // method defined in class C

public class D extends C // Class that extends the previous one (C)
public E tapButtonTwo() // Method defined in class D, can't move this one level up to due to other parts of the code

Код, который пытается использовать эти классы и методы:

// Failing scenario
protected void doSomething() {
    // I already have an instance of type B, but I omitted this part
    b.tapButton() // returns type D
        .isLoaded() // returns type C and is the cause of the problem
        .setAmount(10) // returns type C
        .tapButtonTwo() // fails on: cannot resolve method
}

// Scenario that does work:
protected void doSomething() {
    // I already have an instance of type B, but I omitted this part
    b.tapButton() // returns type D
        .setAmount(10) // now returns type D
        .tapButtonTwo() // works
}

person Alex    schedule 02.05.2019    source источник
comment
Что такое расширение класса?   -  person nicomp    schedule 02.05.2019
comment
Обратите внимание, что D расширяет C, что означает, что он расширяет A<C>, а не A<D>.   -  person JimmyB    schedule 02.05.2019
comment
Вы являетесь D классом, расширяющим C, где класс C всегда будет возвращать объект типа C при вызове isLoaded. Вы можете просто переопределить метод isLoaded в своем классе D, чтобы вернуть объект типа D вместо понижения до C.   -  person Rann Lifshitz    schedule 02.05.2019
comment
@RannLifshitz Нет, не сработает, потому что C придется объявить о возврате D, чего он не может.   -  person JimmyB    schedule 02.05.2019
comment
Связано: Java Generic Builder   -  person MC Emperor    schedule 02.05.2019
comment
Чем расширение класса отличается от наследования?   -  person nicomp    schedule 02.05.2019
comment
@JimmyB: я прямо заявил - переопределение должно быть выполнено в классе D, который расширяет C, таким образом наследуя все методы Cs. Переопределение isLoaded в классе D позволит вернуть экземпляр как фактический экземпляр D вместо экземпляра C.   -  person Rann Lifshitz    schedule 02.05.2019
comment
@RannLifshitz Теперь я понимаю, что ты имеешь в виду. Не рассматривал этот вариант, потому что он как бы нарушает контракт A.   -  person JimmyB    schedule 02.05.2019
comment
@JimmyB: Правильно - указывает на то, что ИМХО может быть проблема со всем дизайном.   -  person Rann Lifshitz    schedule 02.05.2019