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

san*_*one 109 java android overriding

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

而且我认为就是这样,从一开始Android团队建议我们总是调用super每个方法覆盖.

但是,在很多书中我都可以看到,比我更有经验的开发人员经常忽略呼叫super,我真的怀疑他们是缺乏知识.例如,查看这个基本的SAX解析器类,其中super省略了startElement,characters并且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
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

这只是一个简单的例子.书中充满了类似的代码.

他们怎么知道你什么时候打电话super,什么时候可以省略打电话?

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

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

Xav*_*ica 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
    }
}
Run Code Online (Sandbox Code Playgroud)

的调用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
}
Run Code Online (Sandbox Code Playgroud)

关于super()IDE生成的代码中的默认调用,如@barsju他的注释中所指出的,在每个构造函数中都有一个隐式调用super()(即使你没有在你的代码中编写它),这意味着,在那个上下文中,调用super' s默认构造函数.在IDE刚刚记下来给你,但它也将得到,如果你删除它叫.还要注意,当实现构造函数时,super()或者带有参数的任何变体(即super(x,y,z))只能在方法的最开头调用.

  • 还要注意,对于构造函数`super()`(超类的默认构造函数)总是被调用,即使你没有指定它.如果超类没有默认构造函数,如果没有显式调用超类的一个构造函数作为子类构造函数中的第一个语句,则会出现编译错误. (14认同)

yor*_*rkw 16

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

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

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

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


Mic*_*ael 7

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

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

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