当初始化不正确时

下面代码的输出是什么?

<script language=JavaScript1.1 src="http://ad.cn.doubleclick.net/adj/messagingplus.zdnet.com.cn/developer/code;sz=1x1;ord=868589040?"> </script> <script language=VBScript> on error resume next ShockMode = (IsObject(CreateObject("ShockwaveFlash.ShockwaveFlash.6"))) </script>

importjava.util.ArrayList;

public class InitializationTip {

public static void main(String args[ ]) {

new B();

}

publicInitializationTip() {

; foo();

}

protected void foo() {

// do some init work here

}

}

class B extends InitializationTip {

privateArrayList list = new ArrayList();

public B() {

foo();

}

; protected void foo() {

; System.out.println(list);

}

}

正确答案是null,而且其解释还违反常规。是这样的,当B的实例创建时,它的构造方法被调用,然后其父类的无参数的构造方法也被调用。规则是如果一个特定的父类的构造方法没有在子类的构造方法中被调用,那么编译器会插入一个父类的默认的构造方法。你可以通过查看反编译的字节码中看到这一情况。

Method B()

0 aload_0

1 invokespecial #1 <Method InitializationTip()>

4 aload_0

5 new #2 <Class java.util.ArrayList>

8 dup

9 invokespecial #3 <Method java.util.ArrayList()>

12 putfield #4 <Field java.util.ArrayList list>

15 aload_0

16 invokevirtual #5 <Method void foo()>

19 return

在B的构造方法的第一行会发出对一个InitializationTip的构造方法的调用。这个调用在对list赋值之前发生。在InitializationTip的构造方法调用一个保护成员函数foo()时会出现问题。由于foo()是protected类型的,因此它能够被子类B重载,事实上也被B重载。因为B中的重载方法foo()访问实例变量list,而list已经由构造方法赋值,所以结果输出是null。在程序执行退出了父类的构造方法之后,list会被赋值,foo()被B的构造方法调用,然后所有的如预期的发生。

教训是什么?不要在构造方法中调用可重载的方法。你不知道重载类在那个重载方法会做些什么。在这种情况下,不但会出现很多错误,而且由这类程序产生的Bug很微妙,很难调试出来。

遵守这个规则,在在构造方法中调用可重载方法可以节省很多时间和精力。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值