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


113

当我创建自己的Android自定义类时,extend它就是本机类。然后,当我要重写基方法,我总是叫super()方法,就像我一直做的onCreateonStop

我认为就是这样,因为从一开始,Android团队就建议我们始终调用super每个方法重写。

但是,在许多书中,我可以看到比我自己更有经验的开发人员经常忽略调用super,我真的怀疑他们是因为缺乏知识而这样做。例如,看看这个基本的SAX,其中解析器类super中被省略startElementcharacters并且endElement

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。不要绑定到此特定示例。这只是从许多例子中随机挑选的一个例子。

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


3
endElement的API文档说:“默认情况下,不执行任何操作。应用程序编写者可能会覆盖此方法...”,这意味着您可以安全地调用super,因为它“不执行任何操作”,但您不必这样做,并且可以真正覆盖它。如果您阅读该方法的文档,通常可以告诉您是否必须/不可以/不应该这样做。
zapl 2012年

1
一个小例子:我在初始屏幕中使用onBackPressed(),但我不调用super,所以它不会消​​失,它只是禁用了按钮。
Bojan Kogoj

@sandalone很抱歉在这里询问,但是您对使用应用内结算如何处理增值税,如何由Google自动完成哪些国家/地区以及我必须手动向/报告增值税的做法有任何经验吗?看到stackoverflow.com/questions/36506835/...
王庙韦斯特内斯

Answers:


144

通过调用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()逻辑两个AB,在该特定的顺序。如果您不在super.save()内部通话B.save(),则A.save()不会被呼叫。如果你叫super.save()save(b)A.save()将有效地执行之后B.save()

如果您想覆盖 super的行为(也就是说,完全忽略其实现并自行提供),则不应调用super

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

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

super()正如@barsju他的评论所指出的那样,关于IDE生成的代码中的默认调用,在每个构造函数中都有一个隐式调用super()(即使您没有在代码中编写它),在这种情况下,这意味着对super'的默认构造函数。在IDE刚刚记下来给你,但它也将得到,如果你删除它叫。还要注意,在实现构造函数super()或其带参数的任何变体(即super(x,y,z))时,只能在方法的开始处进行调用。


14
还要注意super(),即使未指定for构造函数(超类的默认构造函数),也始终会调用它。如果超类没有默认的构造函数,而您未在子类构造函数中将第一个语句作为父语句显式调用,则会收到编译错误。
barsju 2012年

1
是的,这基本上只是懒惰-对于我们知道什么也不做的方法,只是为了简洁起见就忽略了
Voo 2012年

1
感谢您的宝贵意见,@ barjsu,我在回答中包含了这些详细信息。
XaviLópez'12

16

他们怎么知道何时必须调用super以及何时可以忽略它呢?

通常,如果特殊的API方法对基础框架上下文生命周期具有关键意义,则将始终在API文档(如Activity.onCreate()API文档)中明确声明并突出显示该方法。此外,如果API遵循健壮的设计,则它应引发一些异常,以在项目编译时警告使用者开发人员,并确保它在运行时不会产生错误。

如果在API文档中未明确说明,则对于消费者开发人员而言,假设重写该API方法不是强制性调用是非常安全的。消费者开发者可以决定使用默认行为(调用super方法)还是完全覆盖默认行为。

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


感谢您向我解释其他内容。感谢您提醒我检查源代码。
sandalone 2012年

7

您应该进行的测试是:

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

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


3

好吧,Xavi给出了一个更好的答案..但是您可能知道super()在重写方法中调用时会做什么...它会用默认行为广告您所做的事情。

例如:

onDraw() 

视图类中的方法被重写时..在说super.onDraw()之前绘制了一些东西,一旦视图被完全绘制,它就会出现..所以在这里调用super是必要的,因为android有一些非常重要的事情要做(例如onCreate())

但同时

onLongClick()

当您覆盖此内容时,您不希望调用super,因为它会弹出一个对话框,其中包含EditText或任何其他类似视图的选项列表。这就是基本的区别。您可以选择将其保留一段时间。其他方法,例如onCreate() , onStop()应该让操作系统处理。


2

我不清楚您的问题,但是如果您要问为什么不调用该super方法:

调用该super方法是有原因的:如果父类中没有零参数构造函数,则无法为其创建子类,因此您需要在父类中保留无参数构造函数,或者需要在子类构造函数的顶部定义super()调用语句argument(how much argument constructor you have used in super class)

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


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. 想要通过多态性添加特定行为的特定性,例如常见的动物王国示例中的移动语义,其中鸟移动(飞)和青蛙移动(跳)的方式特定于每个子类。

2

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

在此处输入图片说明

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.