题 为什么我们有时必须在Android中调用super?


有时当我覆盖方法时,我第一次调用它时会出现异常,如下所示:

05-31 21:32:04.266: E/AndroidRuntime(28471): android.support.v4.app.SuperNotCalledException: 
Fragment AnalFragment{41795860 #1 id=0x7f070002} did not call through to super.onDestroy()

我们为什么被迫打电话 super.method()?有意义的是,父类有义务,但更重要的是,我们如何知道方法需要 super 被召唤,而不是等待它崩溃?


41
2018-06-01 01:36


起源


在Java中,我们有 方法不是 功能。请记住,方法是属于a的函数 class (成员职能)。 - Alex Lockwood
@AlexLockwood所以...方法是函数,我们没有函数? - Dave Newton
方法是“属于a的函数 class”。 - Alex Lockwood
我不确定如何定义它而不使用“功能”这个词......那么“子程序”怎么样呢?我所知道的是Java没有功能,哈哈 - Alex Lockwood
+1“AnalFragment” - 我很好奇你正在写什么。 - ajacian81


答案:


为什么我们被迫调用super.method()?

构成Android SDK的类可能非常复杂。例如,活动和片段必须执行许多操作才能正常工作(即管理生命周期,优化存储器使用,将布局绘制到屏幕等)。要求客户端调用基类(通常在方法的开头)确保仍然执行这些操作,同时仍为开发人员提供合理的抽象级别。

我们怎么知道a 功能  方法 要求超级被召唤?

文档应该告诉您是否需要这样做。如果不是,我会谷歌搜索一些示例代码(或检查API演示......或者更好,请查看源代码!)。弄清楚应该不难。


38
2018-06-01 01:49



我想我依赖Eclipse的自动完成功能总会让我接触到这个问题。我想我的问题是,你怎么强迫孩子打电话给超级? - StackOverflowed
通过“要求”,我的意思是,如果你不打电话 super,运行时系统会抛出异常,或者事情无法正常工作。 - Alex Lockwood
对不起,我的意思是强制要求调用超级的方法是什么? - StackOverflowed
这取决于基类实现。大多数情况下,Android会检查是否使用布尔标志调用了超类方法。例如,在Activity实现中,有一个布尔变量 mCalled 设置为 true 如果已调用超类方法,并且 false 除此以外。如果基类识别出从未调用过类方法,则抛出一个 SuperNotCalledException。你可以通过检查来亲自看看 Activity 源代码。这是否回答你的问题? - Alex Lockwood
啊,我看,这是一种强制执行此行为的辅助方法。谢谢。 - StackOverflowed


我知道这不是OP的真正意图,他确实提出了这个问题,我不相信它有一个非常好的答案所以,如果有人想知道“为什么我要打超级?”?如果他们会要求它,为什么他们不这样做呢!!!“。这是问题的答案......

基本上,如果你要覆盖必须调用的东西,那么必须调用super(),这通常是相当复杂的代码。现在,他们不仅仅为你做这件事并在你的功能之前调用它的原因主要是让你有控制权! :-D

更具体地说,你无法控制如果你调用super(),但是,你可以控制WHEN! 所以,假设你有一些特定的代码需要在调用super()之前发生,你现在可以在运行你的代码之后自由调用super()。或者......假设您需要super()已经为您的代码运行而不是崩溃,您现在可以选择在运行代码之前运行super(),从而确保为您设置所有内容。哎呀,你甚至可以在技术上覆盖超类硬核并编写你自己的方法来处理super()本身,然后使它不需要调用super(),但99.9%的时间理智的人不需要去做这个! :-P

所以,“为什么我必须调用super()”的简短回答是......这样你就可以控制它何时被调用并在之前或者在super()运行之后执行操作。 :-)


13
2017-12-02 18:50





 关键字有两个主要用途

1。 调用超类的构造函数。

2。 访问由子类成员隐藏的超类的成员。

那么,为什么有时需要用户超级关键字呢?答案将是4GB语言下的android,这意味着它已经准备好了很多功能。虽然我们覆盖了这些自定义方法,但我们使用了super关键字。

看看android中超级关键字的非常简单的用法(正如我们大部分时间所做的那样)。

@Override
public void onCreate(Bundle savedInstanceState) 
{
    super.onCreate(savedInstanceState);
    .
    .
    .
}

super()必须始终是子类'构造函数内执行的第一个语句。当子类调用super()时,它调用其直接超类的构造函数。第二种形式的super最适用于子类的成员名称在超类中使用相同名称隐藏成员的情况。


9
2018-06-01 02:41



注意:如果构造函数没有显式调用超类构造函数,那么Java(以及C#)编译器 自动 插入对超类的无参数构造函数的调用。这就是所谓的 构造函数链接,当有一长串的下降时,你需要注意它。 - Disk Crasher


该要求通常直接在API文档中指定。例如,请参阅android.widget.ListView.onFinishInflate:

protected void onFinishInflate()

...

即使子类重写onFinishInflate,它们也应该始终确保调用super方法,以便我们调用它。

不幸的是,我个人的经验是Android文档的质量参差不齐。因此,我怀疑有些情况需要调用,但没有记录。


3
2018-06-01 01:43





作为基础,super是一种方法,用于引用完成类扩展的主超类字段/方法(在初始类定义中使用extends)或者从其创建实例。

当我们需要一个最基本的定义来改变超类的方法/字段来解决我们的目的。

例如

java.lang.Object(有很多方法和字段)> android.view.View> android.view.ViewGroup> android.widget.LinearLayout

但是如果你需要更改/使用它,因为它是Object Class的一个方法,那么你需要Super方法来引用第一次创建的方法在对象类中 LinearLayout类。


0
2018-03-18 19:14



这个答案对现有答案有何影响? - TylerH
TylerH - 简单易懂。所有上述答案都像任何新的蜜蜂开发者的行话。这个问题总是出现在新开发者身上。在这里,我试图将它们与他们学习OOP的基础知识联系起来,以便获得一些熟人。以上答案令人惊叹和酷,但因为它们很容易理解中等级开发。不是一个新的蜜蜂开发,因为他/她可能会问这个超级棒是什么?这是一个像超人。我希望你理解我的观点。 - Rahul Joshi


重要的是要注意,一旦覆盖了一个方法,你基本上忽略了父类中的所有内容,而是在子类中拥有自己的自定义实现(从字面上覆盖它)!

在我们的例子中,我们不想丢弃父实现。我们实际上希望继续使用原始方法,并分别为每个子类添加额外的检查。

这是我们使用“超级”关键字的地方!

您可以使用“super”关键字,然后使用点,然后使用方法名称,在子类中重用父方法:

例如:isValidMove(position)是棋子的方法,检查移动有效性并绑定在8x8棋盘上。

super.isValidMove(位置);

在这里使用关键字super意味着我们希望在“this”类的实现内部运行super(或parent)类中的实际方法。

这意味着在每个子类中,在检查自定义移动之前,您可以检查super.isValidMove(position)是否返回false。如果是这样,则无需再进行任何检查并立即返回false;否则,继续检查。

Rook类的新实现将如下所示:

class Rook extends Piece{
   boolean isValidMove(Position newPosition){
      // First call the parent's method to check for the board bounds
  if(!super.isValidMove(position)){
     return false;
  }
  // If we passed the first test then check for the specific rock movement
  if(newPosition.column == this.column && newPosition.row == this.row){
     return true;
  }
  else{
     return false;
      }
   }
}

您还可以使用super()来调用父级的构造函数。这通常在实现子构造函数时完成。通常,您希望首先在父构造函数中运行所有内容,然后在子构造函数中添加更多代码:

class Rook extends Piece{
   // default constructor
   public Rook(){
    super(); // this will call the parent's constructor
    this.name = "rook";
   }
}

注意:如果子代的构造函数没有使用super显式调用父代的构造函数,Java编译器会自动插入对父类的默认构造函数的调用。如果父类没有默认构造函数,则会出现编译时错误。


0
2018-06-08 07:12