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

Как заставить полиморфный вызов метода супер?

У меня есть метод init, который используется и переопределяется через обширную иерархию. Каждый вызов init, однако, распространяется на работу, выполненную предыдущим. Естественно, я бы:

@Override public void init() {
   super.init();
}

И, естественно, это обеспечит, чтобы все вызывалось и создавалось. Мне интересно: могу ли я создать способ гарантировать, что был вызван метод super? Если все init не являются вызовом, в obejct есть разрыв, поэтому я хочу выбросить исключение или ошибку, если кто-то забывает называть super.

TYFT ~ Aedon

4b9b3361

Ответ 1

Здесь один из способов повысить исключение, если производный класс не может вызвать суперкласс:

public class Base {
    private boolean called;
    public Base() { // doesn't have to be the c'tor; works elsewhere as well
        called = false;
        init();
        if (!called) {
            // throw an exception
        }
    }
    protected void init() {
        called = true;
        // other stuff
    }
}

Ответ 2

Вместо того, чтобы пытаться это сделать, я не думаю, что это достижимо кстати! - как насчет другого подхода:

abstract class Base {
 public final void baseFunction() {
   ...
   overridenFunction(); //call the function in your base class
   ...
 }

 public abstract void overridenFunction();
}
...
class Child extends Base {
 public void overridenFunction() {...};
}

...
Base object = new Child();
object.baseFunction(); //this now calls your base class function and the overridenFunction in the child class!

Будет ли это работать для вас?

Ответ 3

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

Например, в onCreate() первое, что вам нужно сделать, это вызвать super.onCreate().

Ответ 4

Мне часто нравится использовать это решение. Это не вызовет ошибку времени выполнения, но будет отображаться синтаксическая ошибка:

 @CallSuper
 public void init() {
     // do stuff
 }

Это часть аннотаций Android поддержки.

Ответ 5

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

super.init()
if (!_baseIsInitialized) {
    // throw exception or do w/e you wish
}

где base использует

_baseIsInitialized = true;

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

Ответ 6

Я не знаю, как это сделать с помощью метода.

Однако обратите внимание, что именно так работают конструкторы. Каждый конструктор должен прямо или косвенно вызвать один из своих конструкторов суперклассов. Это статически гарантировано.

Я отмечаю, что вы пишете метод init. Не могли бы вы реорганизовать, чтобы ваш код использовал конструкторы, а не методы init? Это даст вам такое поведение прямо из ворот. Некоторые люди (например, я) в любом случае предпочитают конструкторы для инициализации методов, отчасти по этой причине.

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

Ответ 7

В настоящее время вы можете аннотировать свой метод с помощью @CallSuper. Это заставит Lint проверить, что любые переопределения этого метода вызывает super(). Вот пример:

@CallSuper
protected void onAfterAttached(Activity activity) {
    if (activity instanceof ActivityMain) {
        mainActivity = (ActivityMain) activity;
    }
}

В приведенном выше примере любые методы в классах потомков, которые переопределяют onAfterAttached, но не называют super, заставят Lint вызывать ошибку.