JAVA 构造函数 调用 多态的成员方法 的问题


在构造器中调用多态方法进行初始化,也许会产生不可预料的结果。

[java]  view plain copy
  1. import java.io.FileWriter;  
  2. import java.io.IOException;  
  3.   

  4. class Shap {  
  5.     void set() {  
  6.         try {  
  7.             System.out.println("Shap.set()");  
  8.             FileWriter fw = new FileWriter("hello.txt"true);  
  9.             String s = "Shap.set\n";  
  10.             fw.write(s);  
  11.             fw.flush();  
  12.             fw.close();  
  13.         } catch (IOException e) {  
  14.             System.out.println("Shap.set e=" + e.getMessage());  
  15.         }  
  16.     }  
  17.   
  18.     Shap() {  
  19.         System.out.println("Shap().in=");  
  20.         set();  
  21.         System.out.println("Shap().out=");  
  22.     }  
  23. }  
  24.   
  25. class Line extends Shap {  
  26.     int counter = 9;  
  27.   
  28.     void set() {  
  29.         try {  
  30.             System.out.println("Line.set() counter="+counter);  
  31.             FileWriter fw = new FileWriter("hello.txt"true);  
  32.             String s = "Line.set counter=" + counter+"\n";  
  33.             fw.write(s);  
  34.             fw.flush();  
  35.             fw.close();  
  36.         } catch (IOException e) {  
  37.             System.out.println("Line.set e=" + e.getMessage());  
  38.         }  
  39.     }  
  40.   
  41.     Line() {  
  42.         System.out.println("Line().in=" + counter);  
  43.         set();  
  44.         System.out.println("Line().out=" + counter);  
  45.     }  
  46. }  
  47.   
  48. public class Mom {  
  49.     public static final void main(String[] args) {  
  50.         Line t = new Line();  
  51.     }  
  52. }  

预料中hello.txt中内容应该是这样:

[html]  view plain copy
  1. Shap.set  
  2. Line.set counter=9  


实际hello.txt文件中内容如下:

[html]  view plain copy
  1. Line.set counter=0  
  2. Line.set counter=9  


原因:

《Thinking in java》中指出,这是由于构造器初始化顺序的问题:

初始化的实际过程是:

1、在其他任何事物发生之前,将分配给对象的存储空间初始化成二进制零。
2、调用基类构造器。这个步骤会不断的反复递归下去,首先是构造这种层次结构的根,然后是下一层导出类,等等。直到最低层的导出类。此时,调用被重载的<pre name="code" class="html">set()方法(是的,是在调用Line构造器之前调用的),由于步骤(1)的缘故,我们此时会发现counter的值为0。
3、按照声明的顺序调用成员的初始化代码。在类的内部,初始化的顺序是先“静态”,(如果它们尚未因前面的对象创建过程而被初始化),后“非静态”。而非静态变量定义的顺序决定了初始化的顺序。即使变量定义散布于方法定义之间,它们仍旧会在任何方法(包括构造器)被调用之前得到初始化。
4、调用导出类的构造器主体。


结论:
如果你要在构造器中调用一个方法时,将该方法声明为private。
对于这个规则是需要一些说明的,假使你的父类构造器中要调用一个非静态方法,而这个方法不是private的又被子类所重载,这样在实际创建子类的过程中递归调用到了父类的构造器时,父类构造器对这个方法的调用就会由于多态而实际上调用了子类的方法当这个子类方法需要用到子类中实例变量的时候,就会由于变量没有初始化而出现异常(至于为什么子类中的实例变量没有初始化可以参考上边的实例初始化过程),这是Java不想看到的情况。而当父类构造器中调用的方法是一个private方法时,多态就不会出现,也就不会出现父类构造器调用子类方法的情况,这样可以保证父类始终调用自己的方法,即使这个方法中调用了父类中的实例变量也不会出现变量未初始化的情况(变量初始化总是在当前类构造器主体执行之前进行)。

可以参见本博的另外一篇文章

http://blog.csdn.net/bigtree_3721/article/details/50364675


  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值