正如我的标题中所总结的,我想知道涉及实例化时定义的常量的表达式是否在编译时得到简化?
例如,我有一个堆类,其中有一个最终布尔值 isMinHeap,其值在堆的构造函数中设置。然后堆的方法在某些地方使用这个布尔值。编译器是否可以对此进行优化以简化所有涉及此布尔值的表达式,或者每次调用方法时都会完整计算表达式?
谢谢!
编辑: 因为有人问我一个更具体的例子,下面是每次从堆中删除节点时调用的方法(以帮助重新堆化树):
private boolean requiresRepositioningDown(BTNode<T> node)
{
boolean childIsSmaller = (node.getLeft().getValue().compareTo(
node.getValue()) < 0)
|| (node.getRight() != null && node.getRight().getValue().compareTo(
node.getValue()) < 0);
if (isMinHeap && childIsSmaller || !isMinHeap && !childIsSmaller)
return true;
else
return false;
}
这里带有 isMinHeap 的表达式似乎每次都会被完整求值,而如果堆在实例化时被设置为最大堆,则表达式的整个右侧可以(并且应该)被忽略。
很可能不会。首先,它在编译时对于类来说仍然不是恒定的;仍然可能有两种情况不同。这种优化通常留给 JIT 编译器。 即使您的常量从未设置为其他任何值,这也不会被优化。例如
public class Heap {
final boolean isMinHeap;
public Heap() {
isMinHeap = true;
}
@Override
public String toString() {
if (isMinHeap) return "Min!";
return "Not Min";
}
}
编译为
public java.lang.String toString();
Code:
0: aload_0
1: getfield #2 // Field isMinHeap:Z
4: ifeq 10
7: ldc #3 // String Min!
9: areturn
10: ldc #4 // String Not Min
12: areturn
请注意,条件仍然存在。如果经常使用该方法,JIT 编译器可能会选择完全删除它,因为它应该知道
final
成员无法更改。但这有点难以观察。
如果您立即将
isMinHeap
设置为一个值,而不是在构造函数中执行此操作,
然后将执行优化:
public class Heap {
final boolean isMinHeap = true;
public Heap() {
}
@Override
public String toString() {
if (isMinHeap) return "Min!";
return "Not Min";
}
}
将
toString
编译为:
public java.lang.String toString();
Code:
0: ldc #3 // String Min!
2: areturn
无法针对仅在执行时已知的值进行优化。在该术语的正常使用中,这样的值并不是真正的“常数”。我相信,真正的常量表达式可以在编译时被简化被简化 - 所以如果你有:
public static final int FOO = 10;
public static final int BAR = 20;
...
System.out.println(FOO * BAR):
我相信乘法将在编译时执行。但是,在您描述的情况下这是不可能的,因为它们不是编译时常量。
JIT 编译器也许能够发现常见的表达式,但您必须给我们一个更具体的示例(在代码中,而不仅仅是描述)才能获得任何确定性。