Vraag Eclipse waarschuwing over synthetische accessor voor private statische geneste klassen in Java?


Mijn collega stelde voor om verschillende van de Eclipse code-opmaak- en waarschuwingsinstellingen strenger te maken. De meeste van deze veranderingen zijn logisch, maar ik krijg deze ene rare waarschuwing in Java. Hier is wat testcode om het "probleem" te reproduceren:

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    

De lijn met de !!! geeft me deze waarschuwing in Eclipse met mijn nieuwe waarschuwingsinstellingen:

Toegang tot insluitende constructor   WeirdInnerClassJavaWarning.InnerClass ()   wordt geëmuleerd door een synthetische accessor   methode. Het vergroten van de zichtbaarheid zal   verbeter uw prestaties.

Wat betekent dit? De waarschuwing verdwijnt wanneer ik "private static class" verander in "protected static class", wat voor mij zinloos is.


Bewerk: Ik heb eindelijk de "juiste" oplossing gevonden. Het echte probleem lijkt hier te zijn dat deze geneste privé statische klasse een openbare constructor mist. Die ene tweak verwijderde de waarschuwing:

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();
    }
}

Ik wil dat de klasse een privé geneste klasse is (dus geen enkele andere klas kan er toegang toe hebben, inclusief subklassen van de klasse die de omsluiting bevat) en ik wil dat deze een statische klasse is.

Ik begrijp nog steeds niet waarom het maken van de geneste klasse beschermd in plaats van privé een andere methode is om het "probleem" op te lossen, maar misschien is dat een eigenaardigheid / bug van Eclipse.

(verontschuldigingen, ik had het moeten noemen NestedClass in plaats van InnerClass voor meer duidelijkheid.)


45
2018-05-28 14:06


oorsprong


antwoorden:


U kunt als volgt van de waarschuwing af raken:

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();
    }
}

Zoals anderen al hebben gezegd, klaagt Eclipse omdat een privéklasse zonder expliciete constructor niet van buitenaf kan worden geïnstantieerd, behalve via de synthetische methode die de Java-compiler maakt. Als u uw code neemt, compileert en decompileert met jad (*), krijg je het volgende (opnieuw ingedeelde):

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);
}

Als u een beschermde constructor toevoegt, is de synthetische code niet nodig. De synthetische code is theoretisch, naar ik aanneem, langzamer met een minuscule hoeveelheid dan niet-synthetische code die een openbare of beschermde constructor gebruikt.

(*) Voor jad heb ik een koppeling gemaakt met een Wikipedia-pagina ... het domein dat dit programma heeft gehost, is verlopen, maar Wikipedia linkt naar een andere die ik zelf niet heb getest. Ik weet dat er andere (mogelijk recentere) decompilers zijn, maar dit is degene die ik begon te gebruiken. Noteer het klaagt bij het decompileren van recente Java class-bestanden, maar het doet nog steeds een goede baan.


41
2018-05-28 14:37



Overigens staat de instelling om de waarschuwing uit te schakelen op de pagina Java-fouten / waarschuwingen onder "Codestijl" en wordt deze genoemd:

Toegang tot een niet-toegankelijk lid van een omsluitend type


19
2017-08-30 17:27



U kunt InnerClass niet van Instant WeirdInnerClassJavaWarning maken. Het is privé, JVM zou je dat niet toestaan, maar de Java-taal (om wat voor reden dan ook) zou dat wel zijn.

Daarom zou javac een extra methode in InnerClass maken die alleen InnerClass () zou retourneren, waardoor je InnerClass-instanties van WeirdInnerClassJavaWarning kunt maken.

ik denk niet dat je er echt vanaf wilt komen, omdat de prestatiedruppel onmetelijk klein zou zijn. Je kunt het echter wel als je het echt wilt.


8
2018-05-28 14:11



Ik begrijp nog steeds niet waarom het maken van de geneste klasse eerder dan privé beschermd is een andere methode om het "probleem" op te lossen, maar misschien is dat een gril / bug van Eclipse

Dat is geen gril / bug van Eclipse, slechts een kenmerk van Java. De Java-taalspecificatie, 8.8.9 zegt:

... als de klasse als beveiligd wordt verklaard, krijgt de standaardconstructor impliciet de beveiligde toegangsmodificatie ...


3
2018-05-28 14:52



Om mensen te helpen, is dit wat je krijgt als je de originele klascode in de vraag gebruikt

javac -XD-printflat WeirdInnerClassJavaWarning.java -d tmp

Raw-uitvoer, compiler heeft de opmerkingen toegevoegd. Let op de toevoeging van de private klasse en constructor van het synthetische pakket.

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 {
}

2
2017-08-21 15:27



U zou er vanaf moeten komen door de standaardscope te gebruiken in plaats van privé of beschermd, d.w.z.

static class InnerClass ...

Het is ook de moeite waard om op te merken dat wanneer u uw cursor op de coderegel plaatst met de waarschuwing en op ctrl-1 drukt, Eclipse dit mogelijk automatisch voor u kan herstellen.


0
2018-05-28 14:19