Как заставить производный класс вызывать метод super?(Как и в Android) - PullRequest
71 голосов
/ 18 ноября 2010

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

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

Ответы [ 8 ]

166 голосов
/ 09 июня 2015

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

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

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

@ CallSuper

77 голосов
/ 18 ноября 2010

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

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

9 голосов
/ 18 ноября 2010

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

8 голосов
/ 28 июня 2012

Чтобы ответить на ваш актуальный вопрос, автоматическое создание вызова 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 сообщает это, для удобства.Удачного кодирования!

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

4 голосов
/ 18 ноября 2010

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

3 голосов
/ 18 ноября 2010

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

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

1 голос
/ 17 марта 2011

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

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

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

...