在 Java 中:涉及实例化时定义的常量的表达式在编译时会得到简化吗?

问题描述 投票:0回答:2

正如我的标题中所总结的,我想知道涉及实例化时定义的常量的表达式是否在编译时得到简化?

例如,我有一个堆类,其中有一个最终布尔值 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 的表达式似乎每次都会被完整求值,而如果堆在实例化时被设置为最大堆,则表达式的整个右侧可以(并且应该)被忽略。

java optimization constants compile-time
2个回答
2
投票

很可能不会。首先,它在编译时对于类来说仍然不是恒定的;仍然可能有两种情况不同。这种优化通常留给 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



1
投票
编译器

无法针对仅在执行时已知的值进行优化。在该术语的正常使用中,这样的值并不是真正的“常数”。我相信,真正的常量表达式可以在编译时被简化被简化 - 所以如果你有: public static final int FOO = 10; public static final int BAR = 20; ... System.out.println(FOO * BAR):

我相信乘法将在编译时执行。但是,在您描述的情况下这是不可能的,因为它们不是编译时常量。

JIT 编译器也许能够发现常见的表达式,但您必须给我们一个更具体的示例(在代码中,而不仅仅是描述)才能获得任何确定性。

© www.soinside.com 2019 - 2024. All rights reserved.