Як змусити похідний клас викликати супер метод? (Як і 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

192

Це додано до бібліотеки анотацій підтримки:

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

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

@CallSuper


Так, ти вдарив цвях тут по голові. Дякую.
SMBiggs

Ще не пробували, але прочитайте документацію. Це, здається, буде приголомшливо. Це має бути прийнятою відповіддю.
Rizwan Sohaib

1
Усі інші відповіді - абсолютно безглузді, крім цього. Слід прийняти.
Le_Enot

3
@RizwanSohaib це нічого не змусить вас робити. Це виділить і дасть вам знати, що вам потрібно зателефонувати. Щоб зробити щось більш складне, вам знадобиться або процесор анотацій, або реалізувати логіку самостійно. залежно від IDE, це також не повинно заважати вам будувати.
морозний дивовижний

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

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

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 (), який можна замінити.


8

Щоб відповісти на ваше власне запитання, автоматичне створення виклику 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 про це повідомляє для зручності. Щасливого кодування!


4

У Java немає нічого, що змушує закликати супер, і є безліч прикладів, коли ви цього не хотіли б. Єдине місце, де можна змусити викликати супер - це конструктори. Усі конструктори повинні викликати конструктор суперкласу. Один (конструктор без аргументів) буде вставлений, якщо ви не напишете його явно, а якщо немає конструктора без аргументів, то ви повинні викликати його явно.


3

Eclipse просто корисний, нагадуючи вам, що ви можете зателефонувати до реалізації суперкласу, якщо хочете.

ви, мабуть, отримуєте помилку, оскільки ви не робите чогось необхідного, що робить суперклас, оскільки ви не викликаєте його реалізацію.


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.