Java 不可达语句:while true vs if true
我应该如何理解这种Java编译器行为Java 不可达语句:while true vs if true,java,javac,unreachable-code,Java,Javac,Unreachable Code,我应该如何理解这种Java编译器行为 while (true) return; System.out.println("I love Java"); // Err: unreachable statement if (true) return; System.out.println("I hate Java"); // OK. 谢谢 编辑: 几分钟后我发现了要点: 在第一种情况下,编译器由于无限循环而抛出错误。在这两种情况下,编译器都不会考虑后续语句中的代码 编辑II: 现在让我对javac
while (true) return;
System.out.println("I love Java");
// Err: unreachable statement
if (true) return;
System.out.println("I hate Java");
// OK.
谢谢
编辑:
几分钟后我发现了要点:
在第一种情况下,编译器由于无限循环而抛出错误。在这两种情况下,编译器都不会考虑后续语句中的代码
编辑II:
现在让我对javac印象深刻的是:
if (true) return; // Correct
}
while (true) return; // Correct
}
看起来javac知道两个循环中都有什么,如果是结果,
但是,当您编写另一个命令(如第一个示例中所示)时,您会得到非等效的行为(看起来javac忘记了loop/if中的内容)
公共静态最终编辑III:
作为回答的结果,我可能会说(希望是正确的):
如果(arg){…;return;}和而(arg){…;return;}
的表达式在语义和语法(字节码)上都是等价的,那么Java iffargv
是非常量(或实际上是最终类型)表达式。如果argv
为常量,则表达式字节码(和行为)可能不同
免责声明
这个问题不是关于不可访问的语句,而是对逻辑等价表达式的不同处理,如
while true return
和if true return
在java中可访问语句时有非常严格的规则。这些规则设计为易于评估,而不是100%准确。它应该可以防止基本的编程错误。为了解释java中的可达性,您仅限于这些规则,“公共逻辑”不适用
下面是Java语言规范中的规则
if-then语句在可到达时可以正常完成
因此,如果没有else,if-then之后的语句总是可以到达的
如果以下至少一项为真,则while语句可以正常完成:
- while语句是可访问的,条件表达式不是值为true的常量表达式(§15.28)
- 有一个可到达的break语句退出while语句
如果您稍微更改代码(删除常量表达式),这样就不会触发javac可达性,那么实际上会为这两种语言生成相同的字节码
static boolean flag = true;
static void twhile(){
while (flag) return;
System.out.println("Java");
}
static void tif(){
if (flag) return;
System.out.println("Java");
}
生成的字节码:
static void twhile();
descriptor: ()V
flags: ACC_STATIC
Code:
stack=2, locals=0, args_size=0
StackMap locals:
StackMap stack:
0: getstatic #10 // Field flag:Z
3: ifeq 7
6: return
StackMap locals:
StackMap stack:
7: getstatic #20 // Field java/lang/System.out:Ljava/io/PrintStream;
10: ldc #26 // String Java
12: invokevirtual #28 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
15: return
LineNumberTable:
line 8: 0
line 9: 7
line 10: 15
LocalVariableTable:
Start Length Slot Name Signature
StackMapTable: number_of_entries = 1
frame_type = 7 /* same */
static void tif();
descriptor: ()V
flags: ACC_STATIC
Code:
stack=2, locals=0, args_size=0
StackMap locals:
StackMap stack:
0: getstatic #10 // Field flag:Z
3: ifeq 7
6: return
StackMap locals:
StackMap stack:
7: getstatic #20 // Field java/lang/System.out:Ljava/io/PrintStream;
10: ldc #26 // String Java
12: invokevirtual #28 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
15: return
LineNumberTable:
line 12: 0
line 13: 7
line 14: 15
LocalVariableTable:
Start Length Slot Name Signature
StackMapTable: number_of_entries = 1
frame_type = 7 /* same */
这是一个“如果我写了疯狂的代码,编译器也可能表现得疯狂”的例子。请仔细阅读。@marek094,您这样比较的目的是什么?Java不是低级语言,也就是说编译器不是机器语言编译器。你想要的确切答案是什么,或者你想问的确切问题是什么?另外,考虑到目前可用的虚拟机和编译器的数量,在我看来,这是一个非常通用且信息量较少的问题。@Siddharttyagi这是为我的考试做准备,我希望在考试中回答写在论文上的类似问题。¯_(ツ)_/“@marek094只有在语法正确的情况下,您才有合理的语义。任何可编译代码可能都没有语义意图,但没有实际的语义。是的,我阅读了常量表达式大小写的字节码,其差异非常模糊。@marek094因为您没有提供常量表达式大小写的可编译示例,所以很难理解。”比较。在我的测试中,它会产生“noops”,周围有不同的绒毛。你是对的,我指的是我问题中的第二个例子。我知道,情况不一样,但也很有趣。我记得看到了这一点的基本原理。基本思想是你可以有
if(编译开关)return;A
并让程序正确编译,而不管开关的值如何。