如何强制派生类调用超级方法?(就像Android一样)


85

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

我不知道不调用父类是否违法,但是我记得在某些方法中,我没有这样做就引发了异常。这也是Java内置的吗?您可以使用某些关键字来做到这一点吗?或如何完成?


我也想知道这一点。而且,不仅是Eclipse有所帮助,如果我删除对super.onCreate()的调用,该应用程序还会显示一个运行时错误:“未调用super.onCreate()”。是的,这确实迫使您调用super方法。但是如何?
罗德里戈·卡斯特罗

@RodrigoCastro您可以查看每种方法的javadocs。例如onCreate()

Answers:


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 2010年

192

这被添加到支持注释库中:

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

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

@CallSuper


是的,您在这里碰到头了。谢谢。
SMBiggs 2015年

尚未尝试,但请阅读文档。我猜这太棒了。这应该是公认的答案。
Rizwan Sohaib

1
除此以外,所有其他答案都是垃圾。应该被接受。
Le_Enot

3
@RizwanSohaib它不会强迫您做任何事情。它将突出显示并告知您需要调用它。要做更复杂的事情,您将需要注释处理器或自己实现逻辑。取决于IDE,它也会阻止您进行构建。
frostymarvelous

1
完美的答案。非常感谢
武广HOA

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

如果要绝对确保也调用了超类方法,则必须进行一些欺骗:不要覆盖超类方法,而要让它调用可重写的受保护方法。

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


8

为了回答您的实际问题,对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插件会告诉它。祝您编码愉快!


4

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


3

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

您可能会收到错误,因为您没有执行超类所必需的操作,因为您没有调用其实现。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.