有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java JVM会优化别名变量吗?

我很好奇。如果我制作了一些局部变量,这些局部变量只是用作其他变量的别名(即,一个新的“别名”变量只是被分配了其他变量的值,而别名的分配永远不会改变),JVM是否通过直接使用原始变量对此进行了优化

比如说,我正在编写一个(不可变的)四元数类(aquaternion是一个有四个值的向量)。我编写了一个multiply()方法,它接受另一个Quaternion,将二者相乘,然后返回结果Quaternion。为了节省键入时间并提高可读性,我在执行实际计算之前使用了几个别名:

public class Quaternion {

    private double[] qValues;

    public Quaternion(double q0, double q1, double q2, double q3) {
        qValues = new double[] {q0, q1, q2, q3};
    }

    // ...snip...

    public Quaternion multiply(Quaternion other) {
        double a1 = qValues[0],
                 b1 = qValues[1],
                 c1 = qValues[2],
                 d1 = qValues[3],

                 a2 = other.qValues[0],
                 b2 = other.qValues[1],
                 c2 = other.qValues[2],
                 d2 = other.qValues[3];

        return new Quaternion(
                    a1*a2 - b1*b2 - c1*c2 - d1*d2,
                    a1*b2 + b1*a2 + c1*d2 - d1*c2,
                    a1*c2 - b1*d2 + c1*a2 + d1*b2,
                    a1*d2 + b1*c2 - c1*b2 + d1*a2
                );
    }

}

因此,在这种情况下,JVM会取消a1b1等,直接使用qValues[n]other.qValues[n]


共 (4) 个答案

  1. # 1 楼答案

    没有您在Java中描述的别名。当您将一个值从一个内存位置分配给一个新变量时,JVM会复制该值。如果要创建别名,则在计算期间从另一个线程更改基础数组将改变结果。在您的示例中不会发生这种情况,因为您特别告诉JVM首先复制这些值

    如果您担心性能,请不要担心。程序正确性胜过所有性能问题。任何更快产生错误结果的程序都是毫无价值的。我并不是说直接在计算中访问数组必然会产生错误的结果,因为我还没有看到代码的其余部分,但我是说,如果不首先找到性能问题,然后执行计时测试以验证问题所在,这种类型的微优化就不值得您的努力

  2. # 2 楼答案

    javac编译器不会这么做。分解一段简单的代码,如下所示:

        int a = 1;
        int b = a;
        System.out.println("" + (a - b));
    

    显示:

       0: iconst_1      
       1: istore_1      
       2: iload_1       
       3: istore_2
       ...
    

    但这就是解释器将要执行的(甚至解释器有时也可以进行一些基本的优化)。JIT编译器将处理这些类型的优化和许多其他优化;对于您的方法,它甚至小到可以内联,所以一旦JIT开始,您甚至不会得到方法调用开销

    (例如,在我的示例中,JIT可以非常轻松地进行常量传播,只需使用"" + 0作为println()方法的参数调用,就可以省去变量和计算。)

    但是,在最后,只需遵循JIT黑客们经常说的话:编写可维护的代码。不要担心JIT会做什么或不会做什么

    (注意:David关于变量不是“别名”,而是原始值的副本的说法是正确的。)

  3. # 3 楼答案

    正如其他答案所指出的,Java中没有别名变量的概念,变量的值存储在每个声明的变量中

    使用局部变量存储数组的值以供将来计算是一个更好的主意,因为它使代码更具可读性,并消除了对数组的额外读取

    也就是说,创建局部变量确实会增加方法线程中分配的java堆栈帧的大小。这在这个特定的问题中不是问题,但是更多的局部变量会增加执行所需的堆栈大小。如果涉及递归,这将特别重要

  4. # 4 楼答案

    您的程序应该可以运行,但问题的答案是否定的。JVM不会将a1视为qValues[0]的别名,而是将后者的值复制到前者

    检查此良好引用:http://www.yoda.arachsys.com/java/passing.html