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

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

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


person Peterdk    schedule 18.11.2010    source источник
comment
Я тоже хочу это знать. И дело не только в том, что Eclipse помогает: если я удаляю вызов super.onCreate(), приложение выдает ошибку времени выполнения, говоря: не вызывал super.onCreate(). Так что да, это действительно заставляет вас вызывать метод super. Но как?   -  person Rodrigo Castro    schedule 16.12.2011
comment
@RodrigoCastro Вы можете просмотреть javadocs для каждого метода. Например, onCreate() .   -  person    schedule 09.05.2012


Ответы (8)


Вот исходник 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() для вас. Хотя это всего лишь предположение.

person Matt Ball    schedule 18.11.2010
comment
Я предполагаю, что mCalled = true также используется для возможного исключения. Возможно, не в onCreate(), но когда действительно возникает такое исключение, оно будет использовать этот простой шаблон. - person Peterdk; 18.11.2010

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

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

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

@CallSuper

person runor49    schedule 09.06.2015
comment
Да, вы попали в точку. Спасибо. - person SMBiggs; 09.08.2015
comment
Еще не пробовал, но читал документацию. Это будет круто, я думаю. Это должен быть принятый ответ. - person Rizwan Sohaib; 12.08.2015
comment
Извините, но мне нужно изменить свой комментарий. Это не заставило реализовать суперметод. Я смог запустить приложение без ужина. - person Rizwan Sohaib; 12.08.2015
comment
Все остальные ответы полная чушь, кроме этого. Должно быть принято. - person Le_Enot; 20.02.2016
comment
@RizwanSohaib это не заставит вас что-либо делать. Он будет выделен и сообщит вам, что вам нужно позвонить. Чтобы сделать что-то более сложное, вам понадобится либо обработчик аннотаций, либо реализовать логику самостоятельно. в зависимости от IDE, это также должно помешать вам строить. - person frostymarvelous; 28.02.2016
comment
Идеальный ответ. Большое спасибо - person Võ Quang Hòa; 21.10.2016
comment
Вы можете применить @CallSuper к выпускным сборкам, используя проверку lint MissingSuperCall tools.android.com/tips/lint -проверки - person fthdgn; 03.07.2017
comment
Спасибо, это именно то, что я хочу. - person smarteist; 27.08.2019
comment
Это должен быть ответ! - person sebasira; 17.06.2020

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

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().

person Andrzej Doyle    schedule 18.11.2010

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

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(), и это всегда будет версия базового класса, поскольку она была объявлена ​​окончательной. Специфичные для реализации вещи находятся в impl_stuff(), которую можно переопределить.

person Lagerbaer    schedule 18.11.2010

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

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

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

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

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

person speakingcode    schedule 27.06.2012

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

person DJClayworth    schedule 18.11.2010

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

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

person hvgotcodes    schedule 18.11.2010

Eclipse просто помогает вам делать все правильно и избегать исключений.

Из http://developer.android.com/reference/android/app/Activity.html#onCreate(android.os.Bundle)

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

person Flygenring    schedule 17.03.2011