Eclipse warning about synthetic accessor for private static nested classes in Java?
My coworker suggested making several of the Eclipse code-formatting and warning settings to be more rigorous. The majority of these changes make sense, but I get this one weird warning in Java. Here's some test code to reproduce the "problem":
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
The line with the !!! gives me this warning in Eclipse with my new warning settings:
Access to enclosing constructor WeirdInnerClassJavaWarning.InnerClass() is emulated by a synthetic accessor method. Increasing its visibility will improve your performance.
What does this mean? The warning goes away when I change "private static class" to "protected static class", which makes no sense to me.
edit: I finally figured out the "correct" fix. The real problem here seems to be that this nested private static class is missing a public constructor. That one tweak removed the warning:
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();
}
}
I want the class to be a private nested class (so no other class can have access to it, including subclasses of the enclosing class) and I want it to be a static class.
I still don't understand why making the nested class protected rather than private is another method of fixing the "problem", but maybe that is a quirk/bug of Eclipse.
(apologies, I should have called it NestedClass instead of InnerClass to be more clear.)
You can get rid of the warning as follows:
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();
}
}
As others have said, Eclipse is complaining because a private class with no explicit constructor cannot be instantiated from outside, except via the synthetic method that the Java compiler creates. If you take your code, compile it, and then decompile it with jad (*), you get the following (reformatted):
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);
}
If you add a protected constructor, the synthetic code is unnecessary. The synthetic code is theoretically, I suppose, slower by a minescule amount than non-synthetic code using a public or protected constructor.
(*) For jad, I linked to a Wikipedia page ... the domain that hosted this program has expired, but Wikipedia links to another that I have not tested myself. I know there are other (possibly more recent) decompilers, but this is the one I started using. Note: It complains when decompiling recent Java class files, but it still does a good job.
By the way, the setting to turn the warning off is in the Java Errors/Warnings page under "Code style" and is called:
Access to a non-accessible member of an enclosing type
You can not instantiate InnerClass from WeirdInnerClassJavaWarning. It's private, JVM wouldn't let you to, but the Java language (for some reason) would.
Therefore, javac would make an additional method in InnerClass that would just return new InnerClass(), therefore permitting you to create InnerClass instances from WeirdInnerClassJavaWarning.
i don't think you really need to get rid of it because the perfomance drop would be inmeasureably tiny. However, you can if you really want to.