JAVA属性初始化顺序

属性分为静态属性和非静态属性,参与初始化或者说赋值顺序的,JAVA类的属性的初始化方式有默认初始化,定义时显式初始化,代码块赋值,构造器赋值,spring@value属性注入。为考虑不同的情况,细分为①静态变量默认初始化②静态变量显式赋值③非静态代码块赋值④静态代码块赋值⑤创建对象⑥构造器赋值⑦spring@value属性注入⑧非静态变量默认初始化⑨非静态变量显式初始化,此外我们额外插入一个⑤创建对象来对标划分整个过程以便更好理解。现在来一一比较各种方式赋值的先后顺序。

测试类的成员环境

包括 有和没有显式赋值的非静态变量 a和b、有和没有显式赋值的静态变量 c和d、@value属性注入的e、有参和无参构造器、静态和非静态代码块(静态代码块先不启用)。

@Component
class initPriority{
    int a = 1;
    int b;

    static int c;
    static int d = 1;

    @Value("#{7}")
    int e;

    public initPriority (){
    }
    public initPriority (int a, int b, int e){
        this.a = a;
        this.b = b;
        c = b;
        d = b;
        this.e = e;
    }
//    {
//       a = 3;
//        b = 3;
//        c = 3;
//        d = 3;
//    }
//    static {
//        c = 2;
//        d = 2;
//    }
}

对象创建前

已加载类但还未创建对象,现在只有静态属性可以调用,理论上现在能执行的初始化方法有静态方法的默认初始化、静态代码块(静态代码块中只能有静态变量)和静态变量的显式初始化。先不启用静态代码块,直接在测试方法中

System.out.println(initPriority.c+","+initPriority.d);//0,1

c是没有显示赋值的,d有显示赋值,默认初始化的0被覆盖了,说明①静态变量默认初始化早于②静态变量显式初始化。 

现在把静态代码块的注释去掉,再测试

System.out.println(initPriority.c+","+initPriority.d);//2,2

默认初始化的0和显式赋值的1都被2覆盖了,说明④静态代码块赋值要晚于前面两种初始化方法。 

①静态变量默认初始化 >>> ②静态变量显式初始化 >>> ④静态代码块赋值

对象获取后

对象获取是通过构造器的,对象获取后才有非静态属性,可以肯定,其他的非静态赋值方法一定是晚于创建对象的,但这不意味着构造器赋值紧随其后,对象的创建是一个复杂的过程。

现在我们先不启用非静态代码块,由无参构造得到对象,现在理论上进行的非静态初始化方法只有非静态变量的默认初始化、非静态变量的显式初始化。

 initPriority ip1 = new initPriority();
        System.out.println(ip1.a+","+ip1.b+","+initPriority.c+","+initPriority.d+","+ip1.e);
//1,0,2,2,0

由于b是没有显示赋值的,a有显示赋值,默认初始化的0被覆盖了,说明⑧非静态变量默认初始化早于⑨非静态变量显式初始化。 

现在启用非静态代码块,同样用无参构造,

 initPriority ip1 = new initPriority();
        System.out.println(ip1.a+","+ip1.b+","+initPriority.c+","+initPriority.d+","+ip1.e);
//3,3,3,3,3

前面的值全部被3覆盖,说明③非静态代码块赋值要晚于。而且,如果有多个非静态代码块,按代码出现顺序后面的赋值会覆盖前面的。

接下来我们采用有参构造,给所有值赋4,

initPriority ip2 = new initPriority(4,4,4);
        System.out.println(ip2.a+","+ip2.b+","+initPriority.c+","+initPriority.d+","+ip2.e);
//4,4,4,4,4

所有值再次被覆盖,所以构造器赋值晚于前面所述的初始化方法,另外,我们知道Spring的属性注入时先获得bean对象再注入的,则⑦spring@value属性注入必然晚于构造器赋值,但是Spring获取对象是通过无参构造获取的,所以两者也没有什么交集。

ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("springConfig.xml");
        initPriority ip3 = context.getBean("initPriority", initPriority.class);
        System.out.println(ip3.a+","+ip3.b+","+initPriority.c+","+initPriority.d+","+ip3.e);
//3,3,3,3,7

①静态变量默认初始化 >>> ②静态变量显式初始化 >>> ④静态代码块赋值 >>>  ⑤创建对象  >>>  ⑧非静态变量默认初始化  >>>  ⑨非静态变量显式初始化  >>>  ③非静态代码块赋值 >>>  ⑥构造器赋值 >>>  ⑦spring@value属性注入

你可能感兴趣的:(Java语法基础,java,开发语言,spring,junit)