2015-10-09 10 views
25

Ho il seguente:Le operazioni aritmetiche su valori letterali sono calcolate al momento della compilazione o del tempo di esecuzione?

double timeInMinutes = (double) timeInMilliseconds/(1000 * 60); 

è l'operazione (1000 * 60) fatto al momento della compilazione o in fase di esecuzione? In altre parole, ci sono differenze di prestazioni durante la fase di esecuzione tra il frammento di codice di cui sopra e:

double timeInMinutes = (double) timeInMilliseconds/60000; 

EDIT: la mia domanda è diversa da Will the Java compiler precalculate sums of literals?, come sto mescolando l'uso di variabili e letterali nelle operazioni aritmetiche. È una piccola differenza, ma come @TagirValeev ha notato nei commenti (Are arithmetic operations on literals calculated at compile time or run time?), ci sono casi in cui alcuni valori letterali non sono precompilati, anche se potrebbero essere.

+5

Al momento della compilazione. – khelwood

+0

Cerca espressioni costanti. –

+1

In base alle risposte, correlate: http://stackoverflow.com/questions/2012528/is-there-any-concept-called-constant-folding-in-java – neverendingqs

risposta

10

In fase di compilazione. Questa è una di quelle ottimizzazioni di base del compilatore, nota come Constant Folding.

+8

Probabilmente vale la pena notare che 'timeInMilliseconds/1000/60' sarebbe calcolato al runtime. –

+0

@TagirValeev probabilmente vale la pena aggiungere la propria risposta o modificare uno di quelli esistenti per farlo notare. – neverendingqs

+0

@TagirValeev ha deciso di provare quello che hai detto e sembra che sia calcolato in fase di runtime: http://pastebin.com/D2RF0ygF. 'timeInMilliseconds/(1000/60)' comunque andava bene. – neverendingqs

19

Come per JLS §15.2 - Forms of Expressions

Alcune espressioni hanno un valore che può essere determinato al momento della compilazione. Queste sono espressioni costanti (§15.28).

Gli operatori moltiplicativi come *, /, and % ricadono in espressioni costanti, quindi verranno determinati al momento della compilazione.

@SergeyMorozov era più veloce di me di scrivere e ottenere la prova bytecode (#2 = Integer 60000), ma qui è la prova pratica e sopra è teorico/ufficiale dichiarazione:

generazione Prova bytecode a vostra fine, nonché utilizzando 1000 * 60 e 60000, e vedrete le stesse istruzioni sul codice byte, e quindi ci sarebbe la stessa prestazione di runtime. Classe

Java: codice

public class Test { 
    public static void main(String[] args) { 
     int compileTest = 1000 * 60; 
    } 
} 

Byte:

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 
} 
+0

Il tuo esempio 'int compileTest = 1000 * 60;' è leggermente diverso dalla domanda; Sto mescolando l'aritmetica con una variabile e letterali. Leggendo tutte le risposte, probabilmente non cambia il risultato, ma volevo solo notare che è leggermente diverso. – neverendingqs

+0

@neverendingqs Ho preso l'esempio per rispondere alla tua domanda "* L'operazione (1000 * 60) è fatta in fase di compilazione o in fase di esecuzione? *" .. Comunque, la cosa fondamentale è che puoi generare codice byte e verificare alla fine dalla teoria .. – hagrawal

+4

@hagrawal: Penso che la domanda dell'OP possa essere formulata meglio come qualcosa di più simile "le espressioni costanti saranno ancora ottimizzate quando appariranno come parte di un'espressione più ampia e non costante?" – Hurkyl

7

Basta creare classe Test

public class Test { 
    public static void main(String [] args) { 
     long timeInMilliseconds = System.currentTimeMillis(); 
     double timeInMinutes = (double) timeInMilliseconds/(1000 * 60); 
     System.out.println(timeInMinutes); 
    } 
} 

e decompilare utilizzando il comando: javap -v T est

Si può vedere l'uscita di classe decompiled:

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 

Date un'occhiata sulla linea 6: ldc2_w # 3 // doppia 60000.0d

Problemi correlati