I have class AbstractsAndInterfaces
:
public static AbstractsAndInterfaces instance = new AbstractsAndInterfaces();
private static final int DELTA = 5;
private static int BASE = 7;
private int x;
public AbstractsAndInterfaces()
{
//System.out.println(BASE);
//System.out.println(DELTA);
x = BASE + DELTA;
}
public static int getBASE()
{
return BASE;
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
System.out.println(AbstractsAndInterfaces.instance.x);
}
Why does it print 5?
Why BASE
variable is uninitialized?
That's because :
private static final int DELTA = 5;
will be a compile-time constant. So, 5 will already be available (initialized) when the class gets initialized (once it is loaded).
The first line that gets executed is :
public static AbstractsAndInterfaces instance = new AbstractsAndInterfaces();
So, now you will go to :
public AbstractsAndInterfaces()
{
//System.out.println(BASE);
//System.out.println(DELTA);
x = BASE + DELTA; // same as x= 0+5 i.e default value of fields + constant value 5
}
In the above code, DELTA
will be 5 but BASE
will be 0 as it is not final
. Changing BASE
to final will change the result to 12
.
EDIT :
Sample code to show the OP's scenario with byte code.
public class Sample {
static Sample s = new Sample();
static final int x = 5;
static int y = 10;
public Sample() {
int z = x + y;
System.out.println(z);
}
public static void main(String[] args) {
}
}
In the above code, when the program is run, the output will be 5
and not 10
. Now let us look at the byte-code.
The byte code of constructor looks like this :
p
ublic Sample();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=2, locals=2, args_size=1
0: aload_0
1: invokespecial #24 // Method java/lang/Object."<init>
:()V
4: iconst_5 -------> // Here 5 is used directly as it is a compile time constant
5: getstatic #20 -------> // Field y:I
8: iadd
9: istore_1
10: getstatic #25 // Field java/lang/System.out:Ljav
/io/PrintStream;
13: iload_1
14: invokevirtual #31 // Method java/io/PrintStream.prin
ln:(I)V
17: return
Byte code for static init block :
static {}; descriptor: ()V flags: ACC_STATIC Code: stack=2, locals=0, args_size=0 0: new #1 // class Sample 3: dup 4: invokespecial #15 // Method "":()V 7: putstatic #18 // Field s:LSample; 10: bipush 10 12: putstatic #20 // Field y:I 15: return LineNumberTable: line 3: 0 line 5: 10 line 1: 15 LocalVariableTable: Start Length Slot Name Signature
If you check carefully, x
is not being initialized in the static init of class. Only y
is being set as it is static. But when you look at the constructor, you will see that the constant 5 is directly being used (iconst_5
) and pushed onto the stack.
Now if you add the following code in main()
:
public static void main(String[] args) {
System.out.println(Sample.x);
System.out.println(Sample.y);
}
The byte code for main()
will be :
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=1, args_size=1
0: getstatic #25 // Field java/lang/System.out:Ljav
a/io/PrintStream;
3: iconst_5 --> // No "x" but a constant value instead of "x"
4: invokevirtual #31 // Method java/io/PrintStream.prin
tln:(I)V
7: getstatic #25 // Field java/lang/System.out:Ljav
a/io/PrintStream;
10: getstatic #20 // Field y:I --> but "y" is being fetched
13: invokevirtual #31 // Method java/io/PrintStream.prin
tln:(I)V
16: return
LineNumberTable:
line 13: 0
line 14: 7
line 15: 16
LocalVariableTable:
Start Length Slot Name Signature
0 17 0 args [Ljava/lang/String;
}
Again observe that x
is being used as iconst_5
whereas y
is being fetched/referred indirectly.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With