结论 :::info 父类静态属性(成员变量) > 父类静态代码块 > 子类静态属性 > 子类静态代码块 > 父类非静态属性 > 父类非静态代码块 > 父类构造器 > 子类非静态属性 > 子类非静态代码块 > 子类构造器 ::: (注:静态代码块和静态属性顺序 自上而下)

    这里帮大家小结几个特点:

    1. 静态属性代码块,当且仅当该类在程序中第一次被 new 或者第一次被类加载器调用时才会触发(不考虑永久代的回收)。也正是因为上述原因,类优先于对象 加载/new,即 静态优先于非静态
    2. 属性(成员变量)优先于构造方法,可以这么理解,加载这整个类,需要先知道类具有哪些属性,并且这些属性初始化完毕之后,这个类的对象才算是完整的。另外,非静态代码块其实就是对象 new 的准备工作之一,算是一个不接受任何外来参数的构造方法。因此,属性 > 非静态代码块 > 构造方法
    3. 有趣的是,静态部分(前4个)是父类 > 子类,而 非静态部分(后6个)也是父类 > 子类
    4. 另外容易忽略的是,非静态代码块在每次 new 对象时都会运行,可以理解:非静态代码块是正式构造方法前的准备工作(非静态代码块 > 构造方法)

    测试代码:

    1. public class Test {
    2. static class A {
    3. static Hi hi = new Hi("A");
    4. Hi hi2 = new Hi("A2");
    5. static {
    6. System.out.println("A static");
    7. }
    8. {
    9. System.out.println("AAA");
    10. }
    11. public A() {
    12. System.out.println("A init");
    13. }
    14. }
    15. static class B extends A {
    16. static Hi hi = new Hi("B");
    17. Hi hi2 = new Hi("B2");
    18. static {
    19. System.out.println("B static");
    20. }
    21. {
    22. System.out.println("BBB");
    23. }
    24. public B() {
    25. System.out.println("B init");
    26. }
    27. }
    28. static class Hi {
    29. public Hi(String str) {
    30. System.out.println("Hi " + str);
    31. }
    32. }
    33. public static void main(String[] args) {
    34. System.out.println("初次 new B:");
    35. B b = new B();
    36. System.out.println();
    37. System.out.println("第二次 new B:");
    38. b = new B();
    39. }
    40. }

    打印结果:

    1. 初次 new B
    2. Hi A
    3. A static
    4. Hi B
    5. B static
    6. Hi A2
    7. AAA
    8. A init
    9. Hi B2
    10. BBB
    11. B init
    12. 第二次 new B
    13. Hi A2
    14. AAA
    15. A init
    16. Hi B2
    17. BBB
    18. B init

    注意:

    比较两个类是否相等,只有这两个类是由同一个类加载器加载才有意义。否则,即使这两个类是来源于同一个 Class 文件,只要加载它们的类加载器不同,那么这两个类必定不相等。