I am getting confused with below code I expected that it will give an error or answer will be 10 but it is giving 20 how?
public class test {
public static void main(String[] args) {
System.out.println(x);
}
static{
x=10;
}
static int x=20;
}
It's specified in section 12.4.2 of the JLS, which gives details of class initialization:
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 variable initializer (x = 20) occurs after the static initializer (the block containing x = 10) in the program text. The value at the end of initialization is therefore 20.
If you swap the order round so that the variable initializer comes first, you'll see 10 instead.
I'd strongly advise you to avoid writing code which relies on textual ordering if possible though.
EDIT: The variable can still be used in the static initializer because it's in scope - just like you can use an instance variable in a method declared earlier than the variable. However, section 8.3.2.3 gives some restrictions on this:
The declaration of a member needs to appear textually 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.
The usage is via a simple name.
C is the innermost class or interface enclosing the usage.
It is a compile-time error if any of the four requirements above are not met.
So if you change your static initializer to:
static {
System.out.println(x);
}
then you'll get an error.
Your existing static initializer uses x in a way which does comply with all of the restrictions, however.
in static if a value is changed once then it will be effected through out.
So you are getting 20.
if you write this way
public class test {
static int x=20;
public static void main(String[] args) {
System.out.println(x);
}
static{
x=10;
}
}
then it will print 10.
Related
I was reading the question here : Java : in what order are static final fields initialized?
According to the answer
"except that final class variables and fields of interfaces whose
values are compile-time constants are initialized first ..."
I think this is not correct because the following will fail :
static {
String y = x;
}
public static final String x = "test";
In the static block, x is not recognized. Can anyone please comment if that answer is correct ?
The order of initialization doesn't change the fact that the JLS doesn't let you refer to variables before they're declared in various cases. This is described 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.
That's why your code gets this compilation erorr:
error: illegal forward reference
The statement that static fields that are constant variables are initialized first is indeed defined in JLS§12.4.2:
Otherwise, record the fact that initialization of the Class object for C is in progress by the current thread, and release LC.
Then, initialize the static fields of C which are constant variables (§4.12.4, §8.3.2, §9.3.1).
...
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.
As you can see, constant variables are initialized in step 6, but others in step 9.
This demonstrates the behavior:
public class Example {
static String y;
static {
y = foo();
}
static String foo() {
return x.toUpperCase();
}
public static final String x = "test";
public static void main(String[] args) throws Exception {
System.out.println(x);
System.out.println(y);
}
}
That compiles, and outputs:
test
TEST
In contast, if you change the x line so it's not constant anymore:
public static final String x = Math.random() < 0.5 ? "test" : "ing";
It compiles, but then fails because x is null as of y = foo();.
For the avoidance of doubt: I don't recommend using methods to initialize fields like that. :-)
As this answer states:
... they are initialized in the order in which they appear in the source.
You are absolutely right, your example fails, because you are trying to use a variable that is declared after the usage. Since static block are executed in order of the source code, you are absolutely correct and should suggest and edit for that answer, because this statement is invalid:
except that final class variables ... are initialized first.
I'm studying for Oracle's OCA 8 certification. In my studies, I came across an issue that left me with some doubts about the order of initialization of a Java object (static blocks, constructors, initialization of variables, ...). The question is as follows:
public class InitTest{
static String s1 = sM1("a");{
s1 = sM1("b");
}
static{
s1 = sM1("c");
}
public static void main(String args[]){
InitTest it = new InitTest();
}
private static String sM1(String s){
System.out.println(s); return s;
}
}
My question is the order in which each part of the object is started:
1) {...}
2) static {...}
3) InitTest {...}
4) static String s1 = sM1("a");
Can you explain me, please?
Order of initalization is always as follows:
initialize superclasses recursively (not relevant for the example in question since it doesn't have a superclass)
static fields and static initializers
instance fields and instance initializers
constructors
Hence, the order of initialization in your example will be:
1) static String s1 = sM1("a"); - static initialization blocks and static field members are the first to be processed, this happens just after the classloader loads the class (before you start using the class or create an object). If there are more initializers or static member declarations, they are executed in the order in which they are written. That's why this static field will get initialized before the static initializer block.
2) static {...} - explained in point 1. The static initializater comes before the declaration of static variable s1 so that's why it it is processed in this order (both have the same priority but here the order inside of the class wins if both have the same prio).
3) {...} - after the static initializers and static fields, the instance initializers and instance fields are initialized, so the instance initializer is next after the static initializer and static field s1. They are the first to be processed when creating a new object using a constructor and this happens before the constructor actually gets executed.
4.) InitTest {...} - The constructor gets called after everything else is initalized (all initialization blocks and field initializations).
More details about the class and object initialization order you can find in the Java Language Specification: https://docs.oracle.com/javase/specs/jls/se11/html/jls-12.html#jls-12.4.1, https://docs.oracle.com/javase/specs/jls/se11/html/jls-12.html#jls-12.4.2,
https://docs.oracle.com/javase/specs/jls/se11/html/jls-12.html#jls-12.5
First: The part of s1 = sM1("b") is formatted like it is part of s1 definition, but it's completely separate.
static { ... } and static String s1 =sM1("a") are both static, which means they run when the JVM loads the class, before any of the code in your Main. they are executed in the order they are written.
{...} and InitTest{...} aren't static and they run only when you create the instance of InitTest.
{...} is initialization block and run before the constructors.
Anything that's static is first taken care of as there is no reason for an object availability, The possible static contents in a class are,
a) static instance variable
b) static code block
c) static methods
and are evaluated in the same order (although order for a static method doesn't matter). So in your case the s1 = SM1("a") is evaluated first which results in the call to the sM1("a") method. Next the static code block is executed which results in sM1("c") and finally the instance code block is executed with sM1("b"). If you happen to have a no arg constructor in this class, then it would have got called as the last step before the object is available.
In Java, initialization of static variables is executed in textual order. As a result it's not possible to access a static variable e.g. in a static initializer block before it is decleared.
However, I noticed that there are certain possibilities to access a static variable before it is declared.
Given the following code:
static {
STATIC = true;
}
public static boolean STATIC = false;
public static void main (String[] args) {
System.out.println(STATIC);
}
One would expect that there is a compile error in the static initializer block (STATIC = true;), but it's actually compiling fine. Furthermore, the output of the program is false. I'd expect it to be true, since I'm assigning a value to it in the static initializer.
Why is this code snippet not a compile error and why is the variable not set to true after initialization?
In which cases (in general) is it possible to forward access a static variable in Java?
Why is this code snippet not a compile error and why is the variable not set to true after initialization?
Java allows forward references to static variables if it is used on the left hand side of an assignment statement. The reason why the value is false after initialization is, that when Java reaches the static initializer block, the variable STATIC is already declared (which happens before actual initialization of the class) and initially set to false (default value). After the static initializer, the assignment on the declaration line is still executed and the value will end up as false.
In which cases (in general) is it possible to forward access a static variable in Java?
The Java Language Specification (JLS) for Java 8 says in 12.4.1 When Initialization Occurs:
The static initializers and class variable initializers are
executed in textual order, and may not refer to class variables
declared in the class whose declarations appear
textually after the use, even though these class variables are in
scope (§8.3.3).
In general, as stated, forward references are not allowed. But there are certain exceptions described in 8.3.3 Forward References During Field Initialization:
8.3.3. Forward References During Field Initialization
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
To illustrate these conditions, I created the class ThisClass with an example for each of the conditions. If only one of those four conditions is false, it's not a compile error!
1. The declaration of a class variable in a class or interface C appears textually after a use of the class variable
public static boolean STATIC1 = false;
static {
if (!STATIC1) {
System.out.println("Set STATIC1 to true");
STATIC1 = true;
}
}
The usage of STATIC1 occurs after it is defined. The most basic condition for a compiler error is violated. As you would expect, the value of STATIC1 after initialization is true.
2. The use is a simple name in either a class variable initializer of C or a static initializer of C
static {
if (!ThisClass.STATIC2) {
System.out.println("Set STATIC2 to true");
ThisClass.STATIC2 = true;
}
}
public static boolean STATIC2 = false;
The first condition is now met, but the second condition is violated. We are using the qualified name (and not the simple name) to access the variable STATIC2. The difference is described in the JLS in 6.2 Names and Identifiers:
There are two forms of names: simple names and qualified names. A
simple name is a single identifier. A qualified name
consists of a name, a "." token, and an identifier.
More interesting is, what actually happens during initialization. On the first line of the static initializer, the value of STATIC2 is read via the class qualifier. At this point (since the class is initialized in textual order) the variable STATIC2 has not been initialized yet. In this case, the default value is used, which for boolean is false. The if block is entered and the value of STATIC2 is set to true. Initialization is continued and STATIC2 is set to false again, which is the state the variable will be in after initialization.
Note: To prove that the assignment to true actually happens, you can try something like this:
static {
if (!ThisClass.STATIC2a) {
System.out.println("Set STATIC2a to true");
ThisClass.STATIC2a = true;
}
}
public static boolean STATIC2a;
This code compiles perfectly fine and the value of STATIC2a at the end of initialization will be true! The last line of code can even be replaced with the following curious statement, which clarifies even more what's happening:
public static boolean STATIC2a = ThisClass.STATIC2a;
3. The use is not on the left hand side of an assignment
static {
System.out.println("Set STATIC3 to true");
STATIC3 = true;
}
public static boolean STATIC3 = false;
Now we are using the class variable before declaration and are using it with a simple name. However, the third condition in the JLS is not met, since it appears on the left hand side of an assignment. What happens is more or less the same as if it was accessed qualified. The default value false of STATIC3 is overridden with true and then set back to false on the last line of code.
Note: The same as in example 2a holds true. If there is no assignment on the last line of code (or the STATIC3a = ThisClass.STATIC3a no-op), STATIC3a is initialized to true:
static {
System.out.println("Set STATIC3a to true");
STATIC3a = true;
}
public static boolean STATIC3a;
4. C is the innermost class or interface enclosing the use
static class OtherClass {
static {
if (!STATIC4) {
System.out.println("Set STATIC4 to true");
STATIC4 = true;
}
}
}
public static boolean STATIC4 = false;
STATIC4 is defined in the outer class ThisClass and therefor not defined in the innermost class from the perspective of use in OtherClass. The first line in the static block meets all three above conditions. Declaration appears textually after the use, it's referenced by a simple name and the use is also not on the left hand side of an assignment. But since outer classes are always initialized before any nested class, the STATIC4 = false assignment in ThisClass happens before the static initializer in OtherClass.
It is important to see, that initialization of OtherClass does not have to happen when the outer ThisClass is initialized (it might even be loaded, but loading != initialization). We need to make sure, that OtherClass is initialized by e.g. creating an instance of it (see 12.4.1 in the JLS).
The whole program can be studied here:
http://ideone.com/fl5Vet
i am trying to follow the JVM specs http://docs.oracle.com/javase/specs/jls/se8/html/jls-12.html#jls-12.4.2.
Is frustrating for me to read the unclear specs. So:
What are the differences between:
class variable initializers
static initializers of the class
field initializers
/*
Initalizers
*/
class A {
private static String x = "sfi"; //static field initializer
private String ifi = "ifi"; //instance field initializer
static { //static (block) initalizer ?!
String y = "sbi";
}
{ //instance (block) initalizer ?!
String z = "ibi";
}
}
Static members
First you need to understand the difference between static and non-static fields of a class. A static field is not bound to any instance of the class, it is a property of the class (that is the reason why we access them through the class) so in your example you can access x from whithin A like this: A.x. A common example for this is counting the number of objects a class has:
private static int counter = 0;
public A()
{
counter++;
}
// get the instance count
public static int getCounter()
{
return counter;
}
This method we would call from somewhere else like this: A.getCounter() and we will retrieve the number of objects that have the type A.
Non-static members
These are variables that are specific to each object (instance) of the class. In your example this is sfi. The runtime system guarantees that sfi will be available whenever an object of type A is created and that it will have a default value of ifi, but the difference here is that each object you create will have a member called sfi with a default value of ifi so each object can later modify it of course.
Initializing blocks
They are a feature designed to be used when initialization cannot be done inline (initialization requires more complex logic like a for loop or error-checking). Here again we have:
static { /* init code ... /* }
which is a static initialization block that "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" - from here
If, on the other hand, we want to initialize instance members but we cannot do it in one line then we can use a block but without the static keyword:
{
// init code for instance members
}
The Java compiler copies initializer blocks into every constructor. Therefore, this approach can be used to share a block of code between multiple constructors.
Can someone explain me what the following is?
public class Stuff
{
static
{
try
{
Class.forName("com.mysql.jdbc.Driver");
}
catch ( ClassNotFoundException exception )
{
log.error( "ClassNotFoundException " + exception.getMessage( ) );
}
...
}
What does this static { ...} do?
I know about static variables from C++, but is that a static block or something?
When is this stuff going to get executed?
The static block is called a class static initializer - it gets run the first time the class is loaded (and it's the only time it's run [footnote]).
The purpose of that particular block is to check if the MySQL driver is on the classpath (and throw/log error if it's not).
[footnote] The static block run once per classloader that loads the class (so if you had multiple class loaders that are distinct from each other (e.g. doesn't delegate for example), it will be executed once each.
The primary use of static initializers blocks are to do various bits of initialization that may not be appropriate inside a constructor such that taken together the constructor and initializers put the newly created object into a state that is completely consistent for use.
In contrast to constructors, for example, static initializers aren't inherited and are only executed once when the class is loaded and initialized by the JRE. In the example above, the class variable foo will have the value 998877 once initialization is complete.
Note also that static initializers are executed in the order in which they appear textually in the source file. Also, there are a number of restrictions on what you can't do inside one of these blocks such as no use of checked exceptions, no use of the return statement or the this and super keywords.
I want to add that static variables and static initializers are executed in order of appearance at the time of class loading. So, if your static initializer relies on some static variable, it must be initialized before the particular static block, e.g.
final static String JDBC_DRIVER = getJdbcDriver( );
static
{
try
{
Class.forName(JDBC_DRIVER);
}
catch ( ClassNotFoundException exception )
{
log.error( "ClassNotFoundException " + exception.getMessage( ) );
}
}
In this example getJdbcDriver will get executed before static initializer. Also, there may be more than 1 static initializer in the class. Once again they are executed in order of appearance.
I also want to mention the existence of instance initializers here, as they do come as surprise when seen for the first time. They look like a code block inside the class body, like this.
class MyClass
{
final int intVar;
{
intVar = 1;
}
}
In general case their use is somewhat unnecessary, because of the constructor, but they are useful in implementing Java's version of closures.
The static initializer block get executed whenever the class is to be loaded for the first time. That can happen if something at higher level is doing a Class#forName("yourpackage.YourClass") or a new YourClass() on the class in question for the first time.
By a coincidence, the decent JDBC drivers also have something similar inside. They namely registers themselves in the DriverManager using a static initializer block:
static {
DriverManager.registerDriver(new ThisDriver());
}
so that whenever you do a Class.forName("somepackage.ThisDriver"), you will effectively register the driver in the DriverManager so that you can get a connection from it afterwards.
In addition to all above , there is a minute difference in using class constructor and class initializer. Constructor as we know that will be usually used to initialized the objects and if we have static variables then static block is usually used in order to initialize them when the class will be loaded.
When we have static variables and static block then static variables initialized first and then the block.
When class is first loaded, static block initializes before the class constructor.
static initialization block
is a normal block of code
it is enclosed in braces { }
it is preceded by the static keyword
class Foo {
static {
// initialization code goes here:
doSomething();
}
}
class can have any number of static initialization blocks
they can appear anywhere in the class body
they are called in the order of apperence in the code
There is an alternative to static initialization blocks:
write a private static method
and assign it to the static class variable
The advantage of this approach is that the static method can be invoked later to reinitialize the class variable.
class Foo {
public static int myVar = initializeClassVariable();
private static int initializeClassVariable() {
// initialization code goes here:
int v = 255;
return v;
}
}