类初始化
(1)静态类成员变量的显式赋值语句
(2)静态代码块中的语句
整个类初始化只会进行一次,如果子类初始化时,发现父类没有初始化,那么会先初始化父类。

public class Test{ public static void main(String[] args){ Father.test(); } } class Father{ private static int a = getNumber(); static{ System.out.println("Father(1)"); } private static int b = getNumber(); static{ System.out.println("Father(2)"); } public static int getNumber(){ System.out.println("getNumber()"); return 1; } public static void test(){ System.out.println("Father:test()"); } }
运行结果: getNumber() Father(1) getNumber() Father(2) Father:test()
private static int a = getNumber(); static{ System.out.println("Father(1)"); } private static int b = getNumber(); static{ System.out.println("Father(2)"); } 顺序改变 输出内容也改变 static{ System.out.println("Father(1)"); } private static int a = getNumber(); private static int b = getNumber(); static{ System.out.println("Father(2)"); }
类加载时候:Father.test();第一次使用的时候类就加载,此时静态变量赋值和静态初始化按书写顺序同时进行 类加载要比实例化靠前 对象实力化=执行构造器=new 类初始化块在类加载时进行,static静态变量也在类加载时赋值 实例初始化块在实例化对象时进行,同事执行构造器
区别有继承关系的时候,继承关系时候父类优先子类空间运行
父子类

public class Test{ public static void main(String[] args){ Son.test(); System.out.println("-----------------------------"); Son.test(); } } class Father{ private static int a = getNumber(); static{ System.out.println("Father(1)"); } private static int b = getNumber(); static{ System.out.println("Father(2)"); } public static int getNumber(){ System.out.println("Father:getNumber()"); return 1; } } class Son extends Father{ private static int a = getNumber(); static{ System.out.println("Son(1)"); } private static int b = getNumber(); static{ System.out.println("Son(2)"); } public static int getNumber(){ System.out.println("Son:getNumber()"); return 1; } public static void test(){ System.out.println("Son:test()"); } }
运行结果: Father:getNumber() Father(1) Father:getNumber() Father(2) Son:getNumber() Son(1) Son:getNumber() Son(2) Son:test() ----------------------------- Son:test()
结论:
每一个类都有一个类初始化方法<clinit>()方法,然后子类初始化时,如果发现父类加载和没有初始化,会先加载和初始化父类,然后再加载和初始化子类。一个类,只会初始化一次。
语法格式:在类中方法外,一个类中可以出现多个
【修饰符】 class 类名{ { 非静态代码块语句; } }
实际上我们编写的代码在编译时,会自动处理代码,整理出一个<clinit>()的类初始化方法,还会整理出一个或多个的<init>(...)实例初始化方法。一个类有几个实例初始化方法,由这个类有几个构造器决定。
实例初始化方法的方法体,由四部分构成:
(1)super()或super(实参列表) 这里选择哪个,看原来构造器首行是哪句,没写,默认就是super()
(2)非静态实例变量的显示赋值语句
(3)非静态代码块
(4)对应构造器中的代码
特别说明:其中(2)和(3)是按顺序合并的,(1)一定在最前面(4)一定在最后面
执行特点:
-
创建对象时,才会执行,
-
调用哪个构造器,就是指定它对应的实例初始化方法
-
创建子类对象时,父类对应的实例初始化会被先执行,执行父类哪个实例初始化方法,看用super()还是super(实参列表)

public class Test{ public static void main(String[] args){ Father f1 = new Father(); // Father f2 = new Father("atguigu"); } } class Father{ private int a = getNumber(); private String info; { System.out.println("Father(1)"); } Father(){ System.out.println("Father()无参构造"); } Father(String info){ this.info = info; System.out.println("Father(info)有参构造"); } private int b = getNumber(); { System.out.println("Father(2)"); } public int getNumber(){ System.out.println("Father:getNumber()"); return 1; } }
Father:getNumber() Father(1) Father:getNumber() Father(2) Father()无参构造
结论:
类初始化肯定优先于实例初始化。
类初始化只做一次。
实例初始化是每次创建对象都要进行。
构造器和非静态代码块
即如果每个构造器中有相同的初始化代码,且这些初始化代码无须接收参数,就可以把它们放在非静态代码块中定义。通过把多个构造器中相同代码提取到非静态代码块中定义,能更好地提高初始代码的复用,提高整个应用的可维护性。