您的位置:首页 > 编程语言 > Java开发

java继承中类的初始化过程

2017-09-24 11:59 274 查看
我们先看代码,然后再分析。

package se;

public class Beetle extends Insect{
int k = prt("Beetle.k initialized");
Beetle(){
prt("k="+k);
prt("j="+j);
}
static int x2=prt("static Beetle.x2 initialized");
static{
System.out.println("Beetle");
}
static int prt(String s){
System.out.println(s);
return 63;
}
public static void main(String[] args) {
prt("Beetle constructor");
Beetle b = new Beetle();
}
}
class Insect{
int i=9;
int j;
Insect(){
j=prt("i="+i+",j="+j);
}
static{
System.out.println("Insect");
}
static int xl = prt("static Insect.x1 initialized");
static int prt(String s){
System.out.println(s);
return 47;
}
}


输出:

Insect

static Insect.x1 initialized

static Beetle.x2 initialized

Beetle

Beetle constructor

i=9,j=0

Beetle.k initialized

k=63

j=47

java中类的class文件只有在初次使用时才会加载到jvm中。类的静态成员、静态代码块和静态方法会随着类的加载而加载,并且只加载一次。初次使用包含两种情况:

静态调用。就是“类名.静态成员”或“类名.静态方法”。

使用构造器。

上面的程序先从Beetle类的main方法形如执行(可以理解成jvm执行Beetle.main(),也就是静态调用),于是类加载器开始加载Beetle类的字节码文件。在此过程中,编译器发现了“extends”关键字,即Beetle类还继承了Insect类,于是接着加载Insect类。上面的例子包含静态初始化和对象初始化两个过程。首先是开始Insect类(父类)的静态初始化。

static{
System.out.println("Insect");
}
static int xl = prt("static Insect.x1 initialized");


静态代码块和静态成员的执行顺序由书写顺序决定,所以开始输出:

Insect

static Insect.x1 initialized

于是父类(Insect)的静态初始化结束。紧接着,类加载器继续加载子类(Beetle)的静态初始化,输出:

static Beetle.x2 initialized

Beetle

现在父类和子类的静态初始化操作全部完成。以上步骤仅仅是jvm试图调用Beetle类的main方法的准备动作,并没有真正执行main方法中的代码,现在开始真正执行:

public static void main(String[] args) {
prt("Beetle constructor");
Beetle b = new Beetle();
}


第一行输出

Beetle constructor

这没有疑问,显然易见的事。第二行开始实例化Beetle类,即开始对象的初始化了。我们看看Beetle类的构造器:

Beetle(){
prt("k="+k);
prt("j="+j);
}


它等价于:

Beetle(){
supper();
k=prt("Beetle.k initialized");
prt("k="+k);
prt("j="+j);
}


也就是在构造Beetle对象时需要先构造父类(Insect)对象。于是jvm又去执行Insect类的构造器:

Insect(){
j=prt("i="+i+",j="+j);
}


里面使用到了成员变量,其实成员变量的初始化也是放在构造器中的,也就是Insect类中对象成员属性定义等价于:

class Insect{
int i;
int j;
Insect(){
super();
i=9;
j=0;
j=prt("i="+i+",j="+j);
}
//其他部分省略
}


这样,实例化Insect对象时会输出:

i=9,j=0

注意,j的值,因为静态方法虽然能被子类继承但不能被重写,所以j的值是47而不是63,Insect类对象初始化完成。然后jvm回到Beetle构造器继续运行,完成Insect类的对象初始化,依次输出:

k=63

j=47

类初始华过程总结:

父类静态初始化

子类静态初始化

父类对象初始化

子类对象初始化

其他总结:

当类第一次被静态调用或是通过构造器调用时会被加载到内存

对象的成员属性初始化是在构造器中完成的(紧跟在supper()语句后面)

静态方法可以被继承,但是不能被重写,因为静态方法属于类,而不是属于对象
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息