Avviso di Eclipse riguardo all’accessorio sintetico per classi nidificate statiche private in Java?

Il mio collaboratore mi ha suggerito di rendere più rigorose alcune delle impostazioni di formattazione e avvertenza del codice Eclipse. La maggior parte di questi cambiamenti ha senso, ma ricevo questo strano avvertimento in Java. Ecco alcuni codici di test per riprodurre il “problema”:

package com.example.bugs; public class WeirdInnerClassJavaWarning { private static class InnerClass { public void doSomething() {} } final private InnerClass anInstance; { this.anInstance = new InnerClass(); // !!! this.anInstance.doSomething(); } } // using "this.anInstance" instead of "anInstance" prevents another warning, // Unqualified access to the field WeirdInnerClassJavaWarning.anInstance 

La linea con il !!! mi dà questo avviso in Eclipse con le mie nuove impostazioni di avviso:

L’accesso al costruttore di inclusione WeirdInnerClassJavaWarning.InnerClass () viene emulato da un metodo di accesso sintetico. Aumentando la sua visibilità migliorerai le tue prestazioni.

Cosa significa questo? L’avviso scompare quando cambio “class statica privata” in “class statica protetta”, che per me non ha senso.


modifica: ho finalmente capito la correzione “corretta”. Il vero problema qui sembra essere che questa class statica privata nidificata manchi di un costruttore pubblico. Quel ritouch ha rimosso l’avvertimento:

     package com.example.bugs; public class WeirdInnerClassJavaWarning { private static class InnerClass { public void doSomething() {} public InnerClass() {} } final private InnerClass anInstance; { this.anInstance = new InnerClass(); this.anInstance.doSomething(); } } 

    Voglio che la class sia una class nidificata privata (quindi nessun’altra class può avere accesso ad essa, comprese le sottoclassi della class che lo include) e voglio che sia una class statica.

    Non riesco ancora a capire perché rendere protetta la class nidificata anziché privata è un altro metodo per risolvere il “problema”, ma forse è un bug / bug di Eclipse.

    (Mi scuso, avrei dovuto chiamarlo NestedClass anziché InnerClass per essere più chiaro.)

    È ansible eliminare l’avviso come segue:

     package com.example.bugs; public class WeirdInnerClassJavaWarning { private static class InnerClass { protected InnerClass() {} // This constructor makes the warning go away public void doSomething() {} } final private InnerClass anInstance; { this.anInstance = new InnerClass(); this.anInstance.doSomething(); } } 

    Come altri hanno già detto, Eclipse si lamenta perché una class privata senza un costruttore esplicito non può essere istanziata dall’esterno, se non tramite il metodo sintetico creato dal compilatore Java. Se prendi il tuo codice, lo compili e poi lo decompilalo con jad (*), ottieni quanto segue (riformattato):

     public class Test { private static class InnerClass { public void doSomething() {} // DEFAULT CONSTRUCTOR GENERATED BY COMPILER: private InnerClass() {} // SYNTHETIC METHOD GENERATED BY THE JAVA COMPILER: InnerClass(InnerClass innerclass) { this(); } } public Test() { anInstance.doSomething(); } // Your instance initialization as modified by the compiler: private final InnerClass anInstance = new InnerClass(null); } 

    Se aggiungi un costruttore protetto, il codice sintetico non è necessario. Il codice sintetico è teoricamente, suppongo, più lento di una quantità minescola rispetto al codice non sintetico che utilizza un costruttore pubblico o protetto.

    (*) Per jad, ho collegato a una pagina di Wikipedia … il dominio che ha ospitato questo programma è scaduto, ma i collegamenti di Wikipedia ad un altro che non ho testato me stesso. So che ci sono altri decompilatori (forse più recenti), ma questo è quello che ho iniziato ad usare. Nota: si lamenta quando si decompilano i recenti file di class Java, ma fa comunque un buon lavoro.

    A proposito, l’impostazione per distriggersre l’avviso è nella pagina Errori / Avvisi Java sotto “Stile codice” e viene chiamata:

    Accesso a un membro non accessibile di un tipo che racchiude

    Non è ansible creare un’istanza di InnerClass da WeirdInnerClassJavaWarning. È privato, JVM non ti consente di farlo, ma il linguaggio Java (per qualche motivo) lo farebbe.

    Pertanto, javac creerebbe un metodo aggiuntivo in InnerClass che restituirebbe solo il nuovo InnerClass (), consentendo quindi di creare istanze InnerClass da WeirdInnerClassJavaWarning.

    Non penso che tu abbia davvero bisogno di liberartene perché la caduta della perfomance sarebbe infinitamente piccola. Tuttavia, puoi se lo vuoi davvero.

    Ancora non capisco perché rendere protetta la class nidificata piuttosto che privata è un altro metodo per risolvere il “problema”, ma forse è una stranezza / bug di Eclipse

    Questo non è un bug / bug di Eclipse, solo una funzionalità di Java. La specifica della lingua Java, 8.8.9 dice:

    … se la class è dichiarata protetta, allora il costruttore predefinito viene implicitamente protetto dal modificatore di accesso …

    Per aiutare la gente, ecco cosa ottieni se usi il codice di class originale nella domanda

     javac -XD-printflat WeirdInnerClassJavaWarning.java -d tmp 

    Output raw, il compilatore ha aggiunto i commenti. Nota l’aggiunta della class privata e del costruttore del pacchetto sintetico.

     public class WeirdInnerClassJavaWarning { { } public WeirdInnerClassJavaWarning() { super(); } { } private final WeirdInnerClassJavaWarning$InnerClass anInstance; { this.anInstance = new WeirdInnerClassJavaWarning$InnerClass(null); this.anInstance.doSomething(); } } class WeirdInnerClassJavaWarning$InnerClass { /*synthetic*/ WeirdInnerClassJavaWarning$InnerClass(WeirdInnerClassJavaWarning$1 x0) { this(); } private WeirdInnerClassJavaWarning$InnerClass() { super(); } public void doSomething() { } } /*synthetic*/ class WeirdInnerClassJavaWarning$1 { } 

    Dovresti essere in grado di sbarazzartene utilizzando l’ambito predefinito invece che privato o protetto, ad es

     static class InnerClass ... 

    Vale anche la pena notare che posizionando il cursore sulla riga di codice con l’avviso e premendo ctrl-1, Eclipse potrebbe essere in grado di correggerlo automaticamente.