45

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

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被调用,而不是等待它崩溃?

4

6 回答 6

46

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

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

我们怎么知道函数 方法需要调用 super 呢?

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

于 2012-06-01T01:49:13.817 回答
18

我知道这不是 OP 的真正意图,他确实问了这个问题,我不相信它得到了一个很好的答案,所以,如果有人想知道“为什么我必须打电话给超级?!?如果他们会要求的,他们为什么不为我做呢!!!”。以下是这些问题的答案......

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

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

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

于 2013-12-02T18:50:44.860 回答
9

super关键字有两个主要用途

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

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

那么,为什么有时需要用户超级关键字呢?答案是 android 属于 4GL 语言,这意味着它有许多现成的功能。当我们为自定义覆盖这些方法时,我们使用 super 关键字。

看看在 android 中 super 关键字的非常简单的用法(我们大多数时候都这样做)。

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

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

于 2012-06-01T02:41:09.207 回答
4

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

受保护的无效 onFinishInflate ()

...

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

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

于 2012-06-01T01:43:48.113 回答
1

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

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

这就是我们使用“super”关键字的地方!

您可以通过使用“super”关键字,后跟一个点,然后是方法名称来重用子类中的父方法:

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

super.isValidMove(位置);

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

这意味着在每个子类中,在您检查自定义移动之前,您可以检查 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 编译器会自动插入对父类的默认构造函数的调用。如果父类没有默认构造函数,你会得到一个编译时错误。

于 2018-06-08T07:12:15.137 回答
0

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

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

例如

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

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

于 2018-03-18T19:14:14.730 回答