java类验证和装载顺序_Java子父类的加载和执行顺序

本帖最后由 Ralap军 于 2015-9-6 15:53 编辑

看了网友的子父类静态变量、静态代码块、构造代码块、构造方法的执行代码分析

现结合亮哥讲解的子父类加载执行流程,自己写了一个验证代码,望各位大神指点

首先,加载执行流程:

1、在栈内存空间中开辟一个空间给引用数据类型变量b用

2、加载父类.class字节码文件 ——> 父类的静态内容进方法区的静态区

——> 开辟静态成员变量空间,并显示初始化。执行静态代码块(静态成员变量与静态代码块的执行顺序与代码顺序有关)

3、加载子类.class字节码文件 ——> 子类的静态内容进方法区的静态区

——> 开辟静态成员变量空间,并显示初始化。执行静态代码块

4、通过new开辟子类在堆中的内存空间,为对象 ——> 子类的成员变量进堆中,并赋系统默认值(整型-0,浮点型-0.0,布尔型-false,字符型-'0u0000',引用型-null)

——> 把方法加载到方法区的非静态区(成员变量与构造代码块的执行顺序有代码顺序有关)

5、在堆中另开辟一个父类的内存空间,非对象 ——> 父类的成员变量进堆中,并赋系统默认值 ——> 把父类的方法加载到方法区的非静态区

6、对父类的成员变量进行显式初始化。执行父类构造代码块 ——> 父类的构造方法

7、把父类的内存空间标识给子类

8、对子类的成员变量进行显式初始化。执行子类构造代码块 ——> 子类的构造方法

9、把子类在堆中的地址值给栈中的变量b

简单来说:

父类静态内容 ——> 子类静态内容 ——> 父类构造代码块 ——> 父类构造方法 ——> 子类构造代码块 ——> 子类构造方法

/**

*打印类,仅用于打印

*/

class Print {

Print(Object s){

System.out.print(s+"\t");

}

}

/**

*父类A

*/

class A {

public static Print A_sv1 = new Print("A_sv1");

public Print A_cv1 = new Print("A_cv1");

public int num = 66;

public int num2 = 88;

static{

new Print("A_ss1");

}

public static Print A_sv2 = new Print("A_sv2");

{

new Print("A_cs1");

}

A(){

new Print("A_s");

show();

}

public Print A_cv2 = new Print("A_cv2");

{

new Print("A_cs2");

}

static{

new Print("A_ss2");

}

public void show(){

new Print(num);

new Print(num2);

}

}

/**

*子类B

*/

class B extends A {

public static Print B_sv1 = new Print("B_sv1");

public Print B_cv1 = new Print("B_cv1");

public int num = 99;

static{

new Print("B_ss1");

}

public static Print B_sv2 = new Print("B_sv2");

{

new Print("B_cs1");

}

B(){

new Print("B_s");

new Print(num);

}

public Print B_cv2 = new Print("B_cv2");

{

new Print("B_cs2");

}

static{

new Print("B_ss2");

}

public void show(){

new Print(num);

new Print(num2);

super.show();

}

}/**

*测试类Test

*/

class Test {

public static void main(String[] args){

B b = new B();

System.out.println();

System.out.println("-----------------------------");

B b2 = new B();

}

}复制代码根据上面的加载运行流程,应该可以分析出结果

其中,sv-静态成员变量,cv-普通成员变量,ss-静态代码块,cs-构造代码块,s-构造方法

1、B b表示b是B的引用。将在栈内存中开辟空间给b用

2、加载B的父类A的字节码文件,执行静态内容。将打印:A_sv1  A_ss1  A_sv2  A_ss2

3、加载B类的字节码文件,执行静态内容。将打印:B_sv1  B_ss1  B_sv2  B_ss2

4、new B()代表创建B类的对象,将在堆中开辟空间。

成员变量赋系统默认值:B_cv1=null,num=0,B_cv2=null。同时方法show()进方法区

5、堆中另给父类A开辟一个内存空间。

成员变量赋系统默认值:A_cv1=null,num=0,num2=0,A_cv2=null。同时方法show()进方法区

6、父类A成员变量显示初始化num=66,num2=88,同时执行构造代码块,将打印:A_cv1  A_cs1  A_cv2  A_cs2

7、执行父类A的构造方法,将打印:A_s

执行show()方法,注意,此时show()已经被子类B重写,

根据就近原则,num为B类中的成员变量,num2是从父类A中继承过来的,所以打印:0  88

再执行父类的show()方法,此时num和num2都为父类中的,且已被初始化,所以打印:66 88

8、把父类的内存空间标识给子类B的对象

9、B类的成员变量显示初始化num=99,同时执行构造代码块,将打印:B_cv1  B_cs1  B_cv2  B_cs2

10、执行B类的构造方法,根据就近原则,此时num为99,所以,将打印:B_s  99

11、把在堆中创建的B类对象的地址值赋给b

12、B b2 = new B()。因为已经加载过子父类的字节码,所以静态内容不再执行,方法也不用再加载到方法区。重复从第4步开始执行

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值