What really happens when loading a class in java? - java

I'm confused with the process of loading a class. What is the order in which members of a class are executed?
See the following:
class L {
static void fr(){
a=1;
b=3;
a=b;
}
static{
a=3;
b=1;
a=b;// here the problem:cannot reference a field before it is defined
}
static int a;
static int b;
public static void main(String args[]) {
}
}
Whenever I move the declarations of a and b to the top before the static block, compilation works fine. So I need to understand how this stuff works to resolve the problem above.

In Java, it is illegal to refer to a class variable before it is declared, if it's not an expression initializing it. Java will execute initializers in a class in textual order.
Section 12.4.2 of the JLS states:
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.
Section 8.3.3 of the JLS states:
Use of class variables whose declarations appear textually after the use is sometimes restricted, even though these class variables are in scope (§6.3). Specifically, it is a compile-time error if all of the following are true:
The declaration of a class variable in a class or interface C appears textually after a use of the class variable;
The use is a simple name in either a class variable initializer of C or a static initializer of C;
The use is not on the left hand side of an assignment;
C is the innermost class or interface enclosing the use.
All of these are true. The declaration appears after the use in a=b;. It's in a static initializer. It's not on the left side of an assignment, and it's the innermost (only) class.
The simplest way to get this to compile is to move the declarations above the static initializer in the source code.
Interestingly, replacing a=b; with a=L.b; will also get this to compile, because the reference to b is no longer "simple".

First the class is loaded and the overall structure verified. Then the methods are verified and external linkages checked. Then the static init is performed. This is when the static block is executed.
But your problem is apparently with the compiler, not class loading. You need to move your static variable declarations up above the static block. Has nothing at all to do with class loading.
Hint: Learn the difference between a compile-time error and a run-time exception. What you were seeing was an error message from the compiler. (And you're lucky you didn't catch bloody hell and close votes for not including the EXACT error message in your question.)

Related

java enum illegal forward reference with constant [duplicate]

In the below code while accessing a static variable with class name it doesn't throw a forward reference error but accessing it without class name does.
Why this doesn't happen when accessing with class name?
class Test{
static {
System.out.println(a); // shows error
a = 99; // and this line too doesn't give error
System.out.println(Test.a); // this line doesn't
}
static int a = 10;
static{
System.out.println(a);
}
}
The rules for forward reference is defined in JLS §8.3.3:
Use of class variables whose declarations appear textually after the
use is sometimes restricted, even though these class variables are in
scope (§6.3). Specifically, it is a compile-time error if all of the
following are true:
The declaration of a class variable in a class or interface C appears
textually after a use of the class variable;
The use is a simple name in either a class variable initializer of C
or a static initializer of C;
The use is not on the left hand side of an assignment;
C is the innermost class or interface enclosing the use.
So, basically your first Sysout(), satisfies all the above 4 conditions, and hence it's a compile time error.
In the 2nd Sysout(), you're accessing a using it's qualified name, rather than simple name, which as per the above rules is allowed.
Now, the reason for this would be, when you access Test.a, the compiler is sure that Test class has been loaded and all static fields have been initialized, so it can access the field a. But while accessing a on simple name, the compiler isn't sure that initializer for a has already run or not, since it might still be in process of loading the class.
Consider the following process of loading of class:
When a class is loaded, memory is allocated for all the static variables declared in it. At this point, the variable a has got its memory allocated (declaration done)
Then all the static initializers run in the order of occurrence.
First statement is Sysout(a);. a hasn't been initialized yet, so you can't access it. (error)
Second statement is a = 99. Here you're actually initializing the variable a. Perfectly fine.
Third one is Sysout(Test.a) - reasoning for this is already posted above. Compiler knows Test is already loaded.
Then static int a = 10 is executed. It re-initializes a to 10. Remember, declaration part is already taken care of in first step.
First , let's see what JLS have to say for illegal forward references.
Use of class variables whose declarations appear textually after the
use is sometimes restricted, even though these class variables are in
scope (§6.3). Specifically, it is a compile-time error if all of the
following are true:
The declaration of a class variable in a class or interface C appears
textually after a use of the class variable;
The use is a simple name in either a class variable initializer of C
or a static initializer of C;
The use is not on the left hand side of an assignment;
C is the innermost class or interface enclosing the use.
Use of instance variables whose declarations appear textually after
the use is sometimes restricted, even though these instance variables
are in scope. Specifically, it is a compile-time error if all of the
following are true:
The declaration of an instance variable in a class or interface C
appears textually after a use of the instance variable;
The use is a simple name in either an instance variable initializer of
C or an instance initializer of C;
The use is not on the left hand side of an assignment;
C is the innermost class or interface enclosing the use.
It defines what is a illegal forward reference for each - static and instance variables. However, definition seems to be same for both of them. Since your question asks about static, we will dig deep into this only.
1) See, for a static variable, there is declaration and there is initialization.
static int a; //only declaration
static int b = 10; //both declaration and initialization
2) Use of class variables whose declarations appear textually after the use is sometimes restricted, even though these class variables are in scope.
What does it explains to us ? It says that there are cases when we can use static variables even if we declare them afterwards. And in some cases this wont be allowed. So, what are the cases that this won't be allowed ?
If the following 4 conditions are true at the same time. Else you are free to use it even though you have declared it afterwards.
a) The declaration of a class variable in a class or interface C appears textually after a use of the class variable;
b) The use is a simple name in either a class variable initializer of C or a static initializer of C;
c) The use is not on the left hand side of an assignment;
d) C is the innermost class or interface enclosing the use.
Well, the a) point is simple. It says that you must be looking at these rules only when you want to use a static variable before declaring it else why would you dig up into this JLS.
The b) point is that if you use simple name like boy [and not class name appended to it like MyClass.boy only then you might enter the problem of illegal forward reference else you are safe my friend. But just this condition don't qualifies for Illegal forward reference else your a=99 in you code would have given us error immediately. There are 2 more conditions that HAVE to be true for this error to generate . If the below 2 does not qualify, you are allowed to use it like this.]
The point c) is pretty straightforward. Are you not using in left hand side of assignment ? If we look at a=99 , Nope !! System.out.println(a) - This is not even an assignment. Hence no left hand assignment is true.
The point d) is also simple. It just tell you which class/Interface C he means in definition.Your C = Test.
Now let's revisit your code. At each line of code, I will comment True+False+True+false something like this meaning that for each line what point a), b) , c) ,d) will give to each of line. Okay ?
class Test {
static {
System.out.println(a); // True + True + True +True ; Illegal forward reference
a = 99; // True + True + False +True ; No illegal forward reference
System.out.println(Test.a); // True + False + True + True No illegal forward reference
}
static int a = 10;
static {
System.out.println(a);
}
}
The next question one may think is now what it will print ? What values will it take if we use before declaring it ?
Now we come to rules of static initialization. Here, we will go according to your code.
When class is loaded and no illegal forward reference is not there , all the static variables have been initialized to default value and are present in memory.
Now, after this static initialization takes place.
class Test {
static {
System.out.println(Test.a); // prints 0
a = 99; // a get 99
System.out.println(Test.a); // prints 99
}
static int a = 10;
static {
System.out.println(a); // prints 10
}
public static void main(String[] args) {
}
}
Well, the static block
static {
System.out.println(a);
a = 99;
System.out.println(Test.a);
}
will be executed before a is declared.
The line with Test.a won't fire any error because the compiler checks and finds static variable a declared within class Test.
Class initializers are run at the time that the class is loaded, and you cannot determine when exactly this happens. Code that runs within a class initializer should only be for things that need to be processed or "initialized" for other static methods (or the class itself) to work properly.
Additionally, you are referencing a variable that has not yet been declared. In your class initializer (the first static block) you assign a = 99, but a has not yet been declared. If anything you'd want to declare the variable, and then initialize it within the static block.
There is no reason to use class initializers for the type of code you are posting. This should be a static method if anything.
Here's an example
class Test{
static int a = 10;
static void doSomething(){
System.out.println(a);
a = 99;
System.out.println(a);
}
}
Then in main you can call Test.doSomething();

Why illegal forward reference error not shown while using static variable with class name

In the below code while accessing a static variable with class name it doesn't throw a forward reference error but accessing it without class name does.
Why this doesn't happen when accessing with class name?
class Test{
static {
System.out.println(a); // shows error
a = 99; // and this line too doesn't give error
System.out.println(Test.a); // this line doesn't
}
static int a = 10;
static{
System.out.println(a);
}
}
The rules for forward reference is defined in JLS §8.3.3:
Use of class variables whose declarations appear textually after the
use is sometimes restricted, even though these class variables are in
scope (§6.3). Specifically, it is a compile-time error if all of the
following are true:
The declaration of a class variable in a class or interface C appears
textually after a use of the class variable;
The use is a simple name in either a class variable initializer of C
or a static initializer of C;
The use is not on the left hand side of an assignment;
C is the innermost class or interface enclosing the use.
So, basically your first Sysout(), satisfies all the above 4 conditions, and hence it's a compile time error.
In the 2nd Sysout(), you're accessing a using it's qualified name, rather than simple name, which as per the above rules is allowed.
Now, the reason for this would be, when you access Test.a, the compiler is sure that Test class has been loaded and all static fields have been initialized, so it can access the field a. But while accessing a on simple name, the compiler isn't sure that initializer for a has already run or not, since it might still be in process of loading the class.
Consider the following process of loading of class:
When a class is loaded, memory is allocated for all the static variables declared in it. At this point, the variable a has got its memory allocated (declaration done)
Then all the static initializers run in the order of occurrence.
First statement is Sysout(a);. a hasn't been initialized yet, so you can't access it. (error)
Second statement is a = 99. Here you're actually initializing the variable a. Perfectly fine.
Third one is Sysout(Test.a) - reasoning for this is already posted above. Compiler knows Test is already loaded.
Then static int a = 10 is executed. It re-initializes a to 10. Remember, declaration part is already taken care of in first step.
First , let's see what JLS have to say for illegal forward references.
Use of class variables whose declarations appear textually after the
use is sometimes restricted, even though these class variables are in
scope (§6.3). Specifically, it is a compile-time error if all of the
following are true:
The declaration of a class variable in a class or interface C appears
textually after a use of the class variable;
The use is a simple name in either a class variable initializer of C
or a static initializer of C;
The use is not on the left hand side of an assignment;
C is the innermost class or interface enclosing the use.
Use of instance variables whose declarations appear textually after
the use is sometimes restricted, even though these instance variables
are in scope. Specifically, it is a compile-time error if all of the
following are true:
The declaration of an instance variable in a class or interface C
appears textually after a use of the instance variable;
The use is a simple name in either an instance variable initializer of
C or an instance initializer of C;
The use is not on the left hand side of an assignment;
C is the innermost class or interface enclosing the use.
It defines what is a illegal forward reference for each - static and instance variables. However, definition seems to be same for both of them. Since your question asks about static, we will dig deep into this only.
1) See, for a static variable, there is declaration and there is initialization.
static int a; //only declaration
static int b = 10; //both declaration and initialization
2) Use of class variables whose declarations appear textually after the use is sometimes restricted, even though these class variables are in scope.
What does it explains to us ? It says that there are cases when we can use static variables even if we declare them afterwards. And in some cases this wont be allowed. So, what are the cases that this won't be allowed ?
If the following 4 conditions are true at the same time. Else you are free to use it even though you have declared it afterwards.
a) The declaration of a class variable in a class or interface C appears textually after a use of the class variable;
b) The use is a simple name in either a class variable initializer of C or a static initializer of C;
c) The use is not on the left hand side of an assignment;
d) C is the innermost class or interface enclosing the use.
Well, the a) point is simple. It says that you must be looking at these rules only when you want to use a static variable before declaring it else why would you dig up into this JLS.
The b) point is that if you use simple name like boy [and not class name appended to it like MyClass.boy only then you might enter the problem of illegal forward reference else you are safe my friend. But just this condition don't qualifies for Illegal forward reference else your a=99 in you code would have given us error immediately. There are 2 more conditions that HAVE to be true for this error to generate . If the below 2 does not qualify, you are allowed to use it like this.]
The point c) is pretty straightforward. Are you not using in left hand side of assignment ? If we look at a=99 , Nope !! System.out.println(a) - This is not even an assignment. Hence no left hand assignment is true.
The point d) is also simple. It just tell you which class/Interface C he means in definition.Your C = Test.
Now let's revisit your code. At each line of code, I will comment True+False+True+false something like this meaning that for each line what point a), b) , c) ,d) will give to each of line. Okay ?
class Test {
static {
System.out.println(a); // True + True + True +True ; Illegal forward reference
a = 99; // True + True + False +True ; No illegal forward reference
System.out.println(Test.a); // True + False + True + True No illegal forward reference
}
static int a = 10;
static {
System.out.println(a);
}
}
The next question one may think is now what it will print ? What values will it take if we use before declaring it ?
Now we come to rules of static initialization. Here, we will go according to your code.
When class is loaded and no illegal forward reference is not there , all the static variables have been initialized to default value and are present in memory.
Now, after this static initialization takes place.
class Test {
static {
System.out.println(Test.a); // prints 0
a = 99; // a get 99
System.out.println(Test.a); // prints 99
}
static int a = 10;
static {
System.out.println(a); // prints 10
}
public static void main(String[] args) {
}
}
Well, the static block
static {
System.out.println(a);
a = 99;
System.out.println(Test.a);
}
will be executed before a is declared.
The line with Test.a won't fire any error because the compiler checks and finds static variable a declared within class Test.
Class initializers are run at the time that the class is loaded, and you cannot determine when exactly this happens. Code that runs within a class initializer should only be for things that need to be processed or "initialized" for other static methods (or the class itself) to work properly.
Additionally, you are referencing a variable that has not yet been declared. In your class initializer (the first static block) you assign a = 99, but a has not yet been declared. If anything you'd want to declare the variable, and then initialize it within the static block.
There is no reason to use class initializers for the type of code you are posting. This should be a static method if anything.
Here's an example
class Test{
static int a = 10;
static void doSomething(){
System.out.println(a);
a = 99;
System.out.println(a);
}
}
Then in main you can call Test.doSomething();

Hash set with static initilazation parameters

I was going through some classes in which I have found one hashset implementation like this
public static HashSet<String> set = new HashSet<String>();
static{
set.add("abc");
set.add("def");
set.add("eghi");
}
In static block, I just want to know what this pattern known as,static initialization.Does it mean initially when the jvm is up we have the set with initialized values.
Please advise.
StaticInitializer:
static Block
If you see JLS-8.7
A static initializer declared in a class is executed when the class is initialized (§12.4.2). Together with any field initializers for class variables (§8.3.2), static initializers may be used to initialize the class variables of the class.
Note :
Use of class variables whose declarations appear textually after the use is sometimes restricted, even though these class variables are in scope. See §8.3.2.3 for the precise rules governing forward reference to class variables.
The static block only gets called once at the time of class loading, no matter how many objects of that type you create.
Static block will have no access to the non static instance variables or methods.
You can use static block to handle exceptions during initialization.
The fact that static blocks are executed during the loading of class and even before the constructor is called, this feature can be used in singleton pattern.
Yes this is static initialization block.
About Static initialization block:
A static initialization block is a normal block of code enclosed in braces, { }, and preceded by the static keyword.
When it will load:
A class can have any number of static initialization blocks, and they can appear anywhere in the class body. The runtime system guarantees that static initialization blocks are called in the order that they appear in the source code.

Why can you access static field before it is defined through a method in Java?

I ran into an interesting thing:
static {
System.out.println(test); // error cannot reference a field before it is defined
System.out.println(cheat()); // OK!
}
private static boolean cheat() {
return test;
}
private static boolean test = true;
public static void main(String args[]) {}
The first way is wrong and both your compiler and IDE will tell you it's wrong. In the second case, cheating is OK, but it actually defaults the field test to false. Using Sun JDK 6.
This is defined in the JLS 8.3.2.3. In particular:
The declaration of a member needs to appear textually before it is used [...] if the usage occurs in a [...] static initializer of C.
When you call cheat() you go around that rule. This is actually the 5th example in the list of the examples of that section.
Note that cheat() will return false in the static initializer block because test has not been initialised yet.
Because class loading works in this order:
Loads Class definition (methods, signatures)
Allocates the memory for the static variable references (for test) - does not initialize yet
Executes the static initializers (for variables) and the static blocks - in order they are defined
So, by the time you have reachstatic block, you have the method definition ready, but don't have the variable ready. With cheat() you're actually reading an uninitialized value.
This is the generic steps by which class loading happens.
Loading - Load the class to memory
Verification - checks binary representation of a class e is correct
Preparation - create the static fields for the class and initialize those fields to their standard default values.
Initializing - will invoke static initializers and initializers for static fields
After preparation, your test will be false.Then before you assign static variable to true, your static block will execute.That is why you are getting false.
Try making your static variable final.In that case,you will be getting true.This is because your compiler itself will embed the value in bytecode(since the field is final) as part of optimisation

How do you disable lazy class loading/initialization in Sun's JVM?

By default, Sun's JVM both lazily loads classes and lazily initializes (i.e. calls their <clinit> methods) them. Consider the following class, ClinitBomb, which throws an Exception during a static{} block.
public class ClinitBomb {
static {
explode();
}
private static void explode() {
throw new RuntimeException("boom!");
}
}
Now, consider how to trigger the bomb:
public class Main {
public static void main(String[] args) {
System.out.println("A");
try {
Class.forName("ClinitBomb");
} catch (Exception e) {
e.printStackTrace(System.out);
}
System.out.println("B");
ClinitBomb o2 = new ClinitBomb();
System.out.println("C");
}
}
We're guaranteed the explosion happens before point B, since forName's documentation says so; the question is whether it happens before point A (when Main is loaded.) In Sun's JVM, even though main() contains a static reference to ClinitBomb, it happens after A.
I want a way to tell the JVM to load and initialize ClinitBomb as soon as it initializes Main (so the bomb explodes before point A.) In general, I want a way to say, "whenever loading/initializing class X, also do so for any classes Y it references."
Is there a way to do that?
There is no way to do this. The JLS says, in §12.4.1 When Initialization Occurs (emphasis mine):
Initialization of a class consists of executing its static initializers and the initializers for static fields declared in the class. [...]
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.
T is a class and 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, and an assert statement (§14.10) lexically nested within T is executed.
Invocation of certain reflective methods in class Class and in package java.lang.reflect also causes class or interface initialization. A class or interface will not be initialized under any other circumstance.
A Java implementation which initialized classes as soon as they were loaded would violate the JLS.
Although what you could do would be to use the JVM instrumentation API to write a ClassFileTransformer which added a static block to every class which explicitly initialized its referenced classes (via Class.forName, probably). As soon as one class gets initialized, all the classes reachable from it will be initialized. That might give you the result you're after. It's quite a lot of work, though!
Class.forName("...", true /*initialize*/, getClassLoader());
You were halfways there.

Categories

Resources