【问题标题】:How to force derived class to call super method? (Like Android does)如何强制派生类调用超级方法? (就像安卓一样)
【发布时间】:2011-05-12 03:32:54
【问题描述】:

我想知道,当创建新的 Activity 类然后覆盖 onCreate() 方法时,在 eclipse 中我总是自动添加:super.onCreate()。这是怎么发生的?抽象类或父类中是否有 java 关键字强制执行此操作?

我不知道不调用超类是否违法,但我记得在某些方法中我因为不这样做而引发了异常。这也是Java内置的吗?你可以使用一些关键字来做到这一点吗?或者是怎么做的?

【问题讨论】:

  • 我也想知道这个。而且不仅仅是 Eclipse 有帮助,如果我删除对 super.onCreate() 的调用,该应用程序会给出运行时错误消息:“没有调用 super.onCreate()”。所以是的,它真的迫使你调用 super 方法。但是怎么做呢?
  • @RodrigoCastro 您可以查看每个方法的 javadocs。例如onCreate().

标签: java android overriding super


【解决方案1】:

这是在支持注解库中添加的:

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

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

@CallSuper

【讨论】:

  • 是的,你在这里一针见血。谢谢。
  • 尚未尝试,但请阅读文档。我猜这会很棒。这应该是公认的答案。
  • 除此之外,所有其他答案都是废话。应该被接受。
  • @RizwanSohaib 它不会强迫你做任何事情。它会突出显示并让您知道您需要调用它。要执行更复杂的操作,您将需要注释处理器或自己实现逻辑。取决于 IDE,它应该也会阻止你构建。
  • 完美答案。非常感谢
【解决方案2】:

如果你想强制子类执行父类的逻辑,一个常见的模式是这样的:

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

【讨论】:

【解决方案3】:

这里是Activity#onCreate()的来源——几乎都是cmets (original - see line ~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() 的调用。不过,这完全是猜测。

【讨论】:

  • 我猜mCalled = true 也用于可能的异常。也许不在onCreate() 中,但是当确实抛出这样的异常时,它将使用那个简单的模式。
【解决方案4】:

如果你想确保超类方法也被调用,你必须花点小技巧:不要让超类方法被覆盖,而是让它调用一个可覆盖的受保护方法。

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() 中,可以被覆盖。

【讨论】:

    【解决方案5】:

    为了回答您的实际问题,自动创建对 super.onCreate() 的调用是 ADT 插件的一项功能。 在java中,您不能直接强制子类调用方法afaik的超级实现(请参阅其他答案中描述的模式以了解解决方法)。但是,请记住,在 Android 中,您不会直接实例化 Activity 对象(或 Service 对象)——您将 Intent 传递给系统,系统会实例化该对象并在其上调用 onCreate()(以及其他生命周期方法)。所以系统有一个对 Activity 实例的直接对象引用,并且能够检查(可能)一些在 onCreate() 的超类实现中设置为 true 的布尔值。 虽然不知道具体是怎么实现的,但大概是这个样子:

    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 插件会告诉它这样做,以方便使用。编码愉快!

    【讨论】:

      【解决方案6】:

      在 Java 中没有强制调用 super 的内容,并且有很多您不想这样做的示例。唯一可以强制调用 super 的地方是在构造函数中。所有构造函数都必须调用超类构造函数。如果您不显式编写一个(无参数构造函数),则会插入一个,如果没有无参数构造函数,则必须显式调用它。

      【讨论】:

        【解决方案7】:

        Eclipse 只是提供帮助,提醒您可以根据需要调用超类实现。

        您可能会遇到错误,因为您没有执行超类所做的必要操作,因为您没有调用它的实现。

        【讨论】:

          【解决方案8】:

          Eclipse 只是帮助您正确地做事并避免异常。

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

          派生类必须调用该方法的超类实现。否则,将引发异常。

          【讨论】:

            猜你喜欢
            • 2010-11-19
            • 1970-01-01
            • 2022-10-25
            • 2011-09-02
            • 2013-09-28
            • 2010-12-26
            • 2019-11-13
            • 1970-01-01
            • 2013-04-11
            相关资源
            最近更新 更多