Java 文字的算术运算是在编译时还是运行时计算的?

Java 文字的算术运算是在编译时还是运行时计算的?,java,Java,我有以下资料: double timeInMinutes = (double) timeInMilliseconds / (1000 * 60); 操作(1000*60)是在编译时还是在运行时完成的?换句话说,上述代码段和以下代码段在运行时是否存在性能差异: double timeInMinutes = (double) timeInMilliseconds / 60000; 编辑:我的问题不同于,因为我在算术运算中混合使用变量和文字。这是一个很小的区别,但正如@TagirValeev在注释

我有以下资料:

double timeInMinutes = (double) timeInMilliseconds / (1000 * 60);
操作
(1000*60)
是在编译时还是在运行时完成的?换句话说,上述代码段和以下代码段在运行时是否存在性能差异:

double timeInMinutes = (double) timeInMilliseconds / 60000;

编辑:我的问题不同于,因为我在算术运算中混合使用变量和文字。这是一个很小的区别,但正如@TagirValeev在注释()中所指出的,有些情况下,某些文本没有预编译,即使它们可能在编译时被预编译。

。这是最基本的编译器优化之一,根据

有些表达式的值可以在编译时确定。 这些是常量表达式(§15.28)

*、/、和%
这样的乘法运算符属于常量表达式,因此它将在编译时确定

@SergeyMorozov在编写和获得字节码证明方面比我快(
#2=Integer 60000
),但以下是实际证明,以上是理论/官方声明:

尝试在您的终端使用
1000*60
60000
生成字节码,您将看到相同的字节码指令,因此会有相同的运行时性能

Java类:

public class Test {
    public static void main(String[] args) {
        int compileTest = 1000 * 60;
    }
}
Classfile /E:/Test.class
  Last modified Oct 9, 2015; size 265 bytes
  MD5 checksum fd115be769ec6ef7995e4c84f7597d67
  Compiled from "Test.java"
public class Test
  SourceFile: "Test.java"
  minor version: 0
  major version: 51
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #4.#13         //  java/lang/Object."<init>":()V
   #2 = Integer            60000
   #3 = Class              #14            //  Test
   #4 = Class              #15            //  java/lang/Object
   #5 = Utf8               <init>
   #6 = Utf8               ()V
   #7 = Utf8               Code
   #8 = Utf8               LineNumberTable
   #9 = Utf8               main
  #10 = Utf8               ([Ljava/lang/String;)V
  #11 = Utf8               SourceFile
  #12 = Utf8               Test.java
  #13 = NameAndType        #5:#6          //  "<init>":()V
  #14 = Utf8               Test
  #15 = Utf8               java/lang/Object
{
  public Test();
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 1: 0

  public static void main(java.lang.String[]);
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=1, locals=2, args_size=1
         0: ldc           #2                  // int 60000
         2: istore_1
         3: return
      LineNumberTable:
        line 3: 0
        line 4: 3
}
字节码:

public class Test {
    public static void main(String[] args) {
        int compileTest = 1000 * 60;
    }
}
Classfile /E:/Test.class
  Last modified Oct 9, 2015; size 265 bytes
  MD5 checksum fd115be769ec6ef7995e4c84f7597d67
  Compiled from "Test.java"
public class Test
  SourceFile: "Test.java"
  minor version: 0
  major version: 51
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #4.#13         //  java/lang/Object."<init>":()V
   #2 = Integer            60000
   #3 = Class              #14            //  Test
   #4 = Class              #15            //  java/lang/Object
   #5 = Utf8               <init>
   #6 = Utf8               ()V
   #7 = Utf8               Code
   #8 = Utf8               LineNumberTable
   #9 = Utf8               main
  #10 = Utf8               ([Ljava/lang/String;)V
  #11 = Utf8               SourceFile
  #12 = Utf8               Test.java
  #13 = NameAndType        #5:#6          //  "<init>":()V
  #14 = Utf8               Test
  #15 = Utf8               java/lang/Object
{
  public Test();
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 1: 0

  public static void main(java.lang.String[]);
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=1, locals=2, args_size=1
         0: ldc           #2                  // int 60000
         2: istore_1
         3: return
      LineNumberTable:
        line 3: 0
        line 4: 3
}
Classfile/E:/Test.class
最后修改日期:2015年10月9日;大小265字节
MD5校验和fd115be769ec6ef7995e4c84f7597d67
从“Test.java”编译而来
公开课考试
源文件:“Test.java”
次要版本:0
主要版本:51
旗帜:ACC_公共、ACC_超级
固定池:
#1=Methodref#4.#13//java/lang/Object.“:()V
#2=整数60000
#3=等级#14//测试
#4=类#15//java/lang/Object
#5=Utf8
#6=Utf8()V
#7=Utf8代码
#8=Utf8行号表
#9=Utf8主
#10=Utf8([Ljava/lang/String;)V
#11=Utf8源文件
#12=Utf8 Test.java
#13=名称和类型#5:#6/“”:()V
#14=Utf8测试
#15=Utf8 java/lang/Object
{
公开考试();
旗帜:ACC_PUBLIC
代码:
堆栈=1,局部变量=1,参数大小=1
0:aload_0
1:invokespecial#1//方法java/lang/Object。“:()V
4:返回
LineNumberTable:
第1行:0
公共静态void main(java.lang.String[]);
标志:ACC_公共,ACC_静态
代码:
堆栈=1,局部变量=2,参数大小=1
0:ldc#2//int 60000
2:istore_1
3:返回
LineNumberTable:
第3行:0
第4行:3
}
只需创建类测试

public class Test {
    public static void main(String [] args) {
        long timeInMilliseconds = System.currentTimeMillis();
        double timeInMinutes = (double) timeInMilliseconds / (1000 * 60);
        System.out.println(timeInMinutes);
    }
}
并使用命令进行反编译:javap-v Test

您可以看到反编译类的输出:

  public static void main(java.lang.String[]);
flags: ACC_PUBLIC, ACC_STATIC
Code:
  stack=4, locals=5, args_size=1
     0: invokestatic  #2                  // Method java/lang/System.currentTimeMillis:()J
     3: lstore_1
     4: lload_1
     5: l2d
     6: ldc2_w        #3                  // double 60000.0d
     9: ddiv
    10: dstore_3
    11: getstatic     #5                  // Field java/lang/System.out:Ljava/io/PrintStream;
    14: dload_3
    15: invokevirtual #6                  // Method java/io/PrintStream.println:(D)V
    18: return
  LineNumberTable:
    line 3: 0
    line 4: 4
    line 5: 11
    line 6: 18

看看第6行:ldc2_w#3//double 60000.0d

查找常量表达式。根据答案,相关:这是编译器可以实现的最简单的优化之一。即使是旧的“未优化”VB3-VB6也可以执行此操作(不确定早期版本,他们可能也执行过此操作).TagirVallev的观点可能重复:
(double)time/1000/60
不是对文字的操作,出于浮点原因,甚至不能期望给出与
(double)time/(1000*60)相同的结果
。可能值得注意的是,
timeinmillizes/1000/60
将在运行时计算。@TagirValeev可能值得添加您自己的答案或编辑现有答案中的一个来指出这一点。@TagirValeev决定试试您所说的,它看起来像是在运行时计算的:。
timeinmillizes/(1000/60)
还可以。您的示例
int compileTest=1000*60;
与问题有点不同;我将算术与变量和文字混合在一起。阅读所有答案,可能不会改变结果,但只想指出结果略有不同。@NeverdingQS我举了一个示例来回答您的问题“操作(1000*60)是在编译时还是在运行时完成的?”…无论如何,关键是除了理论之外,您还可以生成字节码并在您的终端进行验证。@hagrawal:我认为OP的问题可以用更类似的措辞来表达。”当常量表达式作为更大的非常量表达式的一部分出现时,它们还会被优化吗?”@Hurkyl当我们回答他的问题时,他的问题很清楚——“操作(1000*60)是在编译时还是在运行时完成的?”?“,这就是我们的答案。但是,是的,它可以像你说的那样扩大,我认为OP编辑了他的问题。很高兴对问题标题或正文进行任何编辑。考虑到不同的因素,我不确定如何接受答案。