Java中的条件编译:编译器会从类中省略“always false”块吗?

时间:2012-06-11 19:02:31

标签: java

以下是我的代码片段:

class A { 

   private boolean debug = false;

   // Called when server boots up.
   public void init (property) { 
      debug = property.getBoolean ("debug_var"); // read debug from a config file.
   }

   // some other function  
   public void foo () { 
       if (debug) { 
                 System.out.println ("From inside the debug block");
       }
   }
 }

当我运行代码时,if(debug)实际打印出“来自调试块内部”,如果在配置文件中调试== true。

两个问题:

  1. 因此,在这种情况下,编译器是否在.class文件中包含if块只是因为变量debug的值可能在运行时发生变化?

  2. 如果这是真的,那么如何在某些环境中消除某些代码被添加到.class文件?

6 个答案:

答案 0 :(得分:4)

如果必须这样做,大多数日志记录框架都有自己设置日志详细信息级别的方法,并且它们不会在运行时输出任何过低级别的日志语句。使用日志框架来正确执行此操作。

例如,使用内置的java.util.logging框架,您可以执行类似

的操作
Logger.getLogger("ThisClass").log(Level.FINE, "Log message");

仅在日志级别设置为FINE或更低时才会打印,但在日志级别为CONFIG或更低时会被忽略。

“条件编译”在Java中并不是一个有意义的事情,但是要小心谨慎,JIT将优化它可以确定永远不会被执行的分支。

答案 1 :(得分:1)

没有什么比条件编译更好的了(除非java找到一个保证不执行的条件)。您的类文件包含的字节代码与Java文件中的字节代码相同。

编辑:正如aiobee所指出的,如果编译器发现它们不被执行,编译器可能会省略它们。

答案 2 :(得分:1)

正如其他人所指出的,Java编译器通常非常幼稚,只是将您拥有的Java源代码转换为Java字节码。例如,if语句通常被转换为条件分支,无论您是否发现分支条件总是错误。

然而,从理论的角度来看,没有什么可以阻止编译器弄清楚某些分支永远不会被占用,并且只是在字节码中省略它们。 Java语言规范中没有任何内容规定在定位字节码时应该如何编译

答案 3 :(得分:1)

最接近的是使用静态变量,这在运行时是无用的(基本上)。

但是,在您的示例中,JVM可能会在运行足够多次后对其进行优化,因此如果您关注的是运行时效率,则可能不值得担心。

最终我会问你为什么要根据环境从 class 文件中删除代码 - 如果它不是可以在运行时更改的东西那么你最好的选择就是创建一些可插拔实现的形式,可以在运行时确定/注入。

答案 4 :(得分:0)

  1. 是的,编译器会将其包含在.class文件中。
  2. 没有条件编译机制。您可以使用编译器插件(在JDK 1.7及更高版本中)模拟其中一些,或者您可以尝试使用像AspectJ这样的字节码操作技术来实现类似的效果。

答案 5 :(得分:0)

过去,如果您将布尔值声明为staticfinal并将其值设置为false,则编译器会忽略该代码。那是原始的Java编译器。我不知道当前的那个是否这样做(现在已经存在了很长时间)。这背后的基本原理是允许您使applet下载更小。它至多是一种笨重的机制,所以没有广泛使用。

要测试它,请将您的debug var更改为private static final boolean debug=false;编译它,保存类文件,然后将其翻转为true。然后再次编译它,看看类文件是否不同。顺便说一下,当debug被声明为final时,你的init函数将无效。

相关问题