`
ruilin215
  • 浏览: 1107932 次
  • 性别: Icon_minigender_2
  • 来自: 成都
文章分类
社区版块
存档分类
最新评论

通过final变量实现条件编译

 
阅读更多

首先来比较两段代码所产生的中间代码:

 public   class  AppConfig {

     public   static   final   boolean  debug  =   true ;
}
public   class  DebugCode {
    
public   static   void  main(String[] args) {
       
if (AppConfig.debug) {
           System.out.println(
" Some debug information " );
       }
    }
}

DebugCode 的中间代码(部分):

public class org.levin.insidejvm.miscs.DebugCode {

 public static void main(java.lang.String[] args);

    0 getstatic java.lang.System.out : java.io.PrintStream [16]

    3 ldc <String "Some debug information"> [22]

    5 invokevirtual java.io.PrintStream.println(java.lang.String) : void [24]

    8 return

}

 

public   class  AppConfig {
    
public   static   final   boolean  debug  =   false ;
}
public   class  ReleaseCode {
    
public   static   void  main(String[] args) {
       
if (AppConfig.debug) {
           System.out.println(
" Some debug information " );
       }
    }
}

 

 

ReleaseCode 中间代码(部分):

public class org.levin.insidejvm.miscs.ReleaseCode {

 public static void main(java.lang.String[] args);

    0 return

}

 

在上面的代码中,很明显 DebugCode ReleaseCode中的代码是一样的,只是 AppConfig.debug 的值不一样而已 ,却产生了不同的中间代码,即编译器在 AppConfig.debug false的时候直接忽略了 if中的语句。利用这个特性,我们就可以根据配置来实现条件编译,从而实现不同的条件产生不同的中间代码而不只是不同的运行结果。

 

然而在这里为什么会出现这样的行为呢?

这是因为编译器对 final修饰的基本类型和 String类型的变量,在编译时解析为一个本地拷贝,这样拷贝导致编译器在编译的时候明确的知道 ReleaseCode的那一段 if语句是不会被执行的,因而可以对其做优化。而这种替换的结果也使得用 final修饰的 int变量可以出现在 switch-case语句中。

 

这种方式的缺陷

这种方式的缺陷在于要现实该机制的条件编译,在改变 AppConfig.debug中的值时,需要同时对 AppConfig类和 ReleaseCode类进行编译(即不能只编译 AppConfig类)。

 

参考:《深入 Java虚拟机(第二版)》第八章

3
6
分享到:
评论
2 楼 神之小丑 2011-07-26  
看JDK7,nio2里的 Pool.java有这一段:
    private void d(String msg, int i) {
        if (debug) {
            System.err.println(this + "." + msg + i);
        }
    }

    private void d(String msg, Object obj) {
        if (debug) {
            System.err.println(this + "." + msg + obj);
        }
    }

public final class LdapPoolManager {
。。。
    public static final boolean debug =
        "all".equalsIgnoreCase(getProperty(DEBUG, null));
。。。
}

刚开始不懂为撒要 if(debug),这里是不是 就是条件编译这样的意思啊
1 楼 Coding.Ghost 2011-07-26  
beautiful...you are a programer?

相关推荐

    Java中的final关键字详解及实例

    上面的代码对age进行初始化后就不可再次赋值,否则编译时会报类似上图的错误。 如果修饰的是引用类型的变量,那么初始化后就不能让他指向另一个对象,如下图所示 2.修饰方法 用final关键字修饰的方法是不能被该...

    编译器说 Lambda 表达式中的变量必须是 final 的,我偏不信

    偶尔,我们需要在 Lambda 表达式中修改变量的值,但如果直接尝试修改的话,编译器不会视而不见听而不闻,它会警告我们说:“variable used in lambda expression should be final or effectively final”。...

    JAVA实现Excel导入/导出的功能实现

    请到网站http://www.apache.org/dyn/closer.cgi/poi/右击超链接2.5.1.zip下载压缩包poi-bin-2.5.1-final...请把poi-2.5.1-final-20040804.jar这个文件的路径添加到系统环境变量classpath中,否则无法编译下面的示例程序

    【05-面向对象(下)】

    •对一个final变量来说,不管它是类变量、实例变量,还是局部变量,只要该变量满足3个条件,这个final变量就 不再是一个变量,而是相当于一个直接量。  –使用final修饰符修饰;  –在定义该final变量时指定...

    Simulink生成独立的exe文件的一些方法-EclipseStepByStep_v2_final.ppt

    那么我们通常用eclipse来编译这些程序(因为是免费的,不像微软那些程序,很贵,而且兼容性好,可以实现跨平台) 这里,是一个使用eclipse建立project的ppt文件,讲的很详细,一步一步走即可: ...

    java模拟题库面试题目64道经典答题及答案

    1. 我们能不能声明 main()方法为非静态?...使用 final 关键字修饰一个变量时, 是指引用变量不能变, 引用变量所指向的对象中的 容还是可以改变的。 5. string、 stringbuilder、 stringbuffer 区别

    java基础非常典型的面试题目.wps

    Java面试必备,题目非常基础,看看你能做对几道? 题目及详解示例 14. public class Test { ... 如果局部变量没有被初始化,并且在方法中一直没有被使用,编译和运行都会通过。 可以改正为:String s = null ;

    Java 语言基础 —— 非常符合中国人习惯的Java基础教程手册

    对象的使用包括引用对象的成员变量和方法,通过运算符·可以实现对变量的访问和方法的调 用,变量和方法可以通过设定一定的访问权限(见下面的例子)来允许或禁止其它对象对它的 访问。 我们先定义一个类 Point。 例子...

    【04-面向对象(上)】

    •Java 引用变量有两个类型:一个是编译时的类型,一个是运行时的类型,编译时的类型由声明该变量时使用的类  型决定,运行时的类型由实际赋给该变量的对象决定。 •如果编译时类型和支行时的类型不一致,这就...

    Java语言程序设计的课程设计项目——利用Java实现地球系动画完整实现实例(第3部分).pdf

    (2)Java 中的数组为静态的 1) 所谓静态的数组是指其长度大小是固定的(利用 length 属性可以获得实际的长度,因 为在每个数组对象中都有 1 个 length 的 final 属性变量,这个变量指定了数组的大小, 即数组可以...

    Java的六大问题你都懂了吗

    也就是说,把初始化语句放在只有if块的条件判断语句中编译器也会抗议,因为执行的时候可能不符合if后面的判断条件,如此一来初始化语句就不会被执行了,这就违反了局部变量使用前必须初始化的规定。但如果在else块中...

    JavaLearnSummary:java学习总结

    final方法比非final方法要快,因为在编译的时候已经静态绑定了,不需要在运行时在动态绑定; Ø 修饰变量:如果是基本数据类型,则一旦被初始化,值不能更改;如果是引用类型,一旦被初始化,不能再指向另外的对象,...

    突破程序员基本功的16课.part2

    2.4.1 final修饰的变量 2.4.2 执行"宏替换"的变量 2.4.3 final方法不能被重写 2.4.4 内部类中的局部变量 2.5 小结 第3课 常见Java集合的实现细节 3.1 Set和Map 3.1.1 Set和Map的关系 3.1.2 HashMap和...

    java期末考试试题(2)

    1.MAX_LENGTH是int型public成员变量, 变量值保持为常量100,用简短语句定义这个变量。 A public int MAX_LENGTH=100; B final int MAX_LENGTH=100; C final public int MAX_LENGTH=100; D public final int MAX_...

    java经典面试2010集锦100题(不看你后悔)

    C) 程序能通过编译,运行时将打印出0/0,因为在Java中int型变量day和month默认为0。 D) 以上说法都不正确。 题目10:c 下面关于继承的描述正确的一项是:(选择1项) A) 子类继承父类,那么子类将继承父类的所有...

    Java编程艺术 PDF

    8.6.3 Graphs类的final变量和实例变量 241 8.6.4 Graphs类的构造函数 242 8.6.5 paint()方法 244 8.6.6 bargraph()方法 247 8.6.7 scatter()方法 247 8.6.8 regplot()方法 248 8.7 一个统计表的应用 248 8.7.1 ...

    java 编程艺术

    8.6.3 Graphs类的final变量和实例变量 241 8.6.4 Graphs类的构造函数 242 8.6.5 paint()方法 244 8.6.6 bargraph()方法 247 8.6.7 scatter()方法 247 8.6.8 regplot()方法 248 8.7 一个统计表的应用 248 ...

    baseFinal:使用 Gulp.js 的任务管理器

    以“src”开头的变量是那些指示我们将要编译或缩小的文件路径的变量(重要的是要注意具有 .js 文件路径的名为“src_js”的数组的顺序,这避免了库之间的冲突)。 以“dest”开头的变量是那些指示编译文件将被存储...

Global site tag (gtag.js) - Google Analytics