修改一个常量类中的静态常量值,然后把常量类的class文件上传到服务器后并没有生效,多次重启服务,最后查询了相关资料,使用GUI反编译工具反编译查看编译后源码,终于找到问题所在:

单纯的修改静态常量是没用的,还要重新编译所有引用静态变量的类(或把这些类重新上传服务器),不然不会生效。

这里就牵扯到Java虚拟机编译机制:在Java文件中,指向编译时static final的静态常量, 会在运行时被解析为一个局部的常量值(也就是说静态常量在编译后,成为了常量,而不是原先的代码)。这对所有的基础数据类型(如int ,float等)和java.lang.String都适用。

请看下面一个实例:

程序中使用的各种常量用一个类Contants.java来统一管理。

public class Contants{
    public static final String STR = "csyor.com";
    //......
}

然后在某些逻辑代码段里使用了这些常量。这样做可以便于管理常量,避免了大量的magic number/text,在修改常量内容时只需改这一个类就行了。

import Contant;
public class SomeService {
    public void doSome() {
        // 这里应用了上一个类的静态常量Contants.STR
        System.out.println(Contants.STR);
    }
}

在上面的代码中,SomeService类使用了Contants.STR这个常量,表面上是通过Contants类取得的这个值,实际上在SomeService被编译后,其代码已经改变,如下:

import Contant;
public class SomeService {
    public void doSome() {
        // 这里把静态常量Contant.STR直接编译成为了一个常量"csyor.com"
        System.out.println("csyor.com");
    }
}

我们发现,这里面根本没有Contants类什么事,所以即使我们修改了Contants类中的常量,让STR = “www.csyor.com”,但是SomeService中依然会打印 “csyor.com” ,因为SomeService中的代码没有任何修改,在增量编译的情况下,它的class文件不会被重新编译。

那么说到这里可能会有人问:那为什么你在本地调试的好用呢?

主要是因为本地一般使用的IDE(集成开发环境)是可以自动编译的,而我们上传到服务器的时候一般只是上传自己更改过的java文件编译后的class文件(也就是包含静态常量的class),至于引用这个静态常量的其他类因为没有改动过所以不会上传,就出现了本地调试不会出现问题,但是在服务器上没有效果的情况。

明白了上面这些,问题就已经解决了,注意:不管是更换什么class文件,一定需要重启中间件容器。

解决方法一:单纯的修改静态变量STR是没用的,还要重新编译所有引用过静态变量STR的类(然后重新上传到服务器),不然不会生效,也就是说使用到这个常量的类都要重新编译。

解决方法二:去掉final

使用静态常量时一定要慎重,因为一旦修改它,就需要将整个项目中引用过该静态常量的地方重新编译替换。

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐