编译器会优化它吗?

说我在C代码中有这样的东西。 我知道你可以使用#define来使编译器不能编译它,但只是出于好奇,我问的是编译器是否也会想出这个问题。

我认为这对Java编译器来说更为重要,因为它不支持#define

 const int CONDITION = 0; ........ // Will the compiler compile this? if ( CONDITION ) { } ....... 

在Java中,if中的代码甚至不会是编译代码的一部分。 它必须编译,但不会写入编译的字节码。 它实际上取决于编译器,但我不知道没有优化它的编译器。 规则在JLS中定义:

优化编译器可以实现语句x = 3; 将永远不会执行,并可能选择从生成的类文件中省略该语句的代码,但语句x = 3; 在此处指定的技术意义上,不被视为“无法访问”。

这种不同处理的基本原理是允许程序员定义“标志变量”,例如:

 static final boolean DEBUG = false; 

然后编写如下代码:

 if (DEBUG) { x=3; } 

我们的想法是,应该可以将DEBUG的值从false更改为true或从true更改为false,然后正确编译代码而不对程序文本进行其他更改。

关于C.不知道

首先,Java不允许像C这样的条件句中的非布尔值( ifwhile等)。 另外,如果你在if检查中有一个“常量”表达式,编译器会警告你正在比较相同的表达式,所以我确定它已经优化了。例如

  final int i = 1; if (1 == i) { // warning System.out.println("HI"); } 

而不是问这么简单的问题(唯一正确的答案是“用你的编译器试试”) – 为什么不试试呢?

 public class Test { public static void main(String[] args) { if (true) { System.out.println("Yep"); } boolean var = false; if (var) { System.out.println("Nope"); } final boolean var2 = false; if (var2) { System.out.println("Nope"); } } } javac .\Test.java javap -c Test Compiled from "Test.java" public class Test { public Test(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."":()V 4: return public static void main(java.lang.String[]); Code: 0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; 3: ldc #3 // String Yep 5: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 8: iconst_0 9: istore_1 10: iload_1 11: ifeq 22 14: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; 17: ldc #3 // String Yep 19: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 22: return } 

您不需要了解java / c#字节码或汇编就能够了解正在发生的事情。 现在去尝试同样的C#..

我只是用下面的代码快速检查了一下

 public class Test { private static final boolean flag = true; public static void main(String[] args) throws InterruptedException { if(flag){ System.out.println("1"); System.out.println("1"); System.out.println("1"); System.out.println("1"); System.out.println("1"); System.out.println("1"); System.out.println("1"); System.out.println("1"); System.out.println("1"); } } } 

当flag = true时,生成的类文件大小为708

当flag = false时。 结果类文件大小为462

这意味着编译肯定会对静态最终值进行优化

我可以回想一下我的Java和C#程序中的场景,它确实在哪里(优化它)。 但我也知道它在很大程度上取决于编译器设置 – 因此场景太不明确了。

在Java场景中,我们在一个Java源文件中使用了const值,而在另一个类(文件)中使用了它们。 发生了什么,当我们刚刚更改并使用const值重新编译文件时,使用部分的流程没有任何变化。 我们不得不重新编译整个项目(这是它被优化的证据)。

以下是C语言的具体内容。 我不知道Java如何处理它。

由于int被定义为const ,因此if (i)变为no-op指令。 智能编译器应该能够优化掉那个空的if语句。

示例 :VC 2008

if语句的非空{}

 const int i = 1; // mov dword ptr [i], 1 if (i) // mov eax, 1 // test eax, eax // je wmain+35h { int j = 2; // move dword ptr [j], 2 } // .. 

使用if语句清空{}

 const int i = 1; // mov dword ptr [i], 1 if (i) { } // .. 

java编译器必须检测明显无法访问的代码,这是语言要求。 所以下面的代码将编译没有错误:

 static final boolean flag = true; public static void main(String[] args) { final String msg; if (flag) msg = "true"; if (!flag) msg = "false"; System.out.println(msg); } 

请注意,msg是最终的,但编译器既没有抱怨msg没有初始化也没有抱怨它被初始化两次。 大多数编译器不会将死代码写入类文件。 但即便如此,JIT也会对其进行优化。

C ++也有编译时常量的概念。 const int是一个编译时常量,因此它可以用作非类型模板参数。 因此,即使您在不指定优化选项的情况下进行编译,每个理智的C ++编译器都会检测并优化掉这种类型的死代码。