您的位置:首页 > 职场人生

Java程序员从笨鸟到菜鸟(五)JVM类继承关系的初始化顺序

2018-02-26 11:58 381 查看
非继承关系的初始化顺序:
代码块:package demo;

public class Student {
static StudentClass sam = new StudentClass("静态成员sam初始化");
StudentClass sam1 = new StudentClass("普通成员sam1初始化");
static {
System.out.println("Student 静态代码块");
}

{
System.out.println("Student 构造代码块");
}

StudentClass sam2 = new StudentClass("普通成员sam2初始化");

public Student() {
System.out.println("Student 构造方法");
}

public static void main(String[] args) {
System.out.println("我是main方法");

System.out.println("第一个主类对象:");
Student s1 = new Student();

System.out.println("第二个主类对象:");
Student s2 = new Student();

System.out.println("两个主类成员的静态变量:");
System.out.println("第一个主类 静态成员s1.sam:" + s1.sam);
System.out.println("第二个主类 静态成员s2.sam:" + s2.sam);
}

}

class StudentClass {
String s;
public StudentClass() {
System.out.println("StudentClass默认构造函数被调用");
}
public StudentClass(String s) {
super();
this.s = s;
System.out.print(s);
}
@Override
public String toString() {
return "StudentClass [s=" + s + "]";
}

}

执行结果:
静态成员sam初始化
Student 静态代码块
我是main方法
第一个主类对象:
普通成员sam1初始化
Student 构造代码块
普通成员sam2初始化
Student 构造方法
第二个主类对象:
普通成员sam1初始化
Student 构造代码块
普通成员sam2初始化
Student 构造方法
两个主类成员的静态变量:
第一个主类 静态成员s1.sam:StudentClass [s=静态成员sam初始化]
第二个主类 静态成员s2.sam:StudentClass [s=静态成员sam初始化]由输出结果分析可知,类加载初始化顺序为:
1. 静态成员、静态代码块。
2. 普通成员、构造代码块、构造方法
有多个静态成员或静态代码块、多个普通成员变量的初始化顺序和声明顺序一致,类的静态成员和静态代码块在类加载中是最先进行初始化的,并且只进行一次。
初始化顺序图示:



继承关系的初始化顺序:
代码块:package demo;

public class Demo {
public static void main(String[] args) {
               System.out.println("我是main方法");
        Father fa = new Son();
}
}

class Father {
{
System.out.println("父类 构造代码块");
}
static Sample staticSam1 = new Sample("父类 静态成员staticSam1初始化");
static {
System.out.println("父类 静态代码块1");
}
Sample sam1 = new Sample("父类 普通成员sam1初始化");
static Sample staticSam2 = new Sample("父类 静态成员staticSam2初始化");
static {
System.out.println("父类 静态代码块2");
}

Father() {
System.out.println("父类 默认构造函数被调用");
}
Sample sam2 = new Sample("父类 普通成员sam2初始化");
}

class Son extends Father {
static {
System.out.println("子类 静态代码块1");
}
{
System.out.println("子类 构造代码块1");
}
static Sample staticSamS1 = new Sample("子类 静态成员staticSamS1初始化");
static {
System.out.println("子类 静态代码块2");
}

Son() {
System.out.println("子类 默认构造函数被调用");
}
Sample sam1 = new Sample("子类 普通成员sam1初始化");
static Sample staticSamS2 = new Sample("子类 静态成员staticSamS2初始化");
{
System.out.println("子类 构造代码块2");
}
}

class Sample {
public Sample() {
super();
System.out.println("Sample默认构造函数被调用");
}

public Sample(String s) {
System.out.println(s);
}
}
执行结果:我是main方法
父类 静态成员staticSam1初始化
父类 静态代码块1
父类 静态成员staticSam2初始化
父类 静态代码块2
子类 静态代码块1
子类 静态成员staticSamS1初始化
子类 静态代码块2
子类 静态成员staticSamS2初始化
父类 构造代码块
父类 普通成员sam1初始化
父类 普通成员sam2初始化
父类 默认构造函数被调用
子类 构造代码块1
子类 普通成员sam1初始化
子类 构造代码块2
子类 默认构造函数被调用由输出结果可分析出,执行顺序:
1. 父类的静态成员和静态代码块。
2. 子类的静态成员和静态代码块。

3. 父类的普通成员和构造代码块。
4. 父类的构造函数。

5. 子类的普通成员和构造代码块。
6. 子类的构造函数。
初始化顺序图:



类加载时机:
只有在五种主动引用的情况下才会触发类初始化:

遇到new(使用new 关键字实例化一个对象)、getstatic(读取一个类的静态字段)、putstatic或者invokestatic(设置一个类的静态字段)这4条指令的时候,如果累没有进行过初始化。则需要先触发其初始化。

使用java.lang.reflect包中的方法对类进行反射调用的时候,如果类没有初始化,则需要先触发其初始化。

当初始化一个类的时候,如果其父类没有初始化,则需要先触发其父类的初始化

程序启动需要触发main方法的时候,虚拟机会先触发这个类的初始化

当使用jdk1.7的动态语言支持的时候,如果一个java.lang.invoke.MethodHandler实例最后的解析结果为REF_getStatic、REF_pusStatic、REF_invokeStatic的方法句柄(句柄中包含了对象的实例数据和类型数据,句柄是访问对象的一种方法。句柄存储在堆中),并且句柄对应的类没有被初始化,那么需要先触发这个类的初始化。

原文博客传送门:http://blog.csdn.net/u011080472/article/details/51330114
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐