Java编译器会优化对final静态变量的方法调用吗?当它变成Dalvik代码时会发生什么?

5
我有以下代码。
 float square(float val) { return val*val;}
 boolean isInCircle(final float x,final float y) {

        float squareDistance = square(cx - x) + square(cy - y);
        return squareDistance < square(RADIUS);
    }

其中RADIUS是一个static finalfloat

Java编译器会优化调用square(RADIUS)吗?

当它被转换为androiddalvik代码时会发生什么?它是否仍然保持优化?

4个回答

3

Java编译器不会处理那段代码。

HotSpot JVM几乎肯定会预先计算square(半径)。

Android没有那个特定的JVM。

我个人不会编写square()方法,只需使用return (cx-x)*(cx-x)+(cy-y)*(cy-y) < RADIUS*RADIUS;,让编译器/JVM自行处理。但我是一个数学家;-)


3
正如每个Android工程师都会坚持告诉每个人的那样:Android根本没有JVM。它只有一个" Dalvik VM "。;-) - Joachim Sauer
@JoachimSauer 我能理解为什么... :-| - user207421

2

Dalvik JIT编译器确实会内联短函数,例如在问题中定义的 square()(虽然最好声明为 static )。但是,我无法立即告诉您它是否一定会被内联。

如果有必要,请对代码进行分析!


1

Java的优化是由HotSpot编译器在运行时完成的(当字节码被翻译成机器码时进行优化)。所以答案是肯定的和否定的。

转换后的代码将同样被优化,但这取决于JVM会对其进行什么处理。根据我的经验,这高度依赖于JVM,可能还与其设置(优化器的攻击性)有关。我曾尝试在Windows JVM和Linux JVM上比较带循环和不带循环的SHA1运行情况。在某些情况下,没有循环的代码运行速度快了很多,在另一种情况下(我想是在Linux上),只有时间花费的40%左右的差异...

所以这是一种魔法,你可以给HotSpot提供良好的优化提示,或者配置JVM,但仍然取决于JVM当前的算法...


1
严格来说,优化是由JVM执行的。 “HotSpot”只是JVM的一种可能实现(尽管在桌面/服务器环境中最常见)。 - Joachim Sauer
1
@GautamK:实际上,这并不容易检测。如果派生类有一个不同的square()实现呢?那么编译器所做的任何“优化”都是错误的。此外:Java的基本原则之一是编译器本身不进行真正的优化,而是将源代码直接转换为字节码。所有真正的优化都留给了JVM,在运行时它拥有更多的信息。例如:JVM将知道是否存在派生类,并且可以内联(甚至预计算)square调用。 - Joachim Sauer
@JoachimSauer 好的,那么 javac 不进行任何优化吗? 如果 squarefinal 的呢? - Gautam
2
@GautamK: 几乎为零。与编译时的常量表达式相关的优化非常有限。基本上,如果编译器能够保证表达式的值,那么它将用预先计算的结果来替代它。例如 int i = 2*3; 编译后将变成相同的字节码 int i = 6; (参见JLS §15.28)。 - Joachim Sauer
1
所以,如果“RADIUS”是静态的和不可变的,并且在声明时初始化(使用常量表达式),那么将条件重写为squareDistance < RADIUS * RADIUS将会得到优化后的代码。 - Joachim Sauer
显示剩余3条评论

-1
唯一的优化是编译器很可能会在访问静态 final 字段时将其“内部化”为常量,而不是在运行时执行字段查找。

"实习生"? 你是指 "内联" 吗? - user207421

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接