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会取消a1
、b1
等,直接使用qValues[n]
和other.qValues[n]
吗
# 1 楼答案
没有您在Java中描述的别名。当您将一个值从一个内存位置分配给一个新变量时,JVM会复制该值。如果要创建别名,则在计算期间从另一个线程更改基础数组将改变结果。在您的示例中不会发生这种情况,因为您特别告诉JVM首先复制这些值
如果您担心性能,请不要担心。程序正确性胜过所有性能问题。任何更快产生错误结果的程序都是毫无价值的。我并不是说直接在计算中访问数组必然会产生错误的结果,因为我还没有看到代码的其余部分,但我是说,如果不首先找到性能问题,然后执行计时测试以验证问题所在,这种类型的微优化就不值得您的努力
# 2 楼答案
javac编译器不会这么做。分解一段简单的代码,如下所示:
显示:
但这就是解释器将要执行的(甚至解释器有时也可以进行一些基本的优化)。JIT编译器将处理这些类型的优化和许多其他优化;对于您的方法,它甚至小到可以内联,所以一旦JIT开始,您甚至不会得到方法调用开销
(例如,在我的示例中,JIT可以非常轻松地进行常量传播,只需使用
"" + 0
作为println()方法的参数调用,就可以省去变量和计算。)但是,在最后,只需遵循JIT黑客们经常说的话:编写可维护的代码。不要担心JIT会做什么或不会做什么
(注意:David关于变量不是“别名”,而是原始值的副本的说法是正确的。)
# 3 楼答案
正如其他答案所指出的,Java中没有别名变量的概念,变量的值存储在每个声明的变量中
使用局部变量存储数组的值以供将来计算是一个更好的主意,因为它使代码更具可读性,并消除了对数组的额外读取
也就是说,创建局部变量确实会增加方法线程中分配的java堆栈帧的大小。这在这个特定的问题中不是问题,但是更多的局部变量会增加执行所需的堆栈大小。如果涉及递归,这将特别重要
# 4 楼答案
您的程序应该可以运行,但问题的答案是否定的。JVM不会将
a1
视为qValues[0]
的别名,而是将后者的值复制到前者检查此良好引用:http://www.yoda.arachsys.com/java/passing.html