登录社区:用户名: 密码: 忘记密码 网页功能:加入收藏 设为首页 网站搜索  

文档

下载

图书

论坛

安全

源码

硬件

游戏
首页 信息 空间 VB VC Delphi Java Flash 补丁 控件 安全 黑客 电子书 笔记本 手机 MP3 杀毒 QQ群 产品库 分类信息 编程网站
  立华软件园 - 安全技术中心 - 技术文档 - JAVA 技术文章 | 相关下载 | 电子图书 | 攻防录像 | 安全网站 | 在线论坛 | QQ群组 | 搜索   
 安全技术技术文档
  · 安全配制
  · 工具介绍
  · 黑客教学
  · 防火墙
  · 漏洞分析
  · 破解专题
  · 黑客编程
  · 入侵检测
 安全技术工具下载
  · 扫描工具
  · 攻击程序
  · 后门木马
  · 拒绝服务
  · 口令破解
  · 代理程序
  · 防火墙
  · 加密解密
  · 入侵检测
  · 攻防演示
 安全技术论坛
  · 安全配制
  · 工具介绍
  · 防火墙
  · 黑客入侵
  · 漏洞检测
  · 破解方法
 其他安全技术资源
  · 攻防演示动画
  · 电子图书
  · QQ群组讨论区
  · 其他网站资源
最新招聘信息

构造方法的初始化顺序
发表日期:2004-07-30作者:[转贴] 出处:  

构造方法的初始化顺序

翻译:Cherami

email:cherami@163.net

原文: http://java.sun.com/jdc/TechTips/2000/tt1205.html

 

想像一下你正在用java写程序,并且用下面的代码初始化类 A B 的对象:

    class A {

        int a = f();

        int f() {

            return 1;

        }

    }  

    class B extends A {

        int b = a;

        int f() {

            return 2;

        }

    }   

    public class CtorDemo1 {

        public static void main(String args[]) {

            B bobj = new B();

            System.out.println(bobj.b);

        }

    }

 

现在,好像很明显的当初始化完成后,bobj.b的值将是1。毕竟,类B中的b 的值是用类A中的a的值初始化的,而a 是用f 的值初始化的,而它的值为1,对吗?

实际上, bobj.b 的值是2,要知道为什么需要知道对象初始化的问题。

当一个对象被创建时,初始化是以下面的顺序完成的:

1.         设置成员的值为缺省的初始值 (0, false, null)

2.         调用对象的构造方法 (但是还没有执行构造方法体)

3.         调用父类的构造方法

4.         使用初始化程序和初始块初始化成员

5.         执行构造方法体

 

看看在实际中是如何一步一步完成的,看看下面的例子:

    class A {

        A() {

            System.out.println("A.A called");

        }

    }

   

    class B extends A {

        int i = f();

        int j;

   

        {

            j = 37;

            System.out.println("initialization block executed");

        }

   

        B() {

            System.out.println("B.B called");

        }

   

        int f() {

            System.out.println("B.f called");

            return 47;

        }

    }

   

    public class CtorDemo2 {

        public static void main(String args[]) {

            B bobj = new B();

        }

    }

 

程序的输出是:

 

    A.A called

    B.f called

    initialization block executed

    B.B called

 

B 的构造方法被调用,但是最先做的事情是隐含的调用父类的构造方法。父类必须自己负责初始化它自己的状态而不是让子类来做。

然后B对象的成员被初始化,这包含一个对B.f 的调用和包围在{}中的初始块的执行。最后B的构造方法体被执行。

你可能会问“什么是对父类的构造方法的隐含调用”。这意味着如果你的构造方法的第一行不是下面内容之一:

 

   super();

 

   super(args);

 

   this();

 

   this(args);

 

则有下面的调用:

 

   super();

 

提供给构造方法的第一行。

 

如果类没有构造方法呢?在这种情况下,一个缺省的构造方法(也叫"无参构造方法")java编译器自动生成。缺省构造方法只有在类没有任何其它的构造方法时才产生。

更深入的明白这个,假设在文件A.java中有这样的代码:

 

    public class A {

        public static void main(String args[]) {

            A aref = new A();

        }

    }

 

如果你想编译然后列出A.class 中的字节码,输入下面的内容:

 

    $ javac A.java

    $ javap -c -classpath . A

 

输出:

 

    Compiled from A.java

    public class A extends java.lang.Object {

        public A();

        public static void main(java.lang.String[]);

    }

   

    Method A()

       0 aload_0

       1 invokespecial #1 <Method java.lang.Object()>

       4 return

   

    Method void main(java.lang.String[])

       0 new #2 <Class A>

       3 dup

       4 invokespecial #3 <Method A()>

       7 astore_1

       8 return

 

main 中,注意对 A 的构造方法的调用(就是invokespecial ),以及A的构造方法中产生的类似的对Object 构造方法的调用。

如果父类没有缺省构造方法,你必须明确使用"super(args)"调用父类的某个构造方法,例如,下面是一个错误的用法:

 

    class A {

        A(int i) {}

    }

 

    class B extends A {}

 

在上面的情况下, A 没有缺省的构造方法,但是B的构造方法必须调用A的某个构造方法。

让我们来看看初始化的另一个例子:

 

    class A {

        A() {

            System.out.println("A.A called");

        }

        A(int i) {

            this();

            System.out.println("A.A(int) called");

        }

    }

   

    class B extends A {

        int i = f();

        int j;

   

        {

            j = 37;

            System.out.println("initialization block executed");

        }

   

        B() {

            this(10);

            System.out.println("B.B() called");

        }

   

        B(int i) {

            super(i);

            System.out.println("B.B(int) called");

        }

   

        int f() {

            System.out.println("B.f called");

            return 47;

        }

    }

   

    public class CtorDemo3 {

        public static void main(String args[]) {

            B bobj = new B();

        }

    }

 

程序的输出是:

 

    A.A called

    A.A(int) called

    B.f called

    initialization block executed

    B.B(int) called

    B.B() called

 

这个例子明确使用super() this() 调用。this()调用是调用同一个类中的另一个构造方法;这个方法被称为“显式构造方法调用”。当那样的构造方法被调用,它将执行通常的super() 过程以及后续的操作。这意味着A.A 的方法体在A.A(int)之前执行,而这两个都在B.B(int) B.B 前执行。

如果返回第一个例子,你就可以回答为什么打印的是2而不是1B 没有构造方法,因此生成一个缺省构造方法,然后它调用super(),然后调用A 产生的缺省构造方法。

然后A中的成员被初始化,成员a 被设置为方法f()的值,但是因为B 对象正被初始化,f() 返回值2。换句话说,调用的是B中的f()方法。

A产生的构造方法体被执行,然后B的成员被初始化,而b 被赋予值a,也就是2。最后,B的构造方法被执行。

最后一个例子说明了第一个例子的一个小小的变异版本:

 

    class A {

        int a = f();

        int f() {

            return 1;

        }

    }

   

    class B extends A {

        int b = 37;

        int f() {

            return b;

        }

    }

   

    public class CtorDemo4 {

        public static void main(String args[]) {

            B bobj = new B();

            System.out.println(bobj.a);

            System.out.println(bobj.f());

        }

    }

 

程序的输出是:

 

    0

    37

 

你可能会期望输出的两个值bobj.a bobj.f()是一样的,但是正如你看到的他们不一样。这是正确的,即使是在a是从Bf方法中初始化的并且打印的是a B f 方法的值。

这儿的问题是当a通过对Bf方法调用而初始化,而该方法返回成员b的值,而该成员还没有被初始化。因为这个,b的值就是刚开始的初始值0

这些例子解释了编程中重要的一点?D?D在对象的构造阶段调用可重载的方法是不明智的。


 

我来说两句】 【发送给朋友】 【加入收藏】 【返加顶部】 【打印本页】 【关闭窗口
中搜索 构造方法的初始化顺序

 ■ [欢迎对本文发表评论]
用  户:  匿名发出:
您要为您所发的言论的后果负责,故请各位遵纪守法并注意语言文明。

最新招聘信息

关于我们 / 合作推广 / 给我留言 / 版权举报 / 意见建议 / 广告投放 / 友情链接  
Copyright ©2001-2006 Lihuasoft.net webmaster(at)lihuasoft.net
网站编程QQ群   京ICP备05001064号 页面生成时间:0.00207