找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 712|回复: 3

[java]初始化与类的装载

[复制链接]
发表于 2008-8-17 02:20:55 | 显示全部楼层 |阅读模式

初始化与类的装载

在较传统的编程语言中,程序启动的时候都是一次装载所有的东西,然后进行初始化,接下来再开始执行。这些语言必须仔细的控制初始化的过程,这样static 数据的初始化才不至于会产生问题。就拿C++为例,如果一个static 数据要依赖另一个static 的数据,而它又没有初始化的话,问题就来了。

Java 采用了一种新的装载模式,因此没有这种问题。Java 的所有东西都是对象,因此很多事情都变得简单了,这就是一例。下一章你还会学的更具体。编译之后每个类都保存在它自己的文件里。不到需要的时候,这个文件是不会装载的。总之你可以说“类的代码会在它们第一次使用的时候装载”。类的装载通常都发生在第一次创建那个类的对象的时候,但是访问 static 数据或static 方法的时候也会装载。

第一次使用static 数据的时候也是进行初始化的时候。装载的时候,static 对象和static 代码段会按照它们字面的顺序(也就是在程序中出现的顺序)进行初始化。当然static 数据只会初始化一次。

继承情况下的初始化

了解一下包括继承在内的初始化的过程将是非常有益的,这样就能有个总体的了解。看看下面这段代码:

//: c06:Beetle.java

// The full process of initialization.

import com.bruceeckel.simpletest.*;

 

class Insect {

  protected static Test monitor = new Test();

  private int i = 9;

  protected int j;

  Insect() {

    System.out.println("i = " + i + ", j = " + j);

    j = 39;

  }

  private static int x1 =

print("static Insect.x1 initialized");

  static int print(String s) {

    System.out.println(s);

    return 47;

  }

}

 

public class Beetle extends Insect {

  private int k = print("Beetle.k initialized");

  public Beetle() {

    System.out.println("k = " + k);

    System.out.println("j = " + j);

  }

  private static int x2 =

    print("static Beetle.x2 initialized");

  public static void main(String[] args) {

    System.out.println("Beetle constructor");

    Beetle b = new Beetle();

    monitor.expect(new String[] {

      "static Insect.x1 initialized",

      "static Beetle.x2 initialized",

      "Beetle constructor",

      "i = 9, j = 0",

      "Beetle.k initialized",

      "k = 47",

      "j = 39"

    });

  }

} ///:~

 

当你用Java 运行 Beetle 的时候,第一件事就是访问了Beetel.main( )(这是一个 static 方法),于是装载器(loader)就会为你寻找经编译的Beetle 类的代码(也就是Beetle.class 文件)。在装载的过程中,装载器注意到它有一个基类(也就是extends 所要表示的意思),于是它再装载基类。不管你创不创建基类对象,这个过程总会发生。(试试看,把创建对象的那句注释掉,看看会有什么结果。) 如果基类还有基类,那么这第二个基类也会被装载,以此类推。下一步,它会执行“根基类(root base class)(这里就是Insect) static 初始化,然后是下一个派生类的static 初始化,以此类推。这个顺序非常重要,因为派生类的“静态初始化(即前面讲的 static 初始化)”有可能要依赖基类成员的正确初始化。

现在所有必要的类都已经装载结束,可以创建对象了。首先,对象里的所有的primitive 都会被设成它们的缺省值,而reference 也会被设成null——这个过程是一瞬间完成的,对象的内存会被统一地设置成“两进制的零(binary zero)”。然后调用基类的构造函数。调用是自动发生的,但是你可以使用 super 来指定调用哪个构造函数(也就是 Beetle( )构造函数所做的第一件事)。基类的构造过程以及构造顺序,同派生类的相同。基类构造函数运行完毕之后,会按照各个变量的字面顺序进行初始化。最后会执行构造函数的其余部分。

 

 

Thinking in Java》第六章最后一节

 


在类的内部,变量定义的先后顺序决定了初始化的顺序。即使变量定义散布于方法定义之间,他们仍旧会在任何方法(包括构造器)被调用之前得到初始化。

初始化的顺序时先“静态”,(如果它们尚未因前面的对象创建过程而被初始化),后“非静态”。

 

先找到public class,初始化public class内的静态变量,然后是非静态变量,然后方法。

Static在类加载时初始化,非静态在类构造时初始化。

 

SCJP考试指南

 

我的总结:

父类静态块(包括静态成员变量)==>子类静态块(包括静态成员变量)==>父类非静态块(包含非静态成员变量)==>父类构造器==>子类非静态块(包含非静态成员变量)==>子类构造器

先静态,普通

先父类,后子类

 

 

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表