web-dev-qa-db-ja.com

派生クラスにスーパーメソッドを呼び出すように強制するにはどうすればよいですか? (Androidのように)

新しいActivityクラスを作成してからonCreate()メソッドをオーバーライドすると、Eclipseで常に自動追加されるsuper.onCreate()が不思議でした。これはどのように起こりますか?これを強制する抽象クラスまたは親クラスにJavaキーワードがありますか?

スーパークラスを呼び出さないことが違法かどうかはわかりませんが、一部のメソッドでは、これを行わないと例外がスローされたことを覚えています。これもJavaに組み込まれていますか?あなたはそれを行うためにいくつかのキーワードを使用できますか?それともどうやって?

74
Peterdk

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()への呼び出しを自動的に追加するものだと思います。しかし、それは完全な推測です。

9
Matt Ball

これは、サポートアノテーションライブラリに追加されます。

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

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

@CallSuper

169
runor49

親クラスのロジックを実行するためにサブクラスをforceしたい場合、一般的なパターンは次のようなものです:

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()の呼び出しに失敗した.

79
Andrzej Doyle

スーパークラスメソッドも確実に呼び出されるようにするには、少し工夫する必要があります。スーパークラスメソッドの上書きを許可せず、オーバーライド可能な保護されたメソッドを呼び出すようにします。

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
Lagerbaer

実際の質問に答えるために、super.onCreate()の呼び出しの自動作成はADTプラグインの機能です。 Javaでは、サブクラスに直接メソッドafaikのスーパー実装を呼び出させることはできません(回避策については、他の回答で説明されているパターンを参照してください)。ただし、Androidでは、アクティビティオブジェクト(またはサービスオブジェクト)を直接インスタンス化しないことに注意してください-システムにインテントを渡し、システムがオブジェクトをインスタンス化して、そのオブジェクトでonCreate()を呼び出します(他のライフサイクルメソッドと共に)。そのため、システムにはActivityインスタンスへの直接オブジェクト参照があり、onCreate()のスーパークラス実装でtrueに設定されたブール値を(おそらく)チェックできます。実装方法は正確にはわかりませんが、おそらく次のようになります。

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

私の推測では、おそらくそれよりもわずかに複雑ですが、あなたはアイデアを得る。便宜上、ADTプラグインが指示するため、Eclipseは自動的に呼び出しを作成します。ハッピーコーディング!

8
speakingcode

Javaにはスーパーの呼び出しを強制するものはありません。また、したくない場合は多くの例があります。スーパーの呼び出しを強制できる唯一の場所はコンストラクタです。すべてのコンストラクタスーパークラスコンストラクターを呼び出す必要があります。明示的に記述しない場合は1つ(引数なしのコンストラクター)が挿入され、引数なしのコンストラクターがない場合は明示的に呼び出す必要があります。

4
DJClayworth

Eclipseは単に有用であり、必要に応じてスーパークラス実装を呼び出すことができることを思い出させてくれます。

実装を呼び出していないため、スーパークラスが行う必要のあることを行っていないため、おそらくエラーが発生しています。

3
hvgotcodes

Eclipseは、正しいことを行い、例外を回避するのに役立ちます。

から http://developer.Android.com/reference/Android/app/Activity.html#onCreate(Android.os.Bundle

派生クラスは、このメソッドのスーパークラスの実装を呼び出す必要があります。そうでない場合、例外がスローされます。

1
Flygenring