Why does accessing this private enum constant require a synthetic accessor? - java

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

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:
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.

Related

Why does my integer need to be final or effectively final? [duplicate]

Inner classes only have access to final or effectively final variables. I don't understand though, why an instance variable can be accessed no matter what, but local variables and method parameters need to be at minimum effectively final?
Consider the following code:
public class BookStore {
private static final int taxId = 300000;
public String name;
public String searchBook(final String criteria) {
int count = 0;
int sum = 0;
// name = ""; I can uncomment this -> no compile error
class Enumerator {
String interate(int k) {
System.out.println(name);
System.out.println(sum);
return "";
}
}
// sum++; If I uncomment this, a compile error will be thrown.
return "";
}
}
Why is it necessary that local variables + method arguments need to be effectively final?
It’s all about the value which is captured when the instance is created. Inner classes in an instance context always capture the immutable outer this reference¹, through which the instance fields can be accessed, mutable or not. In contrast, local variables can only be captured by their value, hence, the variable must not change, to be consistent with the captured value.
This is a design decision. Technically, it would be no problem to a) allow subsequent mutations that are not reflected by the inner class’ state or b) wrap every shared local variable into an object to allow mutations like with instance fields of the outer class, but neither, allowed inconsistency nor local variables that aren’t actually local, were deemed acceptable by the language designers.
¹ This differs from lambda expressions which only capture this when actually accessing instance variables
It's because of the scope of the local variables. Their scope is the method in which they are declared. Once execution has left the method, they are no longer valid. However, an inner class such as your Enumerator class can live on past the method execution, e.g. by returning a reference to a class instance.
Thus, the Enumerator class and its methods can be accessed outside of the method in which it is declared. At that point, it needs to assume that the local variables it referenced have the same value they had when execution instantiated the class.
For instance variables, the scope of these and of the inner class is the same - they are both available as long as the parent class instance exists.

Static fields in JVM loading

As part of JVM Loading, Linking and Initalizing, When the
static fields
final static fields
in Class
allocating in memory
init as default value
init as real value
In the case of the static final variables, I think that everything happens in the Loading step, because all values are already in Constant Pool.
But I can not figure out what's going on with the static fields. In principle, in the written documantation that they are initialized with default value in the Preparation step.
Preparation involves creating the static fields for a class or interface and initializing such fields to their default values (§2.3, §2.4). This does not require the execution of any Java Virtual Machine code; explicit initializers for static fields are executed as part of initialization (§5.5), not preparation.
But in this source (Class Variables paragraph) loading the static fields initialization occurs already in the Loading step. This makes sense because at the end of the loading step an instance of the class object is created, and it must contain room for the static fields.
Before a Java virtual machine uses a class, it must allocate memory from the method area for each non-final class variable declared in the class.
So I'd like to know what the right fact is in this case.
Generally, if there is some mismatch between the official specification and some article on the internet, you can safely assume that the specification has the last word and the article is wrong. This will serve you in 99.99% of all cases.
That’s especially true when it comes to the Java Virtual Machine, where articles notoriously mix up the steps of your question (“Loading, Linking, and Initializing”), and also regularly mix up formal steps and implementation details.
The article you’ve linked, does it wrong in several aspects:
Not every static final field is a compile-time constant. Only static final fields of primitive types or String are compile-time constants, if they are immediately initialized with a compile-time constant. Consider
static final String CONSTANT1 = ""; // compile-time constant
static final String CONSTANT2 = CONSTANT1; // compile-time constant
// but
static final String NO_CONSTANT1 = CONSTANT1.toString(); // not a constant expression
static final String NO_CONSTANT2; // no initializer
static {
NO_CONSTANT2 = ""; // assignment in class initializer, valid, but not constant
}
static final BigInteger NO_CONSTANT3 = BigInteger.ONE; // neither primitive nor String
For compile time constants, every ordinary Java language read access is replaced by the constant value at compile-time, still, the identifiers exist and can be inspected via Reflection or accessed by byte code not generated from Java language source code. Whether the JVM treats constant fields specially, when it comes to their storage, is an implementation detail, but usually, implementors try to avoid special treatment, unless there’s a true benefit.
The formal specification describes the constant variables as-if having a storage like any other variable, but of course, implementations may omit this, if they are capable of still retaining the mandated behavior (e.g. make the values available to Reflection).
The initialization of both, constant and non-constant static variables is clearly specified as part of the Initialization (though not at the same time):
 
Otherwise, record the fact that initialization of the Class object for C is in progress by the current thread, and release LC. Then, initialize each final static field of C with the constant value in its ConstantValue attribute (§4.7.2), in the order the fields appear in the ClassFile structure.
…
 9. Next, execute the class or interface initialization method of C.
The “class or interface initialization method” is the method named <clinit> at the bytecode level, which contains all initializers of non-constant static fields as well as any code in static { … } blocks.
Class variables and the constant pool are different things. The constant pool contains the symbolic names of fields as well as values for compile-time constants (which, by the way, may include non-static fields as well).
The values of the constant pool can be used to construct the actual runtime values, e.g. the byte sequence describing a string has to be converted to a reference to an actual String object and the primitive types may undergo Endianess conversions. When this processing happens as part of step 6 described in JVMS§5.5, as cited above, subsequent access to the field will consistently use the result of this process.
My understanding is that the memory allocation is done during the preparation, and the execution of the initializers during initialization. This doesn't contradict either of the sources.
To be precise,
Instance variables will be stored on the heap.
local variables on the stack(in case of variable not a
primitive[reference variable] reference variables live on stack and
the object on heap ). Only method invocation and partial results will
be stored in stack not the method itself.
Static variables and Methods(including static and Non Static) on the
Method Area. Static methods (in fact all methods) as well as static variables are stored in the PermGen section , since they are part of the reflection data (class related data, not instance related).
For static variables, if you do not initialize a variable, default value would be stored before object preparation (JVM takes care of this) but for Final Static, you need to initialize the variable before the object is created i.e. when we try to create a new object calling the constructor, before the object is returned to the reference variable, value need to be initialized else it is a compile time error.
Answers to your questions:
Static variable in Java belongs to the class and
initialized only once when the class is invoked (if not initialized - Lazy Initialization).
Static final variable is initialized at the time of class loading in
the method Area, as it is already initialized in the code (early initialization).
There wont be any change in the allocating in memory for static and final static.
public class Object {
public static final int i;
static{
i=0; // comment this line gives you compile time error
}
/**
* #param args
*/
public static void main(String[] args) {
}
}

Why does Java allow static variables which are FINAL in non-static inner classes

We already do understand that non-static inner classes cannot have any member which has a static keyword with it. Yet we see, static member variables with final is being used and encouraged. Can anyone explain why?
Another observation:
final static String abc = "I Love Food"; //works fine
whereas:
final static String abc = null; //is discouraged and gives error.
Read following JLS section (§8.1.3) for rules about usage of static/non-static members in an inner class.
Inner classes may not declare static initializers (§8.7) or member
interfaces, or a compile-time error occurs.
Inner classes may not declare static members, unless they are constant
variables (§4.12.4), or a compile-time error occurs.
Note this line above - "unless they are constant variables", which answers your question. When you declare a primitive or String as public static final then it becomes a "constant variable" and hence you are able to use it in a non-static inner class because it doesn't break the compilation rules.
Now, why it doesn't break compilation rules because when you declare a constant variable and initialize it then compiler could deterministically say that this would be value of this variable, while if you do not initialize it then compiler cannot deterministically say that this would be value of this variable and wouldn't be sure if it could be modified at runtime, and you cannot change a final value once it is been assigned.
Read rule related to final variable in this JLS section (§4.12.4)
We already do understand that non-static inner classes cannot have any member which has a static keyword with it.
Evidently your understanding is not complete. Section 8.1.3 of version 8 of the JLS specifies, in part,
It is a compile-time error if an inner class declares a member that is explicitly or implicitly static, unless the member is a constant variable (§4.12.4).
(Emphasis added.) Thus an inner class can have static members; there are just fairly strong restrictions on them.
Yet we see, static member variables with final is being used and encouraged. Can anyone explain why?
(Emphasis in the original.) I don't think I often see such usage being encouraged, per se. Nevertheless, it's a sensible way to keep the scope of such constants narrow, which is a good practice.
You furthermore ask about why a static final inner class member cannot be initialized to null. I cannot provide a rationale for that, but the actual rule is spelled out in the JLS, in the definition of a "constant variable" (referenced by the previous excerpt) in section 4.12.4:
A constant variable is a final variable of primitive type or type
String that is initialized with a constant expression (§15.28).
Of course, that depends on the definition of a "constant expression", which is a bit lengthy to present in its entirety. It boils down to an expression of primitive or String type that involve only integer literals, String literals, names designating constant variables, and a fairly large subset of Java's operators. And this brings us to the point: null is neither of primitive type nor of type String, therefore it cannot appear in a constant expression, therefore a variable is not a "constant variable" if it has null or an expression containing null as its initializer. Such a variable, not being a constant variable, cannot appear in an inner class.
If you look at this Accepted Answer Why does Java prohibit static fields in inner classes the referenced section will give you the answer. A final static field is treated as Java's compile time constant.

Singleton via enum way is lazy initialized?

This is a very wide-spread enum singleton code:
public enum enumClazz{
INSTANCE
enumClazz(){
//do something
}
}
and a bunch of places said it is a lazy initialization. But I am confused after I read Chapter 7 of 'Inside the Java Virtual Machine' -- The Lifetime of a Type:
The Java virtual machine specification gives implementations
flexibility in the timing of class and interface loading and linking,
but strictly defines the timing of initialization. All implementations
must initialize each class or interface on its first active use. The
following six situations qualify as active uses:
A new instance of a class is created (in bytecodes, the execution of a new instruction. Alternatively, via implicit creation,
reflection, cloning, or deserialization.)
The invocation of a static method declared by a class (in bytecodes, the execution of an invokestatic instruction)
The use or assignment of a static field declared by a class or interface, except for static fields that are final and initialized by
a compile-time constant expression (in bytecodes, the execution of a
getstatic or putstatic instruction)
The invocation of certain reflective methods in the Java API, such as methods in class Class or in classes in the java.lang.reflect
package
The initialization of a subclass of a class (Initialization of a class requires prior initialization of its superclass.)
The designation of a class as the initial class (with the main()< method) when a Java virtual machine starts up
The third point with bold style clarify that if the field is static final, the initialization of the field is happened at compile-time. Likewise, the INSTANCE in enumClazz is implicitly equal to public static final and comply with the third point.
Can someone correct me if my understanding is wrong?
enum instance fields are not "initialized by a compile-time constant expression". They
can't be, because only String and primitive types are possible types for a compile-time constant expression.
That means that the class will be initialized when INSTANCE is first accessed (which is exactly the desired effect).
The exception in the bold text above exists, because those constants (static final fields initialized with a compile-time constant expression) will effectively be inlined during compilation:
class A {
public static final String FOO = "foo";
static {
System.out.println("initializing A");
}
}
class B {
public static void main(String[] args) {
System.out.println(A.FOO);
}
}
Executing class B in this example will not initialize A (and will not print "initializing A"). And if you look into the bytecode generated for B you'll see a string literal with the value "foo" and no reference to the class A.
The third point with bold style clarify that if the field is 'static final', the initialzation of the field is happened at complie-time
Not exactly - it only applies to "static fields that are final and initialized by a compile-time constant expression":
static final String = "abc"; //compile time constant
static final Object = new Object(); //initialised at runtime
In your case, the singleton will be initialised when the enum class is loaded, i.e. the first time enumClazz is referenced in your code.
So it is effectively lazy, unless of course you have a statement somewhere else in your code that uses the enum.

When is the JVM bytecode access modifier flag 0x1000 (hex) "synthetic" set?

For some Java byte code parser project I read the JVM spec and figured out that the bit mask values of the Java virtual machine class file format access modifier fields are
ACC_PUBLIC = 0x0001
ACC_FINAL = 0x0010
ACC_SUPER = 0x0020 # old invokespecial instruction semantics (Java 1.0x?)
ACC_INTERFACE = 0x0200
ACC_ABSTRACT = 0x0400
ACC_SYNTHETIC = 0x1000
ACC_ANNOTATION = 0x2000
ACC_ENUM = 0x4000
Somehow I have no idea what 0x1000 is for. I saw it once in an inner class, but for all inner classes I checked since then, this flag was never set. Do you now what the meaning of this flag is and where/when it is set?
A synthetic element is any element that is present in a compiled class file but not in the source code it is compiled from. By checking an element for it being synthetic, you allow a distinction of such elements for tools that process code reflectively. This is of course first of all relevant to libraries that use reflection but it is also relevant for other tools like IDEs that do not allow you to call synthetic methods or to work with synthetic classes. Finally, it is also important for the Java compiler to verify code during its compilation to never directly use synthetic elements. Synthetic elements are only used to make the Java runtime happy which simply processes (and verifies) the delivered code where it treats synthetic elements identically to any other element.
You already mentioned inner classes as an example where synthetic elements are inserted by the Java compiler, so let us look at such a class:
class Foo {
private String foo;
class Bar {
private Bar() { }
String bar() {
return foo;
}
}
Bar bar() {
return new Bar();
}
}
This compiles perfectly fine but without synthetic elements, it would be refused by a JVM that does not know a thing about inner classes. The Java compiler desugares the above class to something like the following:
class Foo {
private String foo;
String access$100() { // synthetic method
return foo;
}
Foo$Bar bar() {
return new Foo$Bar(this, (Foo$1)null);
}
Foo() { } // NON-synthetic, but implicit!
}
class Foo$Bar {
private final Foo $this; // synthetic field
private Foo$Bar(Foo $this) { // synthetic parameter
this.$this = $this;
}
Foo$Bar(Foo $this, Foo$1 unused) { // synthetic constructor
this($this);
}
String bar() {
return $this.access$100();
}
}
class Foo$1 { /*empty, no constructor */ } // synthetic class
As said, the JVM does not know about inner classes but enforces private access of members, i.e. an inner class would not be able to access its enclosing classes' private properties. Thus, the Java compiler needs to add so-called accessors to an accessed class in order to expose its non-visible properties:
The foo field is private and can therefore only be accessed from within Foo. The access$100 method exposes this field to its package in which an inner class is always to be found. This method is synthetic as it is added by the compiler.
The Bar constructor is private and can therefore only be called from within its own class. In order to instantiate an instance of Bar, another (synthetic) constructor needs to expose the construction of an instance. However, constructors have a fixed name (internally, they are all called <init>), thus we cannot apply the technique for method accessors where we simply named them access$xxx. Instead, we make constructor accessors unique by creating a synthetic type Foo$1.
In order to access its outer instance, an inner class needs to store a reference to this instance which is stored in a synthetic field $this. This reference needs to be handed to the inner instance by a synthetic parameter in the constructor.
Other examples for synthetic elements are classes that represent lambda expressions, bridge methods when overriding methods with a type-divergent signatures, the creation of Proxy classes or classes that are created by other tools like Maven builds or runtime code generators such as Byte Buddy (shameless plug).
It's the "synthetic" flag, set when the field or method is generated by the compiler. AFAIK it's for inner classes, which meshes with your observation, and must be set when an artifact doesn't appear in the source code.
http://java.sun.com/docs/books/jvms/second_edition/html/ClassFile.doc.html#88571

Categories

Resources