Quando disassembro un enum con javap, gli argomenti impliciti del costruttore dell'enum sembrano mancare e non riesco a capire perché.Enum disassemblato con javap non mostra gli argomenti del costruttore
Ecco un enum:
enum Foo { X }
compilo e smontare questo (su Java 8u60) con questo comando:
javac Foo.java && javap -c -p Foo
Ed ecco l'output ottengo:
final class Foo extends java.lang.Enum<Foo> {
public static final Foo X;
private static final Foo[] $VALUES;
public static Foo[] values();
Code:
0: getstatic #1 // Field $VALUES:[LFoo;
3: invokevirtual #2 // Method "[LFoo;".clone:()Ljava/lang/Object;
6: checkcast #3 // class "[LFoo;"
9: areturn
public static Foo valueOf(java.lang.String);
Code:
0: ldc #4 // class Foo
2: aload_0
3: invokestatic #5 // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
6: checkcast #4 // class Foo
9: areturn
private Foo(); // <--- here
Code:
0: aload_0
1: aload_1
2: iload_2
3: invokespecial #6 // Method java/lang/Enum."<init>":(Ljava/lang/String;I)V
6: return
static {};
Code:
0: new #4 // class Foo
3: dup
4: ldc #7 // String X
6: iconst_0
7: invokespecial #8 // Method "<init>":(Ljava/lang/String;I)V
10: putstatic #9 // Field X:LFoo;
13: iconst_1
14: anewarray #4 // class Foo
17: dup
18: iconst_0
19: getstatic #9 // Field X:LFoo;
22: aastore
23: putstatic #1 // Field $VALUES:[LFoo;
26: return
}
La mia confusione è con il costruttore privato utilizzato per istanziare ogni costante enum. Lo smontaggio mostra che non richiede argomenti (private Foo();
), ma sicuramente accetta argomenti. Ad esempio, è possibile visualizzare le istruzioni load
che leggono il nome e l'ordinale della costante enum passato, nonché il puntatore this
e passarli a the superclass constructor, che li richiede. Il codice nel blocco di inizializzazione statico mostra anche che inserisce tali argomenti nello stack prima di chiamare il costruttore.
Ora mi avrebbe assunto questo era solo un oscuro bug in javap, ma quando compilo esattamente la stessa enum con il compilatore di Eclipse e smontare che l'utilizzo javap, il costruttore è esattamente la stessa, tranne gli argomenti sono mostrato:
final class Foo extends java.lang.Enum<Foo> {
public static final Foo X;
private static final Foo[] ENUM$VALUES;
static {};
Code:
0: new #1 // class Foo
3: dup
4: ldc #12 // String X
6: iconst_0
7: invokespecial #13 // Method "<init>":(Ljava/lang/String;I)V
10: putstatic #17 // Field X:LFoo;
13: iconst_1
14: anewarray #1 // class Foo
17: dup
18: iconst_0
19: getstatic #17 // Field X:LFoo;
22: aastore
23: putstatic #19 // Field ENUM$VALUES:[LFoo;
26: return
private Foo(java.lang.String, int); // <--- here
Code:
0: aload_0
1: aload_1
2: iload_2
3: invokespecial #23 // Method java/lang/Enum."<init>":(Ljava/lang/String;I)V
6: return
public static Foo[] values();
Code:
0: getstatic #19 // Field ENUM$VALUES:[LFoo;
3: dup
4: astore_0
5: iconst_0
6: aload_0
7: arraylength
8: dup
9: istore_1
10: anewarray #1 // class Foo
13: dup
14: astore_2
15: iconst_0
16: iload_1
17: invokestatic #27 // Method java/lang/System.arraycopy:(Ljava/lang/Object;ILjava/lang/Object;II)V
20: aload_2
21: areturn
public static Foo valueOf(java.lang.String);
Code:
0: ldc #1 // class Foo
2: aload_0
3: invokestatic #35 // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
6: checkcast #1 // class Foo
9: areturn
}
la mia domanda è: che cosa fisicamente è differente tra un enum javac-compilato e un enum Eclipse-compilati che provoca javap per non mostrare gli argomenti del costruttore per l'enum javac-compilato? E questa differenza è un bug (in javap, in javac o in Eclipse)?
A ipotesi, l'impostazione del flag '-g' (controlla la generazione delle informazioni di debug). – CPerkins
@CPerkins Buone ipotesi ma ho confrontato '-g' (genera tutte le informazioni di debug) e' -g: none' (non genera informazioni di debug) e sembra non fare alcuna differenza. – Boann
Hai provato il flag '-v' (verbose)? Dovrebbe almeno mostrarti il descrittore del costruttore. La mia ipotesi è che 'javac' segna i primi parametri' MANDATO', il che potrebbe far sì che 'javap' li ometti. – Clashsoft