Jak zmusić klasę pochodną do wywołania super metody? (Tak jak robi to Android)

85

Zastanawiałem się, podczas tworzenia nowych Activityklas, a następnie przesłanianie onCreate()metody w Eclipse zawsze dotrzesz automatycznego dodania: super.onCreate(). Jak to się stało? Czy istnieje słowo kluczowe java w klasie abstrakcji lub nadrzędnej, które to wymusza?

Nie wiem, czy niewywołanie superklasy jest nielegalne, ale pamiętam, że w niektórych metodach został zgłoszony wyjątek, ponieważ tego nie robię. Czy jest to również wbudowane w Javę? Czy możesz użyć do tego słowa kluczowego? Albo jak to się robi?

Peterdk
źródło
Ja też chcę to wiedzieć. I nie tylko Eclipse jest pomocnym, jeśli usunę wywołanie super.onCreate (), aplikacja wyświetli błąd w czasie wykonywania, mówiąc: „nie wywołał super.onCreate ()”. Więc tak, to naprawdę zmusza cię do wywołania super metody. Ale jak?
Rodrigo Castro
@RodrigoCastro Możesz przejrzeć javadocs dla każdej metody. Na przykład onCreate () .

Odpowiedzi:

10

Oto źródło Activity#onCreate()- to prawie wszystkie komentarze ( oryginał - patrz wiersz ~ 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;
}

więc przypuszczam, że wtyczka ADT Eclipse jest tym, do czego automatycznie dodaje to wywołanie super.onCreate(). Ale to całkowite przypuszczenie.

Matt Ball
źródło
2
Wydaje mi się, że mCalled = truerównież jest używany do ewentualnego wyjątku. Może nie w, onCreate()ale jeśli rzeczywiście taki wyjątek zostanie zgłoszony, użyje tego prostego wzorca.
Peterdk
192

To jest dodawane w bibliotece adnotacji wsparcia:

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

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

@CallSuper

runor49
źródło
Tak, trafiłeś tu w sedno. Dzięki.
SMBiggs
Jeszcze nie próbowałem, ale przeczytaj dokumentację. Myślę, że to będzie niesamowite. To powinna być akceptowana odpowiedź.
Rizwan Sohaib,
1
Wszystkie inne odpowiedzi są całkowicie bzdurne, z wyjątkiem tego. Powinien zostać zaakceptowany.
Le_Enot
3
@RizwanSohaib to nie zmusi Cię do niczego. Podświetli się i poinformuje Cię, że musisz go nazwać. Aby zrobić coś bardziej złożonego, będziesz potrzebował procesora adnotacji lub samodzielnego zaimplementowania logiki. w zależności od IDE powinno to również uniemożliwić budowanie.
mroźno cudowny
1
Doskonała odpowiedź.
Wielkie
82

Jeśli chcesz zmusić podklasy do wykonywania logiki klasy nadrzędnej, typowy wzorzec jest podobny do następującego:

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";
    }
}

To właściwie nie odpowiada na twoje pytanie, co skłania Eclipse do automatycznego wstawiania wywołania nadklasy do implementacji; ale nie sądzę, aby tak było, ponieważ zawsze można to usunąć.

W rzeczywistości nie można wymusić, że metoda musi wywoływać wersję nadklasy za pomocą słowa kluczowego Java lub czegoś podobnego. Podejrzewam, że twoje wyjątki pochodzą po prostu z jakiegoś kodu w klasie nadrzędnej sprawdzającego oczekiwane niezmienniki lub coś, co zostało unieważnione przez twoje podejście. Zwróć uwagę, że różni się to nieco od zgłaszania wyjątku, ponieważ nie udało się wywołać super.onCreate().

Andrzej Doyle
źródło
8

Jeśli chcesz mieć absolutną pewność, że wywoływana jest również metoda nadklasy, musisz trochę oszukać: Nie zezwalaj na nadpisywanie metody nadklasy, ale pozwól jej wywołać metodę chronioną nadpisywalną.

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();
  }
}

W ten sposób użytkownik musi wywołać Super.foo () lub Base.foo () i zawsze będzie to wersja klasy bazowej, tak jak została zadeklarowana jako ostateczna. Rzeczy specyficzne dla implementacji znajdują się w impl_stuff (), które można nadpisać.

Lagerbaer
źródło
8

Aby odpowiedzieć na twoje aktualne pytanie, automatyczne tworzenie wywołania super.onCreate () jest funkcją wtyczki ADT. W Javie nie można bezpośrednio zmusić podklasy do wywołania super implementacji metody, afaik (obejrzyj wzorzec opisany w innych odpowiedziach w celu obejścia problemu). Należy jednak pamiętać, że w systemie Android nie tworzysz instancji obiektów Activity (lub obiektów Service) bezpośrednio - przekazujesz Intent do systemu, a system tworzy instancję obiektu i wywołuje onCreate () na nim (wraz z innymi metodami cyklu życia). Tak więc system ma bezpośrednie odwołanie do obiektu do instancji Activity i jest w stanie sprawdzić (prawdopodobnie) niektóre wartości logiczne, które są ustawione na true w implementacji onCreate () nadklasy. Chociaż nie wiem dokładnie, jak jest zaimplementowany, prawdopodobnie wygląda to mniej więcej tak:

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

A w klasie poziomu „systemowego”, która odbiera intencję i tworzy z niej instancję obiektu Activity:

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

Domyślam się, że jest to prawdopodobnie nieco bardziej złożone, ale masz pomysł. Eclipse automatycznie tworzy połączenie, ponieważ wtyczka ADT nakazuje mu to dla wygody. Miłego kodowania!

speakcode
źródło
4

W Javie nie ma nic, co wymusza wywoływanie super, i jest wiele przykładów, kiedy nie chcesz. Jedyne miejsce, w którym możesz wymusić wywołanie super, to konstruktorzy. Wszyscy konstruktorzy muszą wywołać konstruktora nadklasy. Jeden (konstruktor bez argumentów) zostanie wstawiony, jeśli nie napiszesz go jawnie, a jeśli nie ma konstruktora bez argumentów, musisz go wywołać jawnie.

DJClayworth
źródło
3

Eclipse jest po prostu pomocny, przypominając ci, że możesz wywołać implementację nadklasy, jeśli chcesz.

prawdopodobnie otrzymujesz błąd, ponieważ nie robisz czegoś koniecznego, co robi superklasa, ponieważ nie wywołujesz jej implementacji.

hvgotcodes
źródło