当重写时不要调用super()方法?
当我创build自己的Android自定义类时,我extend
它的本地类。 然后当我想重写基方法时,我总是调用super()
方法,就像我总是在onCreate
, onStop
等一样
我认为就是这样,从一开始Android团队build议我们总是在每个方法覆盖面上调用super
。
但是,在许多书中,我可以看到,比我更有经验的开发者经常忽略super
调用,我真的怀疑他们是否缺乏知识。 例如,查看startElement
, characters
和endElement
省略super
基本SAXparsing器类:
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创build任何重写方法, super
将始终作为自动化过程的一部分创build。
这只是一个简单的例子。 书籍充满了类似的代码 。
他们如何知道什么时候你必须打电话给super
电话,什么时候可以忽略电话?
PS。 不要绑定到这个具体的例子。 这只是从许多例子中随机挑选的一个例子。
(这可能听起来像一个初学者的问题,但我真的很困惑。)
通过调用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()
调用将按照此特定顺序为A
和B
执行save()
逻辑。 如果你没有在B.save()
调用super.save()
则不会调用super.save()
。 如果在save(b)
super.save()
之后调用了super.save()
, A.save()
将在后来的B.save()
被有效执行。
如果你想覆盖 super
的行为(即完全忽略它的实现并自己提供),你不应该叫super
。
在您提供的SAXParser
示例中,这些方法的DefaultHandler
的实现只是空的,以便子类可以覆盖它们并为这些方法提供行为。 在这个方法的javadoc中也指出了这一点。
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)
)。
他们如何知道什么时候你必须打电话给超级电话,什么时候可以忽略电话?
通常,如果一个特殊的API方法对底层框架上下文的生命周期有着至关重要的意义,那么它总是会在API文档中明确地陈述和强调,比如Activity.onCreate()
API文档 。 而且,如果API遵循一个健壮的devise,则应该在项目编译时抛出一些exception来提醒消费者开发人员,并确保在运行时不会产生错误。
如果在API文档中没有明确说明这一点,那么消费者开发人员认为在覆盖API方法时不强制要求调用是非常安全的。 由消费者开发者决定是使用默认行为(调用super
方法)还是完全覆盖它。
如果条件允许的话(我喜欢开源软件),消费者开发者可以随时检查API源代码,看看这个方法是如何写在底层的。 例如,查看Activity.onCreate()
源和DefaultHandler.startElement()
源 。
你应该做的testing是:
“我是否希望为我完成这个方法的所有function,然后再做一些事情? 如果是,那么你想调用super()
,然后完成你的方法。 这对于“重要的”方法来说是正确的,例如onDraw()
,它在后台处理很多东西。
如果你只想要一些function(就像你将覆盖的大多数方法一样),那么你可能不想调用super()
。
那么哈维给了一个更好的答案..但你可能会知道super()
做什么时调用重写的方法…它广告你做了什么默认行为..
例如:
onDraw()
方法在视图类中被重写时,你说的super.onDraw()之前,它出现一旦视图完全绘制..所以这里调用super
是必要的,因为android有一些关键的重要事情要做(如onCreate())
但在同一时间
onLongClick()
当你重写这个你不想调用超级,因为它带来了EditText的选项列表或任何其他类似的视图..这就是基本的差异..你可以select离开它一些..但是其他方法像onCreate() , onStop()
你应该让操作系统处理它..
我没有清楚地说明你的问题,但如果你问为什么不调用super
方法:
有一个调用super
方法的原因:如果在父类中没有零参数构造函数,那么就不可能为它创build一个子类,所以要么在父类中保留一个没有参数的构造函数,要么需要使用argument(how much argument constructor you have used in super class)
在子类构造函数的顶部定义super()
调用语句。
我希望这有帮助。 如果没有,让我知道。
我实现了一个约束数组列表
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; } }
如果你看代码,它只是在实际让超类执行实际的元素添加到列表之前进行一些预检。 这说明了方法覆盖的两个重要原因之一:
- 扩展性,你想扩展什么超类可以做
- 你想通过多态性来添加特定行为的特殊性,例如在鸟类移动(飞行)和青蛙移动(跳跃)方式的移动语义的常见动物王国示例中对于每个子类都是特定的。