建议20: 不要只替换一个类

我们经常在系统中定义一个常量接口(或常量类),以囊括系统中所涉及的常量,从而简化代码,方便开发,在很多的开源项目中已采用了类似的方法,比如在Struts2中,org.apache.struts2.StrutsConstants就是一个常量类,它定义了Struts框架中与配置有关的常量,而org.apache.struts2.StrutsStatics则是一个常量接口,其中定义了OGNL访问的关键字。

关于常量接口(类)我们来看一个例子,首先定义一个常量类:

 public class Constant {
//定义人类寿命极限
public final static int MAX_AGE = 150;
}
 public class Client {
public static void main(String[] args) {
System.out.println("人类寿命极限是:" + Constant.MAX_AGE);
}
}

运行的结果非常简单(结果省略)。目前的代码编写都是在“智能型”IDE工具中完成的,下面我们暂时回溯到原始时代,也就是回归到用记事本编写代码的年代,然后看看会发生什么奇妙事情(为什么要如此,稍后会给出答案)。

修改常量Constant类,人类的寿命增加了,最大能活到180岁,代码如下:

 public class Constant {
//定义人类寿命极限
public final static int MAX_AGE = 180;
}

然后重新编译:javac Constant,编译完成后执行:java Client,(只执行Client类,不编译)大家想看看输出的极限年龄是多少岁吗?

输出的结果是:“人类寿命极限是:150”,竟然没有改变为180,太奇怪了,这是为何?

原因是:对于final修饰的基本类型和String类型,编译器会认为它是稳定态(Immutable Status),所以在编译时就直接把值编译到字节码中了,避免了在运行期引用(Run-time Reference),以提高代码的执行效率。针对我们的例子来说,Client类在编译时,字节码中就写上了“150”这个常量,而不是一个地址引用,因此无论你后续怎么修改常量类,只要不重新编译Client类,输出还是照旧。

而对于final修饰的类(即非基本类型),编译器认为它是不稳定态(Mutable Status),在编译时建立的则是引用关系(该类型也叫做Soft Final),如果Client类引入的常量是一个类或实例,即使不重新编译也会输出最新值。

千万不可小看了这点知识,细坑也能绊倒大象,比如在一个Web项目中,开发人员修改一个final类型的值(基本类型),考虑到重新发布风险较大,或者是时间较长,或者是审批流程过于繁琐,反正是为了偷懒,于是直接采用替换class类文件的方式发布。替换完毕后应用服务器自动重启,然后简单测试一下(比如本类引用final类型的常量),一切OK。可运行几天后发现业务数据对不上,有的类(引用关系的类)使用了旧值,有的类(继承关系的类)使用的是新值,而且毫无头绪,让人一筹莫展,其实问题的根源就在于此。

恩,还有个小问题没有说明,我们的例子为什么不在IDE工具(比如Eclipse)中运行呢?那是因为在IDE中不能重现该问题,若修改了Constant类,IDE工具会自动编译所有的引用类,“智能”化屏蔽了该问题,但潜在的风险其实仍然存在。

注意 发布应用系统时禁止使用类文件替换方式,整体WAR包发布才是万全之策。

[改善Java代码]不要只替换一个类的更多相关文章

  1. [改善Java代码]异常只为异常服务

    异常原本是正常逻辑的补充,但是有时候会被当做主逻辑使用.看如下代码: public class Client { enum Color { Red, Blue; } public static voi ...

  2. [改善Java代码]注意Class类的特殊性

    Java语言是先把Java源文件编译成后缀为class的字节码文件,然后再通过ClassLoader机制把这些类文件加载到内存中,最后生成实例执行的,这是Java处理的基本机制,但加载到内存中的数据是 ...

  3. 为什么java源文件中只允许一个public类存在

    1.提出问题 为什么java源文件中只允许一个public类存在? 2.分析问题 问题涉及到的条件:源文件的名字    public类     main方法 一般我们在编写一个源文件的时候: 一个pu ...

  4. java多线程并发去调用一个类的静态方法安全性探讨

    java多线程并发去调用一个类的静态方法安全性探讨 转自:http://blog.csdn.net/weibin_6388/article/details/50750035   这篇文章主要讲多线程对 ...

  5. Java中是否可以调用一个类中的main方法?

    前几天面试的时候,被问到在Java中是否可以调用一个类中的main方法?回来测试了下,答案是可以!代码如下: main1中调用main2的主方法 package org.fiu.test; impor ...

  6. Javascript replace 为什么只替换一个字符?

    Javascript replace 为什么只替换一个字符? 如下代码,为什么结果是 "a2b1c1" ? 'a1b1c1'.replace('1', 2); 因为 javascr ...

  7. java代码行数统计工具类

    package com.syl.demo.test; import java.io.*; /** * java代码行数统计工具类 * Created by 孙义朗 on 2017/11/17 0017 ...

  8. [改善Java代码]让工具类不可实例化

    建议42: 让工具类不可实例化 Java项目中使用的工具类非常多,比如JDK自己的工具类java.lang.Math.java.util.Collections等都是我们经常用到的.工具类的方法和属性 ...

  9. [改善Java代码]使用package-info类为包服务

    建议50: 使用package-info类为包服务 Java中有一个特殊的类:package-info类,它是专门为本包服务的,为什么说它特殊呢?主要体现在3个方面: (1)它不能随便被创建 在一般的 ...

随机推荐

  1. homework-09

    这次作业主要考察C++11的简单用法,个人感觉这样的练习对我这种编程能力比较差的非常有用,加深了对C++11的理解. Lambda的用法 计算“Hello World!”中 a.字母‘e’的个数 b. ...

  2. Spring EL Operators example

    Spring EL supports most of the standard mathematical, logical or relational operators. For example, ...

  3. js获取服务端IP及端口及协议

    alert("location:"+window.location); alert("href: "+window.location.href); alert( ...

  4. OAuth 2.0介绍学习

    OAuth2.0是OAuth协议的下一版本,但不向后兼容OAuth 1.0即完全废止了OAuth1.0. OAuth 2.0关注客户端开发者的简易性.要么通过组织在资源拥有者和HTTP服务商之间的被批 ...

  5. C#枚举数值与名称的转换

    在应用枚举的时候,时常需要将枚举和数值相互转换的情况.有时候还需要转换成相应的中文.下面介绍一种方法. 首先建立一个枚举: /// <summary> /// 颜色 /// </su ...

  6. python的sys.path

    python检测不到模块: No module named 是因为模块没有在sys.path中,查看sys.path的方法 import sys sys.path 发现确实没有加载到模块. windo ...

  7. php redis安装

    一.redis安装 1 下载redis安装包 wget http://redis.googlecode.com/files/redis-2.4.17.tar.gz (若无法下载请手动下载) 2 编译安 ...

  8. Oracle_11g_R2安装详解_for_Windows_7

    Oracle 11g R2安装全攻略 - For Windows 7 图文教程 1.下载Oracle 11g R2的Windows版本,官方下载地址如下: http://download.oracle ...

  9. HTML输出 二 控制行背景颜色

    $Infors = Get-Content ports01.txt$Temp_PortStatustxt = "C:\Windows\Temp\PortStatustxt.txt" ...

  10. 关于struts2 验证框架在联网的时候可以用,不联网不起作用的问题

    这是一个让我很头痛的问题,我是在一个其他的项目框架的基础上来开发新的项目. 当使用struts验证框架时,突然发现这个验证不起作用了,我就纳闷了之前用这个开发的项目好好的怎么到我这就不能用了呢? xm ...