记静态常量遇到的坑

场景:
public class TppsPath {
    static final String name = "小花";

public class Test {
    public static void main(String args[]){
    System.Out.Println(TppsPath.name);
}
}
某个类引用了该变量值。
由于需求变更,需要更改name = "小明",直接更改了包含此静态变量的类文件,并编译成class,把测试环境中相应的class文件替换为新编译的文件。(增量部署)。
但是引用的类并不重新编译,替换。

现象:
测试发现,引用静态变量的类中,值仍然没有变过来,还是小花,并不是重新编译的小明。

解决:

查阅资料发现:
static final常量是在java编译期就进行赋值的,编译完成后,Test.class类用反编译工具打开你会发现是这样式儿的:
public class Test {
    public static void main(String args[]){
    System.Out.Println("小花");
}
}

所以只替换TppsPath 类的编译文件的话,并不能改变Test类,因为他没有跟着TppsPath 重新编译,导致数据还是原来的数据。
总结:一旦经static final修饰的常量内容变动的话,需要将所有引用改常量的类同时编译,并替换。

拓展知识:
static+final
静态常量,编译期常量,编译时就确定值。(Java代码执行顺序,先编译为class文件,在用虚拟机加载class文件执行)
放于方法区中的静态常量池。
在编译阶段存入调用类的常量池中
如果调用此常量的类不是定义常量的类,那么不会初始化定义常量的类,因为在编译阶段通过常量传播优化,已经将常量存到调用类的常量池中了

final常量,类加载时确定或者更靠后。
当用final作用于类的成员变量时,成员变量(注意是类的成员变量,局部变量只需要保证在使用之前被初始化赋值即可)必须在定义时或者构造器中进行初始化赋值
对于一个final变量,如果是基本数据类型的变量,则其数值一旦在初始化之后便不能更改;
如果是引用类型的变量,则在对其初始化之后便不能再让其指向另一个对象。但是它指向的对象的内容是可变的
原文链接:https://blog.csdn.net/u011299745/article/details/52887825

static final常量虚拟机实现:
1.Class 文件的生成阶段
Sun javac编译器对于静态field字段的初始化赋值策略 
目前的Sun javac编译器的选择是: 
1.如果使用final和static同时修饰一个field字段,并且这个字段是基本类型或者String类型的,那么编译器在编译这个字段的时候,会在对应的field_info结构体中增加一个ConstantValue类型的结构体,在别的类进行调用进行赋值的时候使用这个ConstantValue进行赋值; 
2.如果该field字段并没有被final修饰,或者不是基本类型或者String类型,那么将在类构造方法cinit>()中赋值。

对于上述的public static final init MAX=100; javac编译器在编译此field字段构建field_info结构体时,除了访问标志、名称索引、描述符索引外,会增加一个ConstantValue类型的属性表。
2.类加载阶段(链接(准备阶段))
如果类字段的字段属性表中存在ConstantValue属性,即同时被final和static修饰,那么在准备阶段变量value就会被初始化为ConstValue属性所指定的值。 假设上面的类变量value被定义为: public static final int value = 3; 编译时Javac将会为value生成ConstantValue属性,在准备阶段虚拟机就会根据ConstantValue的设置将value赋值为3。 
顺便讲一句:static final 与final static 只是使用的习惯问题 ,没有 差别
原文链接:https://blog.csdn.net/qq_35495763/article/details/81071936


在java中用final修饰符修饰的变量表示不可以被二次赋值,且系统不会给其赋默认值。
如果单纯只是final变量,可以在定义的时候就赋默认值,也可以在构造方法中赋默认值。
但是如果同时用final static 修饰变量,因为static变量属于类而不属于对象,且在调用构造方法之前static 变量就已经被系统给赋默认值。而相应的final static 变量就只能在定义的时候就初始化,否则既无法在构造方法中初始化,系统又不会赋默认值,相当于这个变量被定义出来是毫无用处的。 因此java中final static变量必须初始化。

发布了23 篇原创文章 · 获赞 0 · 访问量 2943

猜你喜欢

转载自blog.csdn.net/kris_lh123/article/details/101542539
今日推荐