I want to add the following code to my class:
static private final ILogic_P logicInstanceI =
(ILogic_P)Factory.CreateAnon("some.path.ILogic_P" + (SomeClass.isIMDB() ? "1" : "2"));
public static ILogic_P getLogicInstanceI(){
return logicInstanceI;
}
I can't figure it out if the initialization of the static variable is thread safety or not.
Is there a chance that two threads will try to initialize this attribute simultaneously?
The answer is given by the Java Language Specification §12.4.2:
Because the Java programming language is multithreaded, initialization of a class or interface requires careful synchronization, since some other thread may be trying to initialize the same class or interface at the same time. There is also the possibility that initialization of a class or interface may be requested recursively as part of the initialization of that class or interface; for example, a variable initializer in class A might invoke a method of an unrelated class B, which might in turn invoke a method of class A. The implementation of the Java Virtual Machine is responsible for taking care of synchronization and recursive initialization by using the following procedure. […]
Note the last sentence starting with “The implementation of the Java Virtual Machine is responsible for taking care …”
So you are not responsible for synchronization in the case of class initialization, and assigning initial values to static variables is part of the class initialization, as specified in §8.3.2:
8.3.2. Field Initialization
If a declarator in a field declaration has a variable initializer, then the declarator has the semantics of an assignment (§15.26) to the declared variable.
If the declarator is for a class variable (that is, a static field), then the following rules apply to its initializer:
…
At run time, the initializer is evaluated and the assignment performed exactly once, when the class is initialized (§12.4.2).
Related
Does creating a reference to an object of a class cause the class to be loaded?
Static variables are initialized when the class is loaded, so considering the following code the answer is no, am I right?
class A{
static int f(){
System.out.println("initializing!");
return 0;
}
static final int i = f();
}
public class Main {
public static void main(String[] args) {
A a;
}
}
The code doesn't give any output.
It’s a common mistake to treat loading and initialization of a class as being the same thing.
The Java Language Specification differentiates between
Loading
Loading refers to the process of finding the binary form of a class or interface type with a particular name, perhaps by computing it on the fly, but more typically by retrieving a binary representation previously computed from source code by a Java compiler, and constructing, from that binary form, a Class object to represent the class or interface.
Linking
Linking is the process of taking a binary form of a class or interface type and combining it into the run-time state of the Java Virtual Machine, so that it can be executed. A class or interface type is always loaded before it is linked.
Three different activities are involved in linking: verification, preparation, and resolution of symbolic references.
Initialization
Initialization of a class consists of executing its static initializers and the initializers for static fields (class variables) declared in the class.
Initialization of an interface consists of executing the initializers for fields (constants) declared in the interface.
For most cases, the exact time of loading and linking doesn’t matter, so it’s no problem that the specification provides some freedom to JVM implementations regarding the exact time. Only in the erroneous case, e.g. when a class is absent or there are incompatibilities (linkage or verify errors), JVM specific differences can show up, regarding the exact time when the associated Error is thrown.
So what your question is aiming at, is not loading, but initialization as you are looking at the side effect produced by the execution of the static class intializer.
The time of initialization is precisely defined:
§12.4.1. When Initialization Occurs
A class or interface type T will be initialized immediately before the first occurrence of any one of the following:
T is a class and an instance of T is created.
A static method declared by T is invoked.
A static field declared by T is assigned.
A static field declared by T is used and the field is not a constant variable (§4.12.4).
T is a top level class (§7.6) and an assert statement (§14.10) lexically nested within T (§8.1.3) is executed.
When a class is initialized, its superclasses are initialized (if they have not been previously initialized), as well as any superinterfaces (§8.1.5) that declare any default methods (§9.4.3) (if they have not been previously initialized). Initialization of an interface does not, of itself, cause initialization of any of its superinterfaces.
So from the specification, you can draw the conclusion that the mere presence of a local variable will never trigger an initialization. When assigning a non-null value to a variable of a reference type, there must have been a preceding instantiation of that type that already triggered its initialization. An unused local variable, however, has no impact.
When it comes to loading rather than initialization, there can be subtle differences, as shown is this scenario.
Yes. Static initializers are called when a class method is called or an instance is instantiated.
From your example you can do one of the following:
1. Create New Instance
public static void main(String[] args) {
A a = new A();
}
2. Call Static Class Method
public static void main(String[] args) {
int f = A.f();
}
Given the following classes:
public abstract class Super {
protected static Object staticVar;
protected static void staticMethod() {
System.out.println( staticVar );
}
}
public class Sub extends Super {
static {
staticVar = new Object();
}
// Declaring a method with the same signature here,
// thus hiding Super.staticMethod(), avoids staticVar being null
/*
public static void staticMethod() {
Super.staticMethod();
}
*/
}
public class UserClass {
public static void main( String[] args ) {
new UserClass().method();
}
void method() {
Sub.staticMethod(); // prints "null"
}
}
I'm not targeting at answers like "Because it's specified like this in the JLS.". I know it is, since JLS, 12.4.1 When Initialization Occurs reads just:
A class or interface type T will be initialized immediately before the first occurrence of any one of the following:
...
T is a class and a static method declared by T is invoked.
...
I'm interested in whether there is a good reason why there is not a sentence like:
T is a subclass of S and a static method declared by S is invoked on T.
Be careful in your title, static fields and methods are NOT inherited. This means that when you comment staticMethod() in Sub , Sub.staticMethod() actually calls Super.staticMethod() then Sub static initializer is not executed.
However, the question is more interesting than I thought at the first sight : in my point of view, this shouldn't compile without a warning, just like when one calls a static method on an instance of the class.
EDIT: As #GeroldBroser pointed it, the first statement of this answer is wrong. Static methods are inherited as well but never overriden, simply hidden. I'm leaving the answer as is for history.
I think it has to do with this part of the jvm spec:
Each frame (§2.6) contains a reference to the run-time constant pool (§2.5.5) for the type of the current method to support dynamic linking of the method code. The class file code for a method refers to methods to be invoked and variables to be accessed via symbolic references. Dynamic linking translates these symbolic method references into concrete method references, loading classes as necessary to resolve as-yet-undefined symbols, and translates variable accesses into appropriate offsets in storage structures associated with the run-time location of these variables.
This late binding of the methods and variables makes changes in other classes that a method uses less likely to break this code.
In chapter 5 in the jvm spec they also mention:
A class or interface C may be initialized, among other things, as a result of:
The execution of any one of the Java Virtual Machine instructions new, getstatic, putstatic, or invokestatic that references C (§new, §getstatic, §putstatic, §invokestatic). These instructions reference a class or interface directly or indirectly through either a field reference or a method reference.
...
Upon execution of a getstatic, putstatic, or invokestatic instruction, the class or interface that declared the resolved field or method is initialized if it has not been initialized already.
It seems to me the first bit of documentation states that any symbolic reference is simply resolved and invoked without regard as to where it came from. This documentation about method resolution has the following to say about that:
[M]ethod resolution attempts to locate the referenced method in C and its superclasses:
If C declares exactly one method with the name specified by the method reference, and the declaration is a signature polymorphic method (§2.9), then method lookup succeeds. All the class names mentioned in the descriptor are resolved (§5.4.3.1).
The resolved method is the signature polymorphic method declaration. It is not necessary for C to declare a method with the descriptor specified by the method reference.
Otherwise, if C declares a method with the name and descriptor specified by the method reference, method lookup succeeds.
Otherwise, if C has a superclass, step 2 of method resolution is recursively invoked on the direct superclass of C.
So the fact that it's called from a subclass seems to simply be ignored. Why do it this way? In the documentation you provided they say:
The intent is that a class or interface type has a set of initializers that put it in a consistent state, and that this state is the first state that is observed by other classes.
In your example, you alter the state of Super when Sub is statically initialized. If initialization happened when you called Sub.staticMethod you would get different behavior for what the jvm considers the same method. This might be the inconsistency they were talking about avoiding.
Also, here's some of the decompiled class file code that executes staticMethod, showing use of invokestatic:
Constant pool:
...
#2 = Methodref #18.#19 // Sub.staticMethod:()V
...
Code:
stack=0, locals=1, args_size=1
0: invokestatic #2 // Method Sub.staticMethod:()V
3: return
The JLS is specifically allowing the JVM to avoid loading the Sub class, it's in the section quoted in the question:
A reference to a static field (§8.3.1.1) causes initialization of only the class or interface that actually declares it, even though it might be referred to through the name of a subclass, a subinterface, or a class that implements an interface.
The reason is to avoid having the JVM load classes unnecessarily. Initializing static variables is not an issue because they are not getting referenced anyway.
The reason is quite simple: for JVM not to do extra work prematurely (Java is lazy in its nature).
Whether you write Super.staticMethod() or Sub.staticMethod(), the same implementation is called. And this parent's implementation typically does not depend on subclasses. Static methods of Super are not supposed to access members of Sub, so what's the point in initializing Sub then?
Your example seems to be artificial and not well-designed.
Making subclass rewrite static fields of superclass does not sound like a good idea. In this case an outcome of Super's methods will depend on which class is touched first. This also makes hard to have multiple children of Super with their own behavior. To cut it short, static members are not for polymorphism - that's what OOP principles say.
According to this article, when you call static method or use static filed of a class, only that class will be initialized.
Here is the example screen shot.
for some reason jvm think that static block is no good, and its not executed
I believe, it is because you are not using any methods for subclass, so jvm sees no reason to "init" the class itself, the method call is statically bound to parent at compile time - there is late binding for static methods
http://ideone.com/pUyVj4
static {
System.out.println("init");
staticVar = new Object();
}
Add some other method, and call it before the sub
Sub.someOtherMethod();
new UsersClass().method();
or do explicit Class.forName("Sub");
Class.forName("Sub");
new UsersClass().method();
When static block is executed Static Initializers
A static initializer declared in a class is executed when the class is initialized
when you call Sub.staticMethod(); that means class in not initialized.Your are just refernce
When a class is initialized
When a Class is initialized in Java After class loading, initialization of class takes place which means initializing all static members of class. A Class is initialized in Java when :
1) an Instance of class is created using either new() keyword or using reflection using class.forName(), which may throw ClassNotFoundException in Java.
2) an static method of Class is invoked.
3) an static field of Class is assigned.
4) an static field of class is used which is not a constant variable.
5) if Class is a top level class and an assert statement lexically nested within class is executed.
When a class is loaded and initialized in JVM - Java
that's why your getting null(default value of instance variable).
public class Sub extends Super {
static {
staticVar = new Object();
}
public static void staticMethod() {
Super.staticMethod();
}
}
in this case class is initialize and you get hashcode of new object().If you do not override staticMethod() means your referring super class method
and Sub class is not initialized.
In the code below, what is the order of initialization of data fields? What is the general rule followed by java for data member and member functions?
public class TestClass
{
int j=10;
static int h=5;
public static void main(String[] args)
{
TestClass obj= new TestClass();
}
}
In general:
1) static field members (static initializers in general)
2) non-static field members
3) constructor
However you can test it with a snippet of code like this:
public class TestClass {
int i = 10;
static int j = 20;
public TestClass() {
// TODO Auto-generated constructor stub
System.out.println(i);
i = 20;
System.out.println(i);
}
public static void main(String[] args) {
new TestClass();
}
}
Quoting from the great "Thinking In Java":
Within a class, the order of initialization is determined by the order that the variables are
defined within the class. The variable definitions may be scattered throughout and in between method definitions, but the variables are initialized before any methods can be
called—even the constructor.
...................................
There’s only a single piece of storage for a static, regardless of how many objects are created.
You can’t apply the statickeyword to local variables, so it only applies to fields. If a field is a
staticprimitive and you don’t initialize it, it gets the standard initial value for its type. If it’s
a reference to an object, the default initialization value is null.
To summarize the process of creatingan object, consider a class called Dog:
Even though it doesn't explicitly use the static keyword, the constructor is actually a
static method. So the first time an object of type Dog is created, or the first time a
static method or static field of class Dog is accessed, the Java interpreter must
locate Dog.class, which it does by searching through the class path.
As Dog.class is loaded (creating a Class object, which you’ll learn about later), all of
its static initializers are run. Thus, static initialization takes place only once, as the
Class object is loaded for the first time.
When you create a new Dog( ), the construction process for a Dog object first
allocates enough storage for a Dog object on the heap.
This storage is wiped to zero, automatically setting all the primitives in that Dog
object to their default values (zero for numbers and the equivalent for boolean and
char) and the references to null.
Any initializations that occur at the point of field definition are executed.
Constructors are executed.This might actually involve a fair amount of activity, especially when inheritance is involved.
Here is the order.
Static fields initialized and static block executed at class loading time, they will be initialized in the same order they declared.
Set fields to default initial values (0, false, null)
Call the constructor for the object (but don't execute the body of the constructor yet)
Invoke the constructor of the superclass
Initialize fields using initializers and initialization blocks
Execute the body of the constructor
I think you're just missing section 12.4.2 of JLS, which includes:
Next, execute either the class variable initializers and static initializers of the class, or the field initializers of the interface, in textual order, as though they were a single block.
The "in textual order" part is the important bit.
If you change m from being static variable to an instance variable, then the field won't be initialized by class initialization - it'll only be initialized by instance initialization (i.e. when an instance is constructed). At the moment, that'll cause a stack overflow - creating one instance requires creating another instance, which requires creating another instance, etc.
So Finally Here is Order which you are searching for:
Initialization blocks run in the order they appear in the program.
Static initialization blocks run when the class is first loaded into JVM
Instance initialization blocks run whenever a new instance of class is created.
I am not sure whether I have a correct model of Java initialization mechanism in my head. Each class follows the following:
Initialize superclass, if there exists one
Initialize yourself
Initialize follows the following:
Initialize static and instance variables which have their values set outside of initializer.
Run static initialization block
Run constructor block
Is that precise/correct?
Code execute as below -
Static init blocks run once, when the class is first loaded.
Static Variable
All Super Constructor.
Instance init blocks run after the constructor's call to super().
instance variable.
(Init blocks execute in the order they appear.)
According to the Java language specification, your assumptions are more or less correct. The exceptions are that:
instance variables are run when the class is constructed (together with the constructor) after the class is initialized,
final static variables with compile-time constant expressions are loaded before even attempting to load the superclass, and
the static initialization block is run together with the static variables as one block, in the order they appear in the code.
I have this code
private static Set<String> myField;
static {
myField = new HashSet<String>();
myField.add("test");
}
and it works. But when I flip the order, I get an illegal forward reference error.
static {
myField = new HashSet<String>();
myField.add("test"); // illegal forward reference
}
private static Set<String> myField;
I'm a little bit shocked, I didn't expect something like this from Java. :)
What happens here? Why is the order of declarations important? Why does the assignment work but not the method call?
First of all, let's discuss what a "forward reference" is and why it is bad. A forward reference is a reference to a variable that has not yet been initialized, and it is not confined only to static initalizers. These are bad simply because, if allowed, they'd give us unexpected results. Take a look at this bit of code:
public class ForwardRef {
int a = b; // <--- Illegal forward reference
int b = 10;
}
What should j be when this class is initialized? When a class is initialized, initializations are executed in order the first to the last encountered. Therefore, you'd expect the line
a = b;
to execute prior to:
b = 10;
In order to avoid this kind of problems, Java designers completely disallowed such uses of forward references.
EDIT
this behaviour is specified by section 8.3.2.3 of Java Language Specifications:
The declaration of a member needs to appear before it is used only if the member is an instance (respectively static) field of a class or interface C and all of the following conditions hold:
The usage occurs in an instance (respectively static) variable initializer of C or in an instance (respectively static) initializer of C.
The usage is not on the left hand side of an assignment.
C is the innermost class or interface enclosing the usage.
A compile-time error occurs if any of the three requirements above are not met.
try this:
class YourClass {
static {
myField = new HashSet<String>();
YourClass.myField.add("test");
}
private static Set<String> myField;
}
it should compile without errors according the JLS...
(don't really help, or?)
In Java, all initializers, static or otherwise, are evaluated in the order in which they appear in the class definition.
See the rules for forward references in the JLS. You cannot use forward references if:
The usage occurs in an instance (respectively static) variable initializer of C or in an instance (respectively static) initializer of C.
The usage is not on the left hand side of an assignment.
The usage is via a simple name.
C is the innermost class or interface enclosing the usage.
Since all of these hold for your example, the forward reference is illegal.
To elaborate on DFA's answer:
I think what's tripping you up is the "left hand side" rule in the second bullet point in JLS 8.2.3.2. In your initialization, myField is on the left-hand side. In your call to add, it's on the right-hand side. The code here is implicitly:
boolean result = myField.add('test')
You're not evaluating the result, but the compiler still acts as if it's there. That's why your initialization passes while your call to add() fails.
As for why this is so, I have no idea. It may well be for the convenience of the JVM developers, for all I know.
I think the method call is problematic because the compiler cannot determine which add() method to use without a reference type for myField.
At runtime, the method used will be determined by the object type, but the compiler only knows about the reference type.