当前位置 : 主页 > 编程语言 > java >

Java类的加载及父类子类加载顺序

来源:互联网 收集:自由互联 发布时间:2023-03-22
点击​​ Mr.绵羊的知识星球 ​​解锁更多优质文章。 一、类的加载 1. 类加载 当程序要使用某些类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现对

点击 ​​Mr.绵羊的知识星球​​ 解锁更多优质文章。

一、类的加载

1. 类加载

当程序要使用某些类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现对这个类进行初始化。

    (1) 加载:将class文件连入内存,并为之创建一个class对象,任何类被使用时系统都会建立一个class对象

    (2) 连接:

    a. 验证:是否有正确的内存结构,并和其他类协调一致。

    b. 准备:负责为类的静态成员分配内存,并设置默认初始化值。

    c. 解析:将类的二进制数据中的符号引用替换为直接引用。

    (3) 初始化:

    a. 创建类的实例。

    b. 访问类的静态变量

    c. 调用类的静态方法

    d. 使用反射方式来强制创建某个类或者某个接口对应的class对象

    e. 初始化某个类的子类

    f. 直接使用java.exe命令来运行某个主类

2. 类加载器

    (1)概述:负责将class文件加载到内存当中,并为之生成对应的class对象

    (2)组成:

    a. Bootstrap ClassLoader 根类加载器:被称之为引导类加载器,负责java核心类的加载,比如System,String等。在JDK中JRE的lib目录下rt.jar文件中

    b. Extension ClassLoader 拓展类加载器:负责JRE的拓展目录中jar包的加载,在JDK中JRE的lib目录下的ext目录

    c. sysetm CalssLoader 系统类加载器:负责在JVM启动时加载来自java命令的class文件,以及classpath环境变量所指的jar包和类路径

二、父类和子类加载顺序

如果有人问我们父类和子类加载顺序,我们一定会说先加载父类后加载子类。但是如果给你两个类,你能准确地说出每个属性或者方法加载的顺序吗?

如果你答对了,那你应该属于那20%对类的加载有研究的人,其实大部分代码并不需要我们关心每个属性或者方法加载的顺序,所以这里也是往往让人忽略的。话不多说,上代码!

1. 案例(代码:​​git地址​​)

    (1) 父类

/** * Parent: 父类 * * @author wxy * @since 2023-01-08 */public class Parent { private static int serialNumber = 0; public static final String PUB_ATTR = printAndReturn("parent public static attr"); private static final String PRI_ATTR = printAndReturn("parent private static attr"); public Parent() { printAndReturn("parent construct"); } static { printAndReturn("parent static code block"); } { printAndReturn("parent anonymous inner class"); } private final String code = printAndReturn("parent member variable code"); /** * 打印str参数 * * @param str 需要打印的值 */ public static String printAndReturn(String str) { System.out.println(++serialNumber + ". " + str); return str; }}

    (2) 子类

/** * Child: 子类 * * @author wxy * @since 2023-01-08 */public class Child extends Parent { static { printAndReturn("child static code block"); } private static final String PRI_ATTR = printAndReturn("child private static attr"); public static final String PUB_ATTR = printAndReturn("child public static attr"); private final String code = printAndReturn("child member variable code"); public Child() { printAndReturn("child construct"); } { printAndReturn("child anonymous inner class"); }}

    (3) 测试方法

/** * 运行方法 * * @author wxy * @since 2023-01-08 */public class ClassLoadCase1Main { public static void main(String[] args) { /* 建议运行下面一次性仅运行一个方法比较清晰 */ createParent(); createChild(); createParentAndChild(); } private static void createParent() { /* 输出: 1. parent public static attr 2. parent private static attr 3. parent static code block 4. parent anonymous inner class 5. parent member variable code 6. parent construct */ /* 由上述输出可知: static修饰最先输出(谁在上面谁先执行, 一般都是public修饰在最上面)-> 匿名内部类和成员变量(谁在上面谁先执行)->最后是其构造方法 */ Parent parent = new Parent(); } private static void createChild() { /* 1. parent public static attr 2. parent private static attr 3. parent static code block 4. child static code block 5. child private static attr 6. child public static attr 7. parent anonymous inner class 8. parent member variable code 9. parent construct 10. child member variable code 11. child anonymous inner class 12. child construct */ /* 由上述输出可知加载是顺序: 加载父类static->加载子类static-> 加载父类匿名内部类成员变量及构造->加载子类匿名内部类成员变量及构造 */ Child child = new Child(); } private static void createParentAndChild() { /* 输出: ---parent--- 1. parent public static attr 2. parent private static attr 3. parent static code block 4. parent anonymous inner class 5. parent member variable code 6. parent construct ---child--- 7. child static code block 8. child private static attr 9. child public static attr 10. parent anonymous inner class 11. parent member variable code 12. parent construct 13. child member variable code 14. child anonymous inner class 15. child construct */ /* 创建两个对象或者多个对象时, static修饰的常量或者变量仅加载一次 (对比单独创建child和创建parent和child可知) */ System.out.println("---parent---"); Parent parent = new Parent(); System.out.println("---child---"); Child child = new Child(); }}

上一篇:阿里巴巴编码规范学习及应用
下一篇:没有了
网友评论