Java 编译器会对此进行优化吗
假设我在C代码中有类似的东西。我知道你可以用一个Java 编译器会对此进行优化吗,java,c,optimization,Java,C,Optimization,假设我在C代码中有类似的东西。我知道你可以用一个#define来代替,让编译器不编译它,但出于好奇,我问编译器是否也会解决这个问题 我认为这对于Java编译器更为重要,因为它不支持#define const int CONDITION = 0; ........ // Will the compiler compile this? if ( CONDITION ) { } ....... 首先,Java不允许C等条件中使用非布尔值(if,while等)。此外,如果您的中有一个“常量”表达式,
#define
来代替,让编译器不编译它,但出于好奇,我问编译器是否也会解决这个问题
我认为这对于Java编译器更为重要,因为它不支持#define
const int CONDITION = 0;
........
// Will the compiler compile this?
if ( CONDITION )
{
}
.......
首先,Java不允许C等条件中使用非布尔值(
if
,while
等)。此外,如果您的中有一个“常量”表达式,如果检查,编译器将警告您正在比较相同的表达式,因此我确信它已优化
final int i = 1;
if (1 == i) { // warning
System.out.println("HI");
}
在Java中,if中的代码甚至不会成为已编译代码的一部分。它必须编译,但不会写入已编译的字节码。它实际上取决于编译器,但我不知道有哪种编译器不会对其进行优化。规则定义如下:
优化编译器可能会意识到,语句x=3;永远不会
可以选择从中省略该语句的代码
生成的类文件,但语句x=3;不被视为
此处规定的技术意义上的“无法达到”
这种不同处理的基本原理是允许程序员
定义“标志变量”,例如:
然后编写如下代码:
if (DEBUG) { x=3; }
其思想是,应该可以更改DEBUG的值
从false到true或从true到false,然后编译代码
正确无需对程序文本进行其他更改
不了解C。我能回忆起Java和C程序中的场景,它在哪里(优化了它)。但我也知道它在很大程度上取决于编译器设置——因此场景太不具体了
在Java场景中,我们在一个Java源文件中使用const值,而在另一个类(文件)中使用它们。发生的事情是,当我们只是用const值更改并重新编译文件时,使用部分的流程没有任何更改。我们必须重新编译整个项目(这就是它被优化的证据).与其问这么简单的问题(唯一正确的答案是“用你的编译器试试”),为什么不试试呢
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."<init>":()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
}
公共类测试{
公共静态void main(字符串[]args){
如果(真){
System.out.println(“是”);
}
布尔值var=false;
if(var){
系统输出打印号(“Nope”);
}
最终布尔值var2=false;
if(var2){
系统输出打印号(“Nope”);
}
}
}
javac.\Test.java
javap-c测试
从“Test.java”编译而来
公开课考试{
公开考试();
代码:
0:aload_0
1:invokespecial#1//方法java/lang/Object。“:()V
4:返回
公共静态void main(java.lang.String[]);
代码:
0:getstatic#2//Field java/lang/System.out:Ljava/io/PrintStream;
3:ldc#3//字符串是
5:invokevirtual#4//方法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 yes
19:invokevirtual#4//方法java/io/PrintStream.println:(Ljava/lang/String;)V
22:返回
}
你不需要了解太多关于java/c字节码或汇编的知识,就可以理解正在发生的事情。现在,你可以尝试同样的方法来处理c。下面是针对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
}
// ..
const int i = 1;
// mov dword ptr [i], 1
if (i)
{
}
// ..
用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
}
// ..
const int i = 1;
// mov dword ptr [i], 1
if (i)
{
}
// ..
我只是用下面的代码快速检查了一下
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
这意味着compile肯定会对静态最终值进行优化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++编译器都会检测并优化这种类型的死区代码,即使编译时没有指定优化选项。
为什么不试试看,重新查看一下。生成二进制代码?具体来说,您可以在类上使用javap-c命令打印出字节码,这实际上非常容易阅读。我记得看到if(false){…}
作为Java中排除代码的推荐方法,在C预处理器中使用a la#if
。那是几年前的事了。@Joe和我从未理解过这种吸引力。在任何现代IDE上,注释几行代码都比编写if()快更清楚的是。我有一个糟糕的习惯——只有在手头没有好的IDE时才需要。@Voo——如果你有很多块应该一起禁用,可能分布在所有类中呢?仅仅更改一个常量的值肯定会更快,更不容易出错。(但我也不喜欢这个想法)这是用标准JDK1.6T实现的吗