建议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-01

    1)先写我的 github 的介绍: github 的域名:http://www.github.com/zhuifeng1022 登入 github 大概是下面的视图: 按照助教的方法:我已经建好了代 ...

  2. ocp 1Z0-051 141-175题解析

    141. View the Exhibitand examine the structure of CUSTOMERS and GRADES tables. You need to displayna ...

  3. 蓝桥杯 入门训练 Fibonacci数列

      入门训练 Fibonacci数列   时间限制:1.0s   内存限制:256.0MB        问题描述 Fibonacci数列的递推公式为:Fn=Fn-1+Fn-2,其中F1=F2=1. ...

  4. XML操作:2.LINQ TO XML(http://www.cnblogs.com/AlexLiu/archive/2008/10/27/linq.html)

    LINQ to XML 建立,读取,增,删,改   LINQ to XML的出现使得我们再也不需要使用XMLDocument这样复杂的一个个的没有层次感的添加和删除.LINQ可以使的生成的XML文档在 ...

  5. (转)WordPress的主查询函数-query_posts()

    今天说说WordPress 的主查询函数 -query_posts(),因为我正在制作的主题里面多次用到了这个函数 . query_posts()查询函数决定了哪些文章出现在WordPress 主 循 ...

  6. Java数据库编程(JDBC)

    一.使用Java对数据库的操作步骤: 1.根据应用程序的数据库类型,加载相应的驱动: 2.连接到数据库,得到Connection对象: 3.通过Connection创建Statement对象: 4.使 ...

  7. Spring和Hibernate集成的HibernateTemplate的一些常用方法总结

    1:get/load存取单条数据 public Teacher getTeacherById(Long id) { return (Teacher)this.hibernateTemplate.get ...

  8. Python 3学习笔记2

    模块: 模块是一个包含Python代码的文本文件.使用import可以将模块导入到其他程序中. 每个模块都有自己的命名空间.主Python程序中的代码与一个名为__main__的明明空间关联.将代码放 ...

  9. 教你50招提升ASP.NET性能(二十二):利用.NET 4.5异步结构

    (40)Take advantage of .NET 4.5 async constructs 招数40: 利用.NET 4.5异步结构 With the arrival of .NET 4.5, w ...

  10. C# 钩子HOOK专题(1)

    目录   基本概念 运行机制 钩子类型 作者 基本概念   钩子(Hook),是Windows消息处理机制的一个平台,应用程序可以在上面设置子程以监视指定窗口的某种消息,而且所监视的窗口可以是其他进程 ...