2

I have a class which contains:

  • a public, static inner enum
  • private constants referring to an int and to the enum
  • a private inner class

Referring to the enum constant from inside the inner class generates a synthetic accessor warning, but referring to the int constant does not.

Why is this? How can I prevent this warning without making the enum constant package scope or disabling the warning? (e.g. perhaps by making an explicit accessor?)

Code reproducing the problem:

public class Outer {
    public static enum Bar {
        A, B, C;
    }

    private static final int FOO = 0;
    private static final Outer.Bar BAR = Outer.Bar.A;

    private class Inner {
        {
            int foo = Outer.FOO;        // just fine
            Outer.Bar bar = Outer.BAR;  // synthetic accessor method warning
        }
    }
}
Ben Blank
  • 54,908
  • 28
  • 127
  • 156
  • 1
    This is just a guess, but it may be because the compiler can optimize the primitive integer store and make it a true compile-time constant (meaning no synthetic accessor call occurs) while the enum assignment, using a proper object, must occur at runtime. – JAB Jun 02 '16 at 19:06
  • 1
    I can't reproduce the warning using Java 8 – Yassin Hajaj Jun 02 '16 at 19:10
  • duplicate of http://stackoverflow.com/questions/921025/eclipse-warning-about-synthetic-accessor-for-private-static-nested-classes-in-jav ? – LeTex Jun 02 '16 at 19:13
  • Where is this warning coming from? What compilation are you using? – Louis Wasserman Jun 02 '16 at 19:16
  • @LeTex - it doesn't look like a dupe to me. The referenced question is about why the warning is generated in the first place, which I think poster understands. The thrust of this question, as I understand it, is the difference between accesses to `Outer.FOO`, which don't generate a warning, and `Outer.BAR`, which do. See my answer for details. – BeeOnRope Jun 02 '16 at 19:25
  • 1
    @YassinHajaj - the warning is compiler-specific and depends on your warning options. I believe the Eclipse compiler is the one that likes the warn about this. IMO the warning is more harmful than the issue it purports to solve. The overwhelming majority of the time these synthetic methods are helpful glue that "just works". Warning about every potential performance issue is a slippery slope and even if I want to go down that slope, I wouldn't start with these methods. – BeeOnRope Jun 02 '16 at 19:42

1 Answers1

2

The JLS requires that accesses to compile time constants be "inlined" into the consuming class, rather than leaving a symbolic reference to be resolved at link and run time. In particular, from JLS 13.1:

  1. References to fields that are constant variables (§4.12.4) are resolved at compile time to the constant value that is denoted. No reference to such a field should be present in the code in a binary file (except in the class or interface containing the field, which will have code to initialize it).

In particular, this means that you class Inner doesn't have any trace of Outer.FOO in its compiled class file. Rather, the constant value 0 of FOO is directly compiled into Inner at compile time.

Synthetic access methods are (among other reasons) added to ease runtime access to private fields between nested classes - but in the case of FOO, the access is already resolved at compile time, so no method is needed.

Outer.BAR on the other hand, is not eligible for compile-time constant treatment - because objects other than certain String objects are not compile time constants per 15.28:

A compile-time constant expression is an expression denoting a value of primitive type or a String that does not complete abruptly and is composed using only the following...

An Enum is neither a primitive nor a String, so the special handling for compile-time constants doesn't apply, and a synthetic accessor method is generated.

BeeOnRope
  • 60,350
  • 16
  • 207
  • 386
  • Do you have any documentation about the synthetic access method for accessing `static` members of another class? – Sotirios Delimanolis Jun 02 '16 at 19:31
  • There is tons of information about why these methods are added and what you can do about them. Personally I consider them innocuous - glue added by the compiler so that things work. The performance warning is a bit of red herring IMO - inlining is going to eliminate the actual call at runtime in 99% of the cases where it matters anyway. See [here](http://stackoverflow.com/questions/7046492/how-can-i-avoid-synthetic-access-compiler-warning-with-inline-anonymous-class-de) for a discussion. – BeeOnRope Jun 02 '16 at 19:36
  • ... and over [here](http://www.javaworld.com/article/2073578/java-s-synthetic-methods.html) if you want an overview of why these are added. All found via Google. – BeeOnRope Jun 02 '16 at 19:38