public class Main {
public static void main(String[] args) {
System.out.println(B.x);
}
}
class A {
public static String x = "x";
}
class B extends A {
static {
System.out.print("Inside B.");
}
}
Question: Why output will be: x. But not: Inside B.x
The reference to B.x issues the following bytecode:
getstatic #3 <Field int B.x>
According to Java Virtual Machine Spec
The Java virtual machine instructions anewarray, checkcast, getfield,
getstatic, instanceof, invokedynamic, invokeinterface, invokespecial,
invokestatic, invokevirtual, ldc, ldc_w, multianewarray, new,
putfield, and putstatic make symbolic references to the runtime
constant pool. Execution of any of these instructions requires
resolution of its symbolic reference.
So the JVM should resolve the symbolic reference to B.x. The field resolution is specified like this:
To resolve an unresolved symbolic reference from D to a field in a
class or interface C, the symbolic reference to C given by the field
reference must first be resolved (§5.4.3.1).
...
When resolving a field reference, field resolution first attempts to
look up the referenced field in C and its superclasses:
If C declares a field with the name and descriptor specified by the
field reference, field lookup succeeds. The declared field is the
result of the field lookup.
Otherwise, field lookup is applied recursively to the direct
superinterfaces of the specified class or interface C.
Otherwise, if C has a superclass S, field lookup is applied
recursively to S.
Otherwise, field lookup fails.
In other words the JVM will resolve B.x into A.x. This is why only A class needs to be loaded.
Because B.x is actually A.x so only the A class needs to be loaded.
§12.4 "Initialization of Classes and Interfaces" of The Java Language Specification, Java SE 7 Edition specifies that:
Initialization of a class consists of executing its static initializers and the initializers for static fields (class variables) declared in the class.
[…]
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.
So although — contrary to claims in some of the answers above — class B does have to be loaded, in order to determine that B.x is declared in A, class B is not initialized (i.e., its static initializers are not actually run) until you do something more specific to B.
It doesn't actually need to load B until it accesses a static member of B directly. Note that this code:
public class TestMain {
public static void main(String[] args) {
System.out.println(B.x);
System.out.println(B.y);
}
static class A {
public static String x = "x";
}
static class B extends A {
public static String y = "y";
static {
System.out.print("Inside B.");
}
}
}
Will output:
x
Inside B.y
Because it doesn't need to load B until something in B is accessed.
Here's a good link on the subject. From the article, "And dont forget, this code will be executed when JVM loads the class. JVM combines all these blocks into one single static block and then executes. Here are a couple of points I like to mention: "
Class B extends A which has an public static variable x which you are accessing when you call B.x
If you expect Inside B. as out put you have to create an Object of that class. All the static code blocks are executed. or move that static code block to class A :-)
When JVM loads class it groups all the static blocks and execute them in the sequence they are declared.
EDIT (Source):
The short answer is that statics are NOT inherited in Java. Rather, the static members declared in a class are (subject to "access" restrictions) directly visible in the namespace of derived classes, unless they "hidden" by declarations in the derived class.
So if the Static belongs to the Class only why does it trickle down to
the derived class ? Shouldn't it just stay with the Class in which it was
defined ?
Related
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();
I have a question regarding static blocks:
Let's say i've got a class looking like this:
class SomeClass {
static {
System.out.println("static block");
}
}
and I define a variable of type SomeClass somewhere.
public static void main(String args[]) {
SomeClass foo;
}
Now i thought the static block would have been executed but it wasn't. As far as i know the static block is executed as soon as the classloader loads the SomeClass class. Now to my real question:
Isn't the class loaded as soon as I define a variable of that type?. If yes why isn't the static block executed?
If the answer should be no, then how can i know if a class has already been loaded by the class loader and what are the different possibilities to have the class loaded (I know of 2: initializing the variable & using a static field/method)
Refer to this doc: http://www.javaworld.com/article/2077260/learn-java/learn-java-the-basics-of-java-class-loaders.html
So when are classes loaded? There are exactly two cases: when the new bytecode is executed (for example, FooClass f = new FooClass();) and when the bytecodes make a static reference to a class (for example, System.out).
In your example, SomeClass foo; does neither execute the bytecode of SomeClass nor make a static reference to SomeClass. That's why the class is not loaded.
So following your example, add a static field in the class
public class SomeClass {
static {
System.out.println("static block");
}
static String abc = "abc";
}
SomeClass is loaded in either:
SomeClass foo = new SomeClass();
Or
System.out.println(SomeClass.abc);
Isn't the class loaded as soon as I define a variable of that type?.
Yes, it is loaded1, but it won't be initialized as a result of declaring a variable. However, when you create an instance of that type, or access a static field of that type, that is sufficient to trigger initialization, including the execution of static blocks.
See this related Q&A - When does static class initialization happen? - which lists all of the things that can trigger initialization.
How can i know if a class has already been loaded by the class loader and what are the different possibilities to have the class loaded (I know of 2: initializing the variable & using a static field/method)
The only ways I can think of for finding out when a class is loaded (as distinct from initialized) are:
turning on the JVM's class loader messages (using -verbose:class), or
using a customer classloader that notices, and does something appropriate when it sees a request to load the class.
A class is actually going to be loaded:
when it is explicitly loaded using Class.forName or similar, or a direct call to a classloader,
when it is necessary to load it in order to link another class, or
at JVM launch time, if the class is named as the entry point class.
The loading / linking / initializing steps are specified in Chapter 12 of the JLS.
1 - In fact, SomeClass needs to be loaded at the same time that the class containing that main method is linked; i.e. before the method containing that local declaration is called.
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();
class Main
{
public static void main (String[] args) throws java.lang.Exception
{
}
public class SuperInner{
int a;
}
public class Inner{
public class MegaInner{
public MegaInner(){
Main.SuperInner.this.a = 6; //error: not an enclosing class: Main.SuperInner
}
}
}
}
IDEON
What JLS says is:
Let C be the class denoted by ClassName. Let n be an integer such that
C is the n'th lexically enclosing class of the class in which the
qualified this expression appears.
[...]
It is a compile-time error if the current class is not an inner class
of class C or C itself.
In the case C:=Main, the set of inner classes S := {SuperInner, MegaInner, Inner}. Which means the code above should work fine. What's wrong?
One could have multiple instances of SuperInner, as well as of Inner or MegaInner.
Calling Main.SupperInner.this.a from within MegaInner, it wouldn't be clear which instance (if there is an instance at all) should have the a variable set to 6.
The inner classes behave much like normal classes: one always needs an instance to set a variable in them. Main.SuperInner.this does not denote an instance from MegaInner's view, as this only refers to the class-hierarchy of MegaInner, which SuperInner is not a part of.
The "Qualified this" expression Main.SuperInner.this.a appers inside MegaInner.
The enclosing classes of MegaInner are Inner and Main. So this is the 0th qualified this, Inner.this is the 1st qualified this, and Main.this is the 2nd qualified this.
The part you were missing is that it has to be an enclosing class of the class where the expression with the this appears. SuperInner is not an enclosing class of MegaInner and therefore the Qualified this does not apply to it.
Think about it in reality. A this expression refers to an instance of the class. It does not refer to the class itself. You cannot refer to this from a static method, for example.
Now, when you create an instance of MegaInner, it has to be part of an actual instance of Inner and an actual instance of Main. But there is no guarantee that there is an actual instance of SuperInner. The code of the enclosing classes may create objects of type SuperInner at any time and independently of instances of Inner.
Thus, you can't access a this of it at compile time. But if you are given an instance of it through a reference variable, you are allowed to access the variable a, as they are all members of the same outer class.
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.