Java中类的加载顺序执行结果在类的实例化时非常重要,正确的理解和使用可以避免程序出现各种问题。以下是完整的攻略:
类的加载过程
首先,当程序需要使用某个类时,Java虚拟机会首先在内存中查找该类是否已经被加载(被其他类引用时可能已经被加载),如果没有被加载则开始类的加载过程。
类的加载过程分为以下几个步骤:
- 加载:虚拟机通过ClassLoader类加载器读取class文件中的二进制数据,并转化为相应的格式,然后在内存中生成对应的Class对象。
- 验证:虚拟机对加载的类进行验证,包括语法验证、字节码验证、符号属性验证、类引用验证。
- 准备:虚拟机为类的静态变量分配并初始化默认值(零值),如int类型的默认值为0,对象类型的默认值为null。
- 解析:虚拟机将类中的符号引用转化为直接引用,包括类、接口、字段、方法等。
- 初始化:执行类的静态代码块和静态变量赋值操作,初始化过程只会执行一次,即第一次实例化或第一次访问静态成员时。
类的加载顺序执行结果
了解了类的加载过程,接下来考虑类的加载顺序执行结果。类的加载顺序分为了以下四个阶段:
- 父类静态代码块和静态变量赋值操作:如果当前类有父类,先执行父类的静态代码块和静态变量赋值操作。
- 当前类的静态代码块和静态变量赋值操作:执行当前类的静态代码块和静态变量赋值操作。
- 父类实例变量赋值操作和构造函数:如果当前类有父类,则执行父类的实例变量赋值操作和构造函数。
- 当前类实例变量赋值操作和构造函数:执行当前类的实例变量赋值操作和构造函数。
根据上述的类的加载顺序,我们可以进行以下两个示例说明:
示例一:
public class SuperClass {
static {
System.out.println("SuperClass init!");
}
public static int value = 123;
}
public class SubClass extends SuperClass {
static {
System.out.println("SubClass init!");
}
}
public class Main {
public static void main(String[] args) {
System.out.println(SubClass.value);
}
}
输出结果如下:
SuperClass init!
123
分析:在执行SubClass.value时,由于SubClass并没有被实例化,因此不会触发SubClass的初始化过程。而此时虚拟机会静态查询类的常量,由于value是一个编译期常量,因此不会触发SuperClass的初始化过程。因此只会执行SuperClass的静态代码块和静态变量赋值操作,输出“SuperClass init!”和“123”。
示例二:
public class SuperClass {
static {
System.out.println("SuperClass init!");
}
public static int value = 123;
}
public class SubClass extends SuperClass {
static {
System.out.println("SubClass init!");
}
public static int value = 456;
}
public class Main {
public static void main(String[] args) {
System.out.println(SubClass.value);
}
}
输出结果如下:
SuperClass init!
SubClass init!
456
分析:在执行SubClass.value时,由于SubClass并没有被实例化,因此不会触发SubClass的初始化过程。由于value并不是一个编译期常量,因此会触发SuperClass的初始化过程。因此先执行SuperClass的静态代码块和静态变量赋值操作,输出“SuperClass init!”和“123”。接着执行SubClass的静态代码块和静态变量赋值操作,输出“SubClass init!”和“456”。最后输出SubClass.value的值,即“456”。
总结
了解类的加载过程和加载顺序能够帮助我们更好地理解Java程序的执行过程,以及在实际编程中如何避免出现各种问题。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java中类的加载顺序执行结果 - Python技术站