我们知道一个对象可以有静态变量、变量、静态初始化块、初始化块,当我们创建一个对象时,它是怎么初始化的呢?按什么顺序初始化的呢?
- public class Test {
- // 静态变量
- public static String staticField = "静态变量"; // 变量
- public String field = "变量";
- // 静态初始化块
- static {
- System.out.println(staticField);
- System.out.println("静态初始化块");
- }
- // 初始化块
- {
- System.out.println(field);
- System.out.println("初始化块");
- }
- // 构造器
- public Test() {
- System.out.println("构造器");
- }
- public static void main(String[] args) {
- Test test = new Test();
- }
- }
运行下代码,输出结果是:
静态变量
静态初始化块
变量
初始化块
构造器
由此可以看到,当new一个对象时,它并不是就是调构造方法,而是先初始化属性变量,我们把变量的定义先后顺序换下,再执行,会发现,静态的是先于非静态进行实始化的,那么对于静态变量和静态初始化块之间、变量和初始化块之间的先后顺序又是怎样呢?是否静态变量总是先于静态初始化块,变量总是先于初始化块就被初始化了呢?
我们先改下代码:
- public class Test {
- public static TestA ta = new TestA();
- // 静态变量
- public static String staticField = "静态变量"; // 变量
- public String field = "变量";
- // 静态初始化块
- static {
- System.out.println(staticField);
- System.out.println("静态初始化块");
- }
- // 初始化块
- {
- System.out.println(field);
- System.out.println("初始化块");
- }
- // 构造器
- public Test() {
- System.out.println("构造器");
- }
- public static void main(String[] args) {
- Test test = new Test();
- }
- }
- class TestA {
- public TestA() {
- System.out.println("Test--A");
- }
- }
输出是:
Test--A
静态变量
静态初始化块
变量
初始化块
构造器
Test--A
静态变量
静态初始化块
变量
初始化块
构造器
静态变量:static TestA ta = new TestA()在静态初始化块前,所以先输出Test--A
再换下位置,把static TestA ta = new TestA()放到在静态初始化块后,我们发现输出是:
再换下位置,把static TestA ta = new TestA()放到在静态初始化块后,我们发现输出是:
静态变量
静态初始化块
Test--A
变量
初始化块
构造器
由此可见这是取决于它们在类中出现的先后顺序,同理可得:变量和初始化块之间也如此,
总结可得:初始化优先级是(静态变量/静态初始化块)>(变量/初始化块)>构造器。
那继承关系时的初始化又是怎样的呢?如下:
大家应该知道,初始化子类时会先初始化父类,再看代码:
- public class Test extends Parent{
- // 静态变量
- public static String staticField = "子类静态变量"; // 变量
- public String field = "子类变量";
- // 静态初始化块
- static {
- System.out.println(staticField);
- System.out.println("子类静态初始化块");
- }
- //public static TestA ta = new TestA();
- // 初始化块
- {
- System.out.println(field);
- System.out.println("子类初始化块");
- }
- // 构造器
- public Test() {
- System.out.println("子类构造器");
- }
- public static void main(String[] args) {
- Test test = new Test();
- }
- }
- class Parent{
- public String field = "父类变量";// 变量
- public static String staticField = "父类静态变量"; // 静态变量
- // 静态初始化块
- static {
- System.out.println(staticField);
- System.out.println("父类静态初始化块");
- }
- // 初始化块
- {
- System.out.println(field);
- System.out.println("父类初始化块");
- }
- // 构造器
- public Parent() {
- System.out.println("父类构造器");
- }
- }
刚才结果应该是:
父类静态变量
父类静态初始化块
子类静态变量
子类静态初始化块
父类变量
父类初始化块
父类构造器
子类变量
子类初始化块
子类构造器
从结果看到,并不是父类完全初始化完后再进行子类的初始化,子类的静态变量和静态初始化块的初始化是在父类的变量、初始化块和构造器初始化之前就完成了。
我们在main方法再创建一个对象,Test test2 = new Test();
大家就test2的初始化又如何?
大家就test2的初始化又如何?
为了好看,我们子类构造器里加多行代码System.out.println("***********");
输出结果:
父类静态变量
父类静态初始化块
子类静态变量
子类静态初始化块
父类变量
父类初始化块
父类构造器
子类变量
子类初始化块
子类构造器
***********
父类变量
父类初始化块
父类构造器
子类变量
子类初始化块
子类构造器
***********
发现什么了?
输出结果:
父类静态变量
父类静态初始化块
子类静态变量
子类静态初始化块
父类变量
父类初始化块
父类构造器
子类变量
子类初始化块
子类构造器
***********
父类变量
父类初始化块
父类构造器
子类变量
子类初始化块
子类构造器
***********
发现什么了?
静态变量和静态代码块只加载一次 。
总结:
一、初始化优先级:
1、静态变量/静态初始化块)>(变量/初始化块)>构造器
2、父类>子类
2、父类>子类
二、静态变量和静态代码块只加载一次,因为它们是全局共享的