Подтвердить что ты не робот

Требовать переопределение метода для вызова супер

Я хочу, чтобы, когда дочерний класс переопределяет метод в родительском классе, в этом дочернем методе вызывается super.method().

Есть ли способ проверить это во время компиляции?
Если нет, как бы я хотел бы бросить исключение во время выполнения, когда это произойдет?

4b9b3361

Ответ 1

Нельзя напрямую обращаться к этому. Однако вы можете сделать что-то вроде:

public class MySuperclass {
    public final void myExposedInterface() {
        //do the things you always want to have happen here

        overridableInterface();
    }

    protected void overridableInterface() {
        //superclass implemention does nothing
    }
}

public class MySubclass extends MySuperclass {
    @Override
    protected void overridableInterface() {
        System.out.println("Subclass-specific code goes here");
    }
}

Это обеспечивает внутреннюю точку интерфейса, которую подклассы могут использовать для добавления пользовательского поведения к общедоступному методу myExposedInterface(), гарантируя, что поведение суперкласса всегда выполняется независимо от того, что делает подкласс.

Ответ 2

Решение:

Посмотрите на проект findBugs...

  • FindBugs
    • Пакет аннотаций

Пример...

    import javax.annotation.OverridingMethodsMustInvokeSuper;
       :

    @OverridingMethodsMustInvokeSuper
    protected String getLabel(){
       ... 
    }

Override:

    @Override
    protected String getLabel(){
       // no call to Super Class!!
       // gives a message 
       ... 
    }

Я использую его около 3 лет. Никакие котята не пострадали.

Ответ 3

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

Если вы действительно хотите поехать по этому пути, вы можете использовать что-то вроде этого шаблона:

public class BaseClass {

  public final void myMethod() {
    // do special stuff here which must always happen ...

    // allow subclasses to customize myMethod() here
    myMethodCustom();
  }

  protected void myMethodCustom() {
    // base class does nothing
  }
}

Ответ 4

Там нет способа проверить это во время компиляции. (Тем не менее, я слышал предложения о том, что вы можете сделать это во время компиляции с аннотациями, хотя я никогда не видел конкретного аннотационного решения, и я не знаю, как это будет сделано.) Для способа выбросить исключение в время выполнения, см. этот поток. Возможно, вы можете реорганизовать свой код так, чтобы базовый класс имел метод final, который включает в себя основные части, и вызывает не конечный метод, который не требует вызова super.

Ответ 5

Как насчет того, если вы сделаете сам вызов? Вместо того, чтобы диктовать реализацию подклассу (который вы действительно не можете сделать), просто применяйте его к интерфейсу и реализации вашего базового класса.

public abstract class BaseClass {

    public final void callMeFirst() {
        // method that needs to be called before subclassing method runs
    }

    public final void makeSureWhateverGetsCalled() {
        callMeFirst();
        overrideMe();
    }

    public abstract void overrideMe();
}

public class OverridingClass extends BaseClass {
    @Override
    public void overrideMe() {
        // do whatever needs to be done AFTER callMeFirst() is run
    }
}

Ответ 6

Ну, я могу предположить, что инициализация в методе суперкласса используется в другом месте. Я бы установил флаг в методе суперкласса и проверил его позже, когда потребуется инициализация. В частности, скажем, setupPaint() - метод суперкласса, который всегда нужно вызывать. поэтому мы можем сделать:

class C {
  private boolean paintSetupDone = false;

  void setupPaint() { 
    paintSetupDone = true;
    ...
  }

  void paint() { // requires that setupPaint() of C has been called
     if (!paintSetupDone) throw RuntimeException("setup not done");
     ...
  }
}

Теперь, если подкласс C не вызывает функцию setupPaint(), нет никакого способа установить флаг (private), а также методы, требующие контрактного вызова суперкласса setupPaint(), такие как paint() сможет проверить и выбросить это исключение.

Как уже упоминалось в другом месте, нет способа требовать такой контракт в java.