Java类加载机制的理解浅析

从今日头条上看到了一道考察Java类加载机制的基础题,感觉不错,只是没有看到答案,所以自己手动敲了一下代码,现将其整理如下:

题目

1.父类A、子类B(继承自父类A)、程序入口类C
public class HelloA {

    public HelloA() {
        System.out.println("父类A 构造方法");
    }
    
    { System.out.println("父类A 构造代码块"); }
    
    static { System.out.println("父类A 静态方法"); }
}

public class HelloB extends HelloA {
    
    public HelloB() {
        System.out.println("子类B 构造方法");
    }
    
    { System.out.println("子类B 构造代码块"); }
    
    static { System.out.println("子类B 静态方法"); }
}

//程序入口类
public class HelloC {

    public static void main(String[] args){
        
        System.out.println("-----------main start-----------");
        new HelloB();
        System.out.println("-----------main end-------------");
    }
}

运行结果如下:

-----------main start-----------
父类A 静态方法
子类B 静态方法
父类A 构造代码块
父类A 构造方法
子类B 构造代码块
子类B 构造方法
-----------main end-------------

2.父类A、子类B(继承自父类A),程序入口在B类中

public class HelloA {

    public HelloA() {
        System.out.println("HelloA");
    }
    
    { System.out.println("I'm A class."); }
    
    static { System.out.println("Static A"); }
}

public class HelloB extends HelloA {
    
    public HelloB() {
        System.out.println("HelloB");
    }
    
    { System.out.println("I'm B class."); }
    
    static { System.out.println("Static B"); }

    public static void main(String[] args){
        
        System.out.println("-----------main start-----------");
        new HelloB();
        System.out.println("-----------main end-------------");
    }
}

运行结果如下:

父类A 静态方法
子类B 静态方法
-----------main start-----------
父类A 构造代码块
父类A 构造方法
子类B 构造代码块
子类B 构造方法
-----------main end-------------

3.父类A、子类B(继承自父类A),程序入口在A类中

public class HelloA {

    public HelloA() {
        System.out.println("HelloA");
    }
    
    { System.out.println("I'm A class."); }
    
    static { System.out.println("Static A"); }

    public static void main(String[] args){
        
        System.out.println("-----------main start-----------");
        new HelloB();
        System.out.println("-----------main end-------------");
    }
}

public class HelloB extends HelloA {
    
    public HelloB() {
        System.out.println("HelloB");
    }
    
    { System.out.println("I'm B class."); }
    
    static { System.out.println("Static B"); }
}

运行结果如下:

父类A 静态方法
-----------main start-----------
子类B 静态方法
父类A 构造代码块
父类A 构造方法
子类B 构造代码块
子类B 构造方法
-----------main end-------------

简单总结:

1.实例化子类的时候
(1)若此类未被加载过,首先加载是父类的类对象,然后加载子类的类对象,接着实例化父类,最后实例化子类;
(2)若此类被加载过,不再加载父类和子类的类对象。

2.接下来是加载顺序
(1)当加载类对象时,首先初始化静态属性,然后执行静态块;
(2)当实例化对象时,首先执行构造块(直接写在类中的代码块),然后执行构造方法。
(3)如果存在多个静态块,各静态块之间执行的顺序按代码先后;如果存在多个静态属性,各静态属性初始化的顺序按代码先后。
(4)属性、构造块(也就是上面的实例块)、构造方法之间的执行顺序(但构造块一定会在构造方法前执行),也是按代码的先后顺序。
3.还要注意入口函数位置、类的执行顺序;

本人java小白,有错误还请指出,共同学习...

参考资料:
(1)Java---类加载机制,构造方法,静态变量,(静态)代码块,父类,变量加载顺序
https://www.cnblogs.com/chihirotan/p/6043442.html
(2)一道网易Java工程师面试题看出你对Java类加载机制的理解深浅
http://url.cn/57lX6cG

你可能感兴趣的:(Java类加载机制的理解浅析)