1

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

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

4

2 回答 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
于 2012-07-21T08:08:47.607 回答
1

原始的源代码到字节码的编译器无法针对仅在执行时才知道的值进行优化。在该术语的正常使用中,这样的值并不是真正的“常数”。我相信,可以在编译时简化的真正常量表达式被简化了——所以如果你有:

public static final int FOO = 10;
public static final int BAR = 20;

...

System.out.println(FOO * BAR):

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

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

于 2012-07-21T08:10:35.470 回答