Question

I am having problem with my final variable. Any help will be greatly appreciated.

This is my first code which is working fine

final int i = 90; 
byte b = i ; 
System.out.println(i);

Here is my second code which says possible loss of precision. What is wrong here?

final int i; 
i = 90;
byte b = i ; 
System.out.println(i);
Was it helpful?

Solution

I couldn't find the exact reason about this in JLS, so I went through the byte code and found that the reason is that the compiler couldn't inline the value of i in the second case, but is able to do it in the first case.

Here's the code:

final int x = 90;
System.out.println(x);

final int i;
i = 90;
System.out.println(i);

The compiled byte code looks like:

 0: getstatic     #2        // Field java/lang/System.out:Ljava/io/PrintStream;
 3: bipush        90
 5: invokevirtual #3        // Method java/io/PrintStream.println:(I)V
 8: bipush        90
10: istore_2
11: getstatic     #2        // Field java/lang/System.out:Ljava/io/PrintStream;
14: iload_2
15: invokevirtual #3        // Method java/io/PrintStream.println:(I)V
18: return

So in the first case (3 to 5), it directly uses the value 90 for printing, while in the second case (8 to 15), it has to store the value into the variable and then load it back onto the stack. Then the print method will pick the top value of the stack.

So, in case of the assignment:

byte x = i;

The value of i will be picked up from the stack at runtime, and not inlined by the compiler. So the compiler doesn't know what value i might contain.

Of course, this is all my guess. The byte code might be different on different JVMs. But I've the strong intuition that this might be the reason.

Also, JLS §4.12.4 might be relevant here:

A variable of primitive type or type String, that is final and initialized with a compile-time constant expression (§15.28), is called a constant variable.

Since in the second case, the variable is not initialized by a constant expression, but is later assigned a value, it is no longer a constant variable.

OTHER TIPS

Simply, the first way the compiler "knows" that 90 can fit into a byte variable, but in the second, it can't detect the value of "i" and has no idea what value it might contain and therefore not sure it could fit into a byte variable or not.

At the compile time compiler can determine the value of final variable if it is assign at the time of creation but in second code you are assigning the value after creation which will not catch by the compiler.

If you use more than 127 in first code (for variable i) it will not work too.

Spec says “If a primitive type or a string is defined as a constant and the value is known at compile time, the compiler replaces the constant name everywhere in the code with its value. This is called a compile-time constant

And

Compile time constant are:

declared final

primitive or String

initialized within declaration

initialized with constant expression

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top