关于static final的问题(半个转载,也有自己总结的)

一、背景
       项目需要统一修改未登录状态的返回码,修改对应CommonConstant类,对应枚举的字段。希望通过修改,使得各应用该枚举的REST接口未登录的返回码得到修改。但在修改该类后,各REST接口返回码并没有改变。一开始无法定位到问题,以为相关类没有上、或者没有编译、服务器存在缓存等问题。后来取得编译后的REST接口类,反编译发现,类中返回码并不是使用的对应static final值,而是写死的对应返回码字符串。
        而在.java中明明是对应的类字段,为什么编译后会变成写死的字符串呢。
二、编译期变量:

       编译期变量:static和final共同修饰的基本类型变量的情况,这时这个变量只占据一段不能被修改的存储空间,称为编译时常量。(这是查到别人的解释)

        我自己的理解:感觉这个概念并不准确,在我理解,用static final修饰的基本类型,编译器认为该变量是不会被修改的,所以在编译时就会在引用类中写死,以增加效率,所以编译后就变成了写死的值,而不是引用。

       也就是说用static、final共同修饰的情况下,该变量在编译时就已经确定、且不可改变,所以每个class类在编译后这个值就会以常量的形式写死在这个类中。所以希编译望通过修改这个变量,达到修改所有相关引用的想法是不可行的。必须将所有引用该变量的类重新编译。
三、测试static final各类结果
public class CompileTest{
    public static void main(String args[]){
//        System.out.println(Data.i1);
//        System.out.println(Data.i2);//initialization!
//        System.out.println(Data.b1);//initialization!
//        System.out.println(Data.b2);
//        System.out.println(Data.s1);
//        System.out.println(Data.s2);//initialization!
//        System.out.println(Data.a); //initialization!
//        System.out.println(Data.e); //initialization!
       
    }
}
class Data{
  static{
      System.out.println("initialization!");
  }
  public static final int i1 = 0;
  public static final Integer i2 = 0;
  public static final Boolean b1 = true;
  public static final boolean b2 = true;
  public static final String s1 = "0";
  public static final String s2 = new String("0");
  public static final A a = new A();
  public static final Enum e = E.A;
}
class A{
 
}
enum E {
    A,B,C,D,E,F,G;
}
结论:
   从上面执行main方法中可以看出,只有基本类型的情况下,static final才会是编译期写死,而修饰其他类型,仍然会先加载该类,然后才去读取变量。
四、注意

    如果不使用Enum,有希望达到枚举值的效果,那么不要使用static final去修饰,应该只使用static,但这样无法保证该变量不会因为某引用类、或方法导致修改,所以最好使用Enum,而如果确定该类从开发开始 一定不会修改,那么再使用static final.


PS:首先开始理解为什么那么多人膜拜《Thinking in JAVA》了,据说书里面早就对final可能引起的各种问题进行了说明。当时自己挑着看了一半.....这一节没看.....。发誓今年找机会一定要看完.....感觉自己LOW爆了。


猜你喜欢

转载自blog.csdn.net/fengcaho0616/article/details/79786327