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

85

Мне было интересно, при создании новых Activityклассов , а затем перекрывая onCreate()метод, в затмении я всегда получить авто добавил: super.onCreate(). Как это произошло? Есть ли ключевое слово java в абстрактном или родительском классе, которое вызывает это?

Я не знаю, незаконно ли не вызывать суперкласс, но я помню, что в некоторых методах у меня возникло исключение из-за того, что я этого не сделал. Это тоже встроено в Java? Вы можете использовать какое-нибудь ключевое слово для этого? Или как это делается?

Петердк
источник
Я тоже хочу это знать. И дело не только в Eclipse: если я удалю вызов super.onCreate (), приложение выдаст ошибку времени выполнения: «super.onCreate () не вызывается». Так что да, это действительно заставляет вас вызывать супер-метод. Но как?
Родриго Кастро
@RodrigoCastro Вы можете просмотреть javadocs для каждого метода. Например onCreate () .

Ответы:

10

Вот источник Activity#onCreate()- это почти все комментарии ( оригинал - см. Строку ~ 800 ):

/**
 * Called when the activity is starting.  This is where most initialization
 * should go: calling {@link #setContentView(int)} to inflate the
 * activity's UI, using {@link #findViewById} to programmatically interact
 * with widgets in the UI, calling
 * {@link #managedQuery(android.net.Uri , String[], String, String[], String)} to retrieve
 * cursors for data being displayed, etc.
 *
 * <p>You can call {@link #finish} from within this function, in
 * which case onDestroy() will be immediately called without any of the rest
 * of the activity lifecycle ({@link #onStart}, {@link #onResume},
 * {@link #onPause}, etc) executing.
 *
 * <p><em>Derived classes must call through to the super class's
 * implementation of this method.  If they do not, an exception will be
 * thrown.</em></p>
 *
 * @param savedInstanceState If the activity is being re-initialized after
 *     previously being shut down then this Bundle contains the data it most
 *     recently supplied in {@link #onSaveInstanceState}.  <b><i>Note: Otherwise it is null.</i></b>
 *
 * @see #onStart
 * @see #onSaveInstanceState
 * @see #onRestoreInstanceState
 * @see #onPostCreate
 */
protected void onCreate(Bundle savedInstanceState) {
    mVisibleFromClient = !mWindow.getWindowStyle().getBoolean(
            com.android.internal.R.styleable.Window_windowNoDisplay, false);
    mCalled = true;
}

Итак, я предполагаю, что плагин ADT Eclipse - это то, что автоматически добавляет этот вызов super.onCreate()для вас. Хотя это полное предположение.

Мэтт Болл
источник
2
Я предполагаю, что mCalled = trueтакже используется для возможного исключения. Возможно, не в, onCreate()но когда действительно создается такое исключение, он будет использовать этот простой шаблон.
Peterdk
194

Это добавлено в библиотеку аннотаций поддержки:

dependencies {
    compile 'com.android.support:support-annotations:22.2.0'
}

http://tools.android.com/tech-docs/support-annotations

@CallSuper

runor49
источник
Да, здесь вы попали в самую точку. Благодарю.
SMBiggs
Еще не пробовал, но прочтите документацию. Думаю, это будет круто. Это должен быть принятый ответ.
Ризван Сохаиб,
1
Все остальные ответы - полная чушь, кроме этого. Следует принять.
Le_Enot
3
@RizwanSohaib, это тебя ни к чему не заставит. Он будет выделен и сообщит вам, что вам нужно позвонить. Чтобы сделать что-нибудь более сложное, вам понадобится либо процессор аннотаций, либо реализация логики самостоятельно. в зависимости от среды IDE это также должно препятствовать сборке.
Frostymarvelous
1
Прекрасный ответ. Большое спасибо
Võ Quang Hòa
82

Если вы хотите заставить подклассы выполнять логику родительского класса, общий шаблон выглядит примерно так:

public abstract class SuperClass implements SomeInterface
{
    // This is the implementation of the interface method
    // Note it's final so it can't be overridden
    public final Object onCreate()
    {
        // Hence any logic right here always gets run
        // INSERT LOGIC

        return doOnCreate();

        // If you wanted you could instead create a reference to the
        // object returned from the subclass, and then do some
        // post-processing logic here
    }

    protected abstract Object doOnCreate();
}

public class Concrete extends SuperClass
{
    @Override
    protected Object doOnCreate()
    {
        // Here's where the concrete class gets to actually do
        // its onCreate() logic, but it can't stop the parent
        // class' bit from running first

        return "Hi";
    }
}

Это фактически не отвечает на ваш вопрос о том, что побуждает Eclipse автоматически вставлять вызов суперкласса в реализацию; но я не думаю, что это все равно что делать, так как это всегда можно удалить.

На самом деле вы не можете заставить метод вызывать версию суперкласса с ключевым словом Java или чем-то подобным. Я подозреваю, что ваши исключения просто возникли из-за какого-то кода в родительском классе, проверяющего ожидаемые инварианты или что-то еще, что было признано недействительным из-за вашего подхода. Обратите внимание, что это немного отличается от вызова исключения из-за того, что вы не смогли вызвать super.onCreate().

Анджей Дойл
источник
8

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

class Super
{
   public final void foo() {
      foo_stuff();
      impl_stuff();
   }

   protected void impl_stuff() {
      some_stuff_that_you_can_override();
   }
}

class Base extends Super
{
  protected void impl_stuff() { 
     my_own_idea_of_impl();
  }
}

Таким образом, пользователь должен вызвать Super.foo () или Base.foo (), и это всегда будет версия базового класса, поскольку она была объявлена ​​как final. Все, что связано с реализацией, находится в impl_stuff (), и его можно переопределить.

Lagerbaer
источник
8

Чтобы ответить на ваш актуальный вопрос, автоматическое создание вызова super.onCreate () - это функция плагина ADT. В java вы не можете напрямую заставить подкласс вызывать супер-реализацию метода afaik (см. Шаблон, описанный в других ответах для обхода). Однако имейте в виду, что в Android вы не создаете экземпляры объектов Activity (или объектов Service) напрямую - вы передаете Intent системе, а система создает экземпляр объекта и вызывает onCreate () для него (вместе с другими методами жизненного цикла). Таким образом, система имеет прямую объектную ссылку на экземпляр Activity и может проверять (предположительно) некоторое логическое значение, для которого установлено значение true в реализации суперкласса onCreate (). Хотя я точно не знаю, как это реализовано, вероятно, это выглядит примерно так:

class Activity
{
  onCreate()
  {
    superCalled = true;
    ...
  }
  ...
}

И в классе «системного» уровня, который получает намерение и создает из него экземпляр объекта Activity:

...
SomeActivitySubclass someActivitySubclassObject = new SomeActivitySubclass();
someActivitySubclassObject.onCreate();
if (!someActivityObject.isSuperCalled())
{
  Exception e = new Exception(...) //create an exception with appropriate details
  throw e;
}

Я предполагаю, что это, вероятно, немного сложнее, но вы поняли идею. Eclipse автоматически создает вызов, потому что плагин ADT сообщает об этом для удобства. Удачного кодирования!

говорящий код
источник
4

В Java нет ничего, что заставляло бы вызывать super, и есть множество примеров, когда вы этого не хотите. Единственное место, где вы можете принудительно вызвать super, - это конструкторы. Все конструкторы должны вызывать конструктор суперкласса. Один (конструктор без аргументов) будет вставлен, если вы не напишете его явно, а если конструктора без аргументов нет, вы должны вызвать его явно.

DJClayworth
источник
3

Eclipse просто помогает, напоминая вам, что вы можете вызвать реализацию суперкласса, если хотите.

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

hvgotcodes
источник