类的装载
在java中只有类被正真的初始化时,或是有静态成员被使用时,类才会被真正的加载。
类的初始化
首先说一下单个类的初始化过程。当一个类的实例被创建时,对于这个类的背后会有哪些神秘的动作发生呢?已前我有提过,类的静态成员会在第一次被使用,或它所在类型被实例化时赋初值,即当一个类被实例化成功前会先为所有的静态变量赋初值,接下来会为所有的非静态成员变量赋上初始值或默认值,最后构造器被调用,实例化过程完成。在这中间需要注意的地方,无论是静态成员属性或非静态成员属性的引用都是有先后顺序的,注:方法的调用受限制。如下面的代码是通不过的。
static int i = j;//这里有问题
static int j = 3;
int k = l;//这里有问题
int l = 3;
从中也可以看出java的初化化初值操作是从上到下的。
说完了单个类的实例化过程,那存在继承关系时实例化过程又是怎样呢?总结上来说,存在继承的情况当实例化子类时,首先会有一个追溯祖先的过程,当追溯到最老的祖先类型后开始对祖先类型的静态成功与非静态成员做初始化操作,并调它的构造器,类似于单类型的实例过程。接下来依次对下级类型做同样的操作,直到最下级类型的构造器被调用。以下代码及结果可以说明这个过程。
public class People {
static int staticValue = staticMethod();
private int i=3;
public static int staticMethod(){
System.out.println("People.staticMethod()");
return 2;
}
public People() {
System.out.println("People");
System.out.println("People-i>>"+i);
call1();
}
public People(String name){
}
public void call1() {
this.m1();
this.m2();
}
public void m1() {
System.out.println("People.m1()");
}
public void m2() {
System.out.println("People.m2()");
}
public void error(){
System.out.println("People error info"+this.i);
}
}
子类代码
public class Hello2 extends People{
static int staticValue = staticMethod();//初始化时可以打印出信息
public static int staticMethod(){
System.out.println("Hello2.staticMethod()");
return 1;
}
int second = 3;//试着交换一下顺序
int first = second;
private int i = 5;//覆盖父类的i
public Hello2() {
super();//对构造器的调用必须写在第一行,而且只能在构造器中调其它构造器
System.out.println("HELLO2");
System.out.println("HELLO2-i>>"+i);//注意
this.error();
}
public void error(){
System.out.println("Hello2 error info"+this.i);
super.error();
}
public void printe(){
int a =3;
}
public void m1() {
System.out.println("Hello2.m1()");
}
public void m2() {
System.out.println("Hello2.m2()");
}
}
new Hello2()后的结果
People.staticMethod()
Hello2.staticMethod()
People
People-i>>3
Hello2.m1()
Hello2.m2()
HELLO2
HELLO2-i>>5
Hello2 error info5
People error info3
针对上面的代码我还得说点,我们应注意的地方,如果在子类的构造器中没有明确认指出supe()这样类似的调用父类构造器的方法,那么java会自动调用父类的默认构造器,但是如果父类没有默认构造器,子类中又没有明确调用父类相应构造器的代码将会编译不过。 限使有手动调用父构造器的代码,这句代码也只能写在子构造器的并且必需做为第一行代码,否则编译不会通过。