什么时候不要在覆盖时调用super()方法?

时间:2012-04-20 10:49:37

标签: java android override

当我创建自己的Android自定义类时,我extend为其本机类。然后当我想覆盖基本方法时,我总是调用super()方法,就像我在onCreateonStop等中一样。

我认为就是这样,因为Android团队从一开始就建议我们在每个方法覆盖时始终调用super

但是,在很多书中,我可以看到,比我更有经验的开发人员经常忽略调用super而我真的怀疑他们这样做是因为缺乏知识。例如,请查看superstartElementcharacters中省略endElement的基本SAX解析器类:

public class SAXParser extends DefaultHandler{
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        if(qName.equalsIgnoreCase("XXY")) {
            //do something
        }
    }

    public void characters(char[] ch, int start, int length) throws SAXException {
        //do something
    }

    public void endElement(String uri, String localName, String qName) throws SAXException {
        if(qName.equalsIgnoreCase("XXY")) {
            //do something
        }else () {
            //do something
        }
    }
}

如果您尝试通过Eclipse或任何其他IDE创建任何覆盖方法,super将始终作为自动化过程的一部分创建。

这只是一个简单的例子。书籍充满类似代码

他们如何知道何时必须致电super以及何时可以省略呼叫?

PS。不要绑定到这个特定的例子。这只是从许多例子中随机挑选的一个例子。

(这听起来像是一个初学者的问题,但我真的很困惑。)

7 个答案:

答案 0 :(得分:140)

通过调用super方法,您不是覆盖方法的行为,而是扩展它。

super的调用将执行您正在扩展的类为该方法定义的任何逻辑。请注意,在您的方法覆盖中调用super的实现时,这可能很重要。例如:

public class A { 
    public void save() { 
         // Perform save logic
    }
}

public class B extends A {
    private Object b;
    @Override
    public void save() { 
        super.save(); // Performs the save logic for A
        save(b); // Perform additional save logic
    }
}

B.save()的调用将按此特定顺序执行save()A的{​​{1}}逻辑。如果您未在B内拨打super.save(),则不会调用B.save()。如果您在A.save()之后致电super.save()save(b)之后A.save()会有效执行。{/ p>

如果您想覆盖 B.save()的行为(即完全忽略其实现并自己提供),则不应该调用super

在您提供的super示例中,这些方法的SAXParser DefaultHandler只是空的,因此子类可以覆盖它们并为这些方法提供行为。在这个方法的implementations中,也指出了这一点。

public void startElement (String uri, String localName,
    String qName, Attributes attributes) throws SAXException {
    // no op
}

关于IDE生成的代码中的super()默认调用,如其注释中指出的@barsju,在每个构造函数中都隐式调用super()(即使您没有把它写在你的代码中),这意味着,在那个上下文中,调用super的默认构造函数。 IDE只是为你写下来,但如果删除它也会被调用。另请注意,在实现构造函数时,super()或带有参数的任何变体(即super(x,y,z))只能在方法的最开始中调用

答案 1 :(得分:16)

  

他们怎么知道什么时候你必须打电话给超级,什么时候可以省略它?

通常,如果特殊的API方法对底层框架上下文生命周期具有重要意义,那么它将始终在API文档中明确声明并突出显示,如Activity.onCreate() API documentation。此外,如果API遵循一个健壮的设计,它应该抛出一些例外来在项目编译时提醒消费者开发人员,并确保它不会在运行时产生错误。

如果API文档中没有明确说明,那么消费者开发人员可以认为在覆盖它时不必强制调用API方法。由消费者开发人员决定是使用默认行为(调用super方法)还是完全覆盖它。

如果条件允许(我喜欢开源软件),消费者开发人员可以随时查看API源代码,看看该方法是如何实际编写的。例如,请查看Activity.onCreate() sourceDefaultHandler.startElement() source

答案 2 :(得分:7)

你应该在头脑中做的测试是:

“我是否希望为我完成此方法的所有功能,然后再做一些事情?”如果是,那么您想调用super(),然后完成您的方法。这对于onDraw()这样的“重要”方法也适用,后者在后台处理很多事情。

如果您只想要一些功能(与您将覆盖的大多数方法一样),那么您可能不想调用super()

答案 3 :(得分:3)

Xavi 给了一个更好的答案..但你可能知道super()在被覆盖的方法中调用时做了什么...它广告你做了什么默认行为..

e.g:

onDraw() 
在重写时视图类中的

方法..在绘制一个视图完全绘制后出现之前你会画出一些东西..所以这里调用super是必要的,因为android有一些非常重要的事情要做(比如onCreate())

但同时

onLongClick()

当你覆盖它时你不想调用super,因为它会显示一个对话框,其中包含EditText或任何其他类似视图的选项列表。这就是基本的差异......你可以选择保留一些时间。但对于像onCreate() , onStop()这样的其他方法,你应该让操作系统处理它..

答案 4 :(得分:2)

我没有清楚地提出你的问题,但如果你问为什么不调用super方法:

调用super方法是有原因的:如果父类中没有零参数构造函数,那么就不可能为此创建子类,所以要么你需要保持一个无参数父类中的构造函数,或者您需要在子类构造函数的顶部使用super()定义argument(how much argument constructor you have used in super class)调用语句。

我希望这会有所帮助。如果没有,请告诉我。

答案 5 :(得分:2)

我实现了像

这样的约束数组列表
public class ConstraintArrayList<T> extends ArrayList<T> {
  ConstraintArrayList(Constraint<T> cons) {this.cons = cons;}
  @Override
  public boolean add(T element) {
    if (cons.accept(element))
      return super.add(element);
    return false;
  }
}

如果查看代码,它只是在实际让超类执行元素到列表的实际添加之前进行一些预检查。 这告诉了方法覆盖的两个原因之一:

  1. 您希望扩展超类可以做什么的可扩展性
  2. 您希望通过多态性添加特定行为的特异性,例如移动语义的常见动物王国示例,其中鸟类移动(飞行)和青蛙移动(跳跃)的方式特定于每个子类。

答案 6 :(得分:2)

对于那些还想知道Android Framework中哪个重写方法应该调用super并发现了这个问题的人-这是2019年的最新提示- Android Studio 3+会告诉您何时需要 >。

enter image description here