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属性注入

另外,springboot中有一个常用的执行一些项目初始化的操作的(加在方法上的)注解@PostConstruct。该注解标注的方法执行位次排序最次,在@value或@autowired的注入之后,如果想要初始化时做一些需要注入依赖才能做的操作就可以使用这个注解。

@value主要是注入数值类型属性,@autowired是注入对象类型。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值