gpt4 book ai didi

java - JVM到底是如何编译三元运算符的?我应该关注不同的 api 版本吗?

转载 作者:行者123 更新时间:2023-11-29 07:04:26 25 4
gpt4 key购买 nike

所以,假设我有这段代码:

int mode = android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB ? AudioManager.MODE_IN_COMMUNICATION : AudioManager.MODE_IN_CALL;

现在,假设我在某个还没有 Gingerbread 的设备上运行这段代码。

AudioManager.MODE_IN_COMMUNICATION 的不可用静态导入是否会被命中?

我的意思是,在检查 Gingerbread 之前是否存在由于 MODE_IN_COMMUNICATION 不可用而导致崩溃的情况?

三元运算符如何在 Java 中编译?它会将这两个东西编译为整数吗?编译时是否展开代码?

最佳答案

滚动到我的答案的底部,看看实际的 javac 源代码做了什么:)

生成的字节码

@zapl 的回答肯定回答了具体问题,但我觉得 OP 的问题仍然没有得到回答。 JVM 究竟是如何编译三元运算符的?所以,我只想为大家解答这个问题。

我们可以通过查看实际生成的字节码来弄清楚这一点。所以,我创建了一个测试,其中我有两个外部类,它们有一些我正在引用的静态变量,等等,但这仍然不是重点,因为我们只想知道它是否以与 if-else 相同的方式编译它.不管怎样,我用三元和等效的 if-else 做了一个测试,结果如下。

Java 代码:

class main {
public static void main(String[] args) {
int a = 0;
int b = 2;
int c = a > b ? MyBigClass.VAR_1 : MyOtherBigClass.VAR_2;
//int c;
// if (a > b) {
// c = MyBigClass.VAR_1;
// } else {
// c = MyOtherBigClass.VAR_2;
// }
}
}

class MyBigClass {
public static int VAR_1 = 0;
}

class MyOtherBigClass {
public static int VAR_2 = 1;
}

如您所见,我在测试 if-else 时注释掉了 if-else,然后我在测试 if-else 时只注释掉了三元。生成的字节码是这样的。

使用 if-else 的字节码:

  public static void main(java.lang.String[]);
Code:
0: iconst_0
1: istore_1
2: iconst_2
3: istore_2
4: iload_1
5: iload_2
6: if_icmple 16
9: getstatic #2 // Field MyBigClass.VAR_1:I
12: istore_3
13: goto 20
16: getstatic #3 // Field MyOtherBigClass.VAR_2:I
19: istore_3
20: return

使用三元的字节码:

  public static void main(java.lang.String[]);
Code:
0: iconst_0
1: istore_1
2: iconst_2
3: istore_2
4: iload_1
5: iload_2
6: if_icmple 15
9: getstatic #2 // Field MyBigClass.VAR_1:I
12: goto 18
15: getstatic #3 // Field MyOtherBigClass.VAR_2:I
18: istore_3
19: return

生成的字节码实际上只有一个额外的指令,它将结果存储在 if 语句的第一个分支中(而三元仅在比较结束时存储结果)。因此,三元组仅根据参数的评估执行将遵循的分支,就像 if-else 语句一样。

而且,因为我很好奇,我决定检查双三元是否等同于 if-elif-else。 (这是剧透)。我用这段代码来测试它,与上面的过程相同:

    public static void main(String[] args) {
int a = 0;
int b = 2;
int c = 3;
int d = a > b ? MyBigClass.VAR_1 : a > c ? MyOtherBigClass.VAR_2 : 0;
// int d;
// if (a > b) {
// d = MyBigClass.VAR_1;
// } else if (a > c) {
// d = MyOtherBigClass.VAR_2;
// } else {
// d = 0;
// }
}

为 if-elif-else 生成的字节码:

  public static void main(java.lang.String[]);
Code:
0: iconst_0
1: istore_1
2: iconst_2
3: istore_2
4: iconst_3
5: istore_3
6: iload_1
7: iload_2
8: if_icmple 19
11: getstatic #2 // Field MyBigClass.VAR_1:I
14: istore 4
16: goto 35
19: iload_1
20: iload_3
21: if_icmple 32
24: getstatic #3 // Field MyOtherBigClass.VAR_2:I
27: istore 4
29: goto 35
32: iconst_0
33: istore 4
35: return

为三元生成的字节码:

  public static void main(java.lang.String[]);
Code:
0: iconst_0
1: istore_1
2: iconst_2
3: istore_2
4: iconst_3
5: istore_3
6: iload_1
7: iload_2
8: if_icmple 17
11: getstatic #2 // Field MyBigClass.VAR_1:I
14: goto 29
17: iload_1
18: iload_3
19: if_icmple 28
22: getstatic #3 // Field MyOtherBigClass.VAR_2:I
25: goto 29
28: iconst_0
29: istore 4
31: return

Javac 源代码的实际作用

献给勇敢者和少数人

我决定查看 javac 的源代码...这花了一段时间,但在他们的 javac 搭便车指南的帮助下,我找到了明确确定发生了什么的一行。检查一下(第 914 行):https://hg.openjdk.java.net/jdk9/jdk9/langtools/file/65bfdabaab9c/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java你看到了吗?让我澄清一下,第 905-918 行是这样说的:

    /** Expression1Rest = ["?" Expression ":" Expression1]
*/
JCExpression term1Rest(JCExpression t) {
if (token.kind == QUES) {
int pos = token.pos;
nextToken();
JCExpression t1 = term();
accept(COLON);
JCExpression t2 = term1();
return F.at(pos).Conditional(t, t1, t2);
} else {
return t;
}
}

注释告诉我们这是他们用来解析三元表达式的东西,如果我们查看它返回的内容,它会返回一个条件,其中 t 是正在评估的表达式,t1 是第一个分支,t2 是第二个分支。让我们看一下 Conditional 只是为了确定。看起来Conditional 是从F 调用的,如果我们深入挖掘,我们可以发现是TreeMaker,什么是树你可能会问制造商?好吧,它特别是一个抽象语法树,通常用作被解析代码的中间表示(在此处查看 https://en.wikipedia.org/wiki/Abstract_syntax_tree )。无论如何,如果我们查看该文件 (https://hg.openjdk.java.net/jdk9/jdk9/langtools/file/65bfdabaab9c/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeMaker.java),我们可以在第 306-313 行看到:

    public JCConditional Conditional(JCExpression cond,
JCExpression thenpart,
JCExpression elsepart)
{
JCConditional tree = new JCConditional(cond, thenpart, elsepart);
tree.pos = pos;
return tree;
}

这进一步证实了我们的想法,三元表达式的编译方式与 if-else 语句(也称为条件语句)完全相同 :) 我鼓励任何有兴趣的人看一看漫游者指南(https://openjdk.java.net/groups/compiler/doc/hhgtjavac/index.html ) 和代码,看到商业级编译器如何遵循您在大学标准编译器类(class)中学到的许多原理性知识,实际上真的很有趣。

关于java - JVM到底是如何编译三元运算符的?我应该关注不同的 api 版本吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21443995/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com