2
votes

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
        }
    }
}
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
I can't reproduce the warning using Java 8Yassin Hajaj
Where is this warning coming from? What compilation are you using?Louis Wasserman
@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

1 Answers

2
votes

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.