如何强制派生类调用super方法? (就像安卓一样)

发布于 2024-10-03 04:18:37 字数 256 浏览 7 评论 0原文

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

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

I was wondering, when creating new Activity classes and then overriding the onCreate() method, in eclipse I always get auto added: super.onCreate(). How does this happen? Is there a java keyword in the abstract or parent class that forces this?

I don't know if it is illegal not to call the super class, but I remember in some methods that I got a exception thrown for not doing this. Is this also built-in into java? Can you use some keyword to do that? Or how is it done?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

鱼窥荷 2024-10-10 04:18:38

如果您想绝对确保超类方法也被调用,则必须采取一些技巧:不允许超类方法被覆盖,但让它调用可覆盖的受保护方法。

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

If you want to make absolutely sure that the superclass-method is called as well, you must trick a bit: Don't allow the superclass-method to be overwritten, but have it call an overridable protected method.

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

That way, the user must call Super.foo() or Base.foo() and it will always be the base-class version as it was declared as final. The implementation-specific stuff is in impl_stuff(), which can be overriden.

婴鹅 2024-10-10 04:18:38

这是 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() 的调用。但这完全是猜测。

Here's the source of Activity#onCreate() - it is almost all comments (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;
}

so, my guess would be that the ADT Eclipse plugin is what's auto-adding that call to super.onCreate() for you. It's a total guess, though.

醉态萌生 2024-10-10 04:18:38

为了回答您的实际问题,自动创建对 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 插件的指示自动创建调用。快乐编码!

To answer your actual question, the auto-creation of the call to super.onCreate() is a feature of the ADT plugin.
In java, you cannot directly force a subclass to call the super implementation of a method, afaik (see the pattern described in other answers for work-around). However, keep in mind that in Android, you are not instantiating Activity objects (or Service objects) directly - you pass an Intent to the system and the system instantiates the object and calls onCreate() upon it (along with other lifecycle methods). So the system has a direct object reference to the Activity instance and is able to check (presumably) some Boolean that is set to true in the superclass implementation of onCreate().
Although I don't know exactly how it is implemented, it probably looks something like this:

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

And in the "system" level class that receives the Intent and instantiates the Activity object from it:

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

My guess is it's probably slightly more complex than that, but you get the idea. Eclipse automatically creates the call because the ADT plugin tells it to, as a convenience. Happy coding!

病女 2024-10-10 04:18:38

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

There is nothing in Java that forces calling of super, and there are plenty of examples when you wouldn't want to. The only place where you can force calling of super is in constructors. All constructors have to call a superclass constructor. One (the no arguments constructor) will be inserted if you don't write one explicitly, and if there is no no-arguments constructor then you must call it explicitly.

執念 2024-10-10 04:18:38

Eclipse 只是提供帮助,提醒您如果需要的话可以调用超类实现。

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

Eclipse is just being helpful, reminding you that you can call the superclass implementation if you want.

you are probably getting an error because you are not doing something necessary that the superclass does, since you are not calling its implementation.

烟沫凡尘 2024-10-10 04:18:38

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

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

派生类必须调用超类对此方法的实现。如果不这样做,就会抛出异常。

Eclipse just helps you doing things right and avoid exceptions.

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

Derived classes must call through to the super class's implementation of this method. If they do not, an exception will be thrown.

涙—继续流 2024-10-10 04:18:38

这是怎么发生的?抽象类或父类中是否有 java 关键字强制执行此操作?

正如您所观察到的,在 Android 上,当您重写函数时,IDE 会自动编辑对 super() 的调用,并且如果删除对 super 的调用,则会出现 lint 错误。

方法可以指示重写它们的方法应该使用 @CallSuper 注释来调用它们。
例如,请参阅文档给出的示例

@CallSuper
override fun onCreate(savedInstanceState: Bundle?) {}

使用为此,您可能需要将注释库添加到您的 build.gradle 中:

dependencies {
    implementation("androidx.annotation:annotation:1.8.0")
}

这也是java内置的吗?你可以使用一些关键字来做到这一点吗?或者说是怎么做到的?

它没有内置到 Java 中,但这里的其他答案显示了纯 Java 的手动方法。

如果您使用的是 Android,我建议仅使用 @CallSuper。它“只是”一个 linter 错误(而不仅仅是一个警告!)。因此,如果您在构建时运行 linter(您应该这样做),效果是相同的:如果您不调用 super 方法,构建将会失败。

How does this happen? Is there a java keyword in the abstract or parent class that forces this?

As you observed, on Android calls to super() are auto-edited by IDEs when you override a function, and you get lint errors if you remove the call to super.

Methods can signal that methods which override them should call them by using the @CallSuper annotation.
E.g., see the example given by the docs:

@CallSuper
override fun onCreate(savedInstanceState: Bundle?) {}

To use this, you may need to add the annotation library to your build.gradle:

dependencies {
    implementation("androidx.annotation:annotation:1.8.0")
}

Is this also built-in into java? Can you use some keyword to do that? Or how is it done?

It's not built into Java, but other answers here show manual approaches for plain Java.

If you are on Android, I recommend just using @CallSuper. It is "only" a linter error (not just a warning!). So if you run the linter at build time (which you should), the effect is the same: the build will fail if you don't call the super method.

擦肩而过的背影 2024-10-10 04:18:37

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

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

http://tools.android.com/tech-文档/支持注释

@CallSuper

This is added in the support annotation library:

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

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

@CallSuper

甲如呢乙后呢 2024-10-10 04:18:37

如果您想强制子类执行父类的逻辑,常见的模式如下所示:

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()而抛出异常略有不同。

If you want to force subclasses to execute the parent class' logic, a common pattern is something like the following:

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

This doesn't actually answer your question about what prompts Eclipse to automatically insert a superclass call into the implementation; but then I don't think that's the way to go anyway as this can always be deleted.

You can't actually enforce that a method must call the superclass' version with a Java keyword, or anything like that. I suspect that your exceptions simply came from some code in the parent class checking expected invariants, or something, that were invalidated by your approach. Note that this is subtly different from throwing an exception because you failed to call super.onCreate().

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文