JAVA中静态变量,静态代码块,静态初始化,非静态初始化的加载顺序

例题1

public class Test08 {
    public static void main(String[] args) {
        Zi zi = new Zi();
    }
}
class Fu{
    private static int i = getNum("(1)i");
    private int j = getNum("(2)j");
    static{
        print("(3)父类静态代码块");
    }
    {
        print("(4)父类非静态代码块,又称为构造代码块");
    }
    Fu(){
        print("(5)父类构造器");
    }
    public static void print(String str){
        System.out.println(str + "->" + i);
    }
    public static int getNum(String str){
        print(str);
        return ++i;
    }
}
class Zi extends Fu{
    private static int k = getNum("(6)k");
    private int h = getNum("(7)h");
    static{
        print("(8)子类静态代码块");
    }
    {
        print("(9)子类非静态代码块,又称为构造代码块");
    }
    Zi(){
        print("(10)子类构造器");
    }
    public static void print(String str){
        System.out.println(str + "->" + k);
    }
    public static int getNum(String str){
        print(str);
        return ++k;
    }
}

  a.构造代码块: {}
     优先于构造方法执行,每new一次就会执行一次
   b.静态代码块: static{}
     优先于构造代码块和构造方法执行的,只执行一次


image-20220224144834234

image-20220224111939847

例题2

public class T {
    public  static int k = 0;
    public static T t1 = new T("t1");
    public static T t2 = new T("t2");
    public static int i = print("i");
    public static int n = 99;
    public int j = print("j");
    static{
        print("静态块");
    }
    {
        print("构造块");
    }
    public T(String str){
        System.out.println((++k) + ":" + str + "  i=" + i + "  n=" + n);
        ++n;
        ++i;
    }
    public static int print(String str){
        System.out.println((++k) + ":" + str + "  i=" + i + "  n=" + n);
        ++n;
        return ++i;
    }
    public static void main(String[] args) {
    }
}

image-20220224142023050

image-20220224143723807

首先看到static关键字,脑子里面第一反应有几点,

1、公有属性,可以有类名称直接访问。

2、静态方法,可以有类名称直接方法。

3、静态方法或者属性,可以再对象实例化之前就调用

至于该题中,顺序执行,先执行public static int k =0 ;

因为没有输出不用考虑这个,接着public static Text t1 = new Text("t1") ;

t1对象初始化时先执行非静态方法或者非静态常量,顺序执行,接着运行构造参数,

根据程序来看应该打印三条记录,分别是

1:j i=0 n=02:构造块 i=1 n=13:t1 i=2 n=2

接下来public static Text t2 = new Text("t2") ;同理,执行完之后继续执行static代码块或者赋值静态变量,在main()方法中new了一个新的实例,静态变量只执行一次,接下来就是顺序执行非静态方法---->构造方法。

几大原则

一、静态成员变量(Static)

  • 静态成员变量为类变量,所有对象共享同一内存空间
  • 静态成员变量的声明和定义仅在首次加载类的时候执行一次
  • 首次加载类时首先对所有静态成员变量根据类型默认赋初值,然后再对有右值的赋右值

二、静态初始块

  • 静态初始化块仅在首次加载类的时候执行一次
  • 多个静态成员变量与静态初始化块 按照编写顺序先后执行

三、动态成员变量

  • 动态成员变量定义在每次实例化对象时在构造函数之前执行

四、动态初始化块

  • 动态初始化块在每次实例化对象时在构造函数之前执行

  • ······多个动态成员变量与动态初始化块参照出现顺序先后执行······

总结:总的来说,在不涉及继承的前提下,当首次加载类时,按照如下顺序执行

  • 按照出现顺序先后执行静态成员变量定义与静态初始化块

  • 按照出现顺序先后执行动态成员变量定义与动态初始化块

  • 执行构造函数

  • 再次实例化对象时只执行第2、3步即可

  • ············成员变量与定义与初始化块先于构造函数执行·········

五、当涉及到继承时,按照如下顺序执行

  • 1、执行父类的静态成员变量定义与静态初始化块,执行子类的静态成员变量定义与静态初始化块

  • 2、执行父类的非静态成员变量定义与动态初始化块,执行父类构造方法

  • 3、执行子类的非静态成员变量定义与动态初始化块,执行子类构造方法

  • 另:父类构造方法中用到的方法如果已被子类重写,那么在构造子类对象时在调用父类构造函数中使用子类重写的方法

posted @ 2022-02-24 14:51  有空就一起吃饭吧  阅读(456)  评论(0编辑  收藏  举报