Как заставить полиморфный вызов метода super? - PullRequest
13 голосов
/ 26 мая 2011

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

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

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

TYFT ~ Aedon

Ответы [ 7 ]

12 голосов
/ 26 мая 2011

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

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!

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

8 голосов
/ 26 мая 2011

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

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 голосов
/ 26 мая 2011

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

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

1 голос
/ 30 января 2016

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

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

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

0 голосов
/ 12 марта 2017

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

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

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

0 голосов
/ 08 сентября 2011

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

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

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

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

0 голосов
/ 26 мая 2011

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

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

, где база использует

_baseIsInitialized = true;

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

...