I happen to come across a Java code at my work place. Here's the scenario: There are 2 classes - ClassA
and ClassB
.
ClassA
has nothing except 4 public static final string values inside it. Its purpose is to use those values like ClassA.variable
(don't ask me why, it's not my code).
ClassB
imports ClassA
. I edited the string values in ClassA
and compiled it. When I ran ClassB
I could see it was using the old values - not the new values. I had to recompile ClassB
to make it use new values from ClassA
! (I had to recompile other classes that imports ClassA
!)
Is this just because of JDK 1.6 or I should have known earlier to recompile ClassB
also! Enlighten me. :)
A public static final variable is a compile-time constant, but a public final is just a final variable, i.e. you cannot reassign value to it but it's not a compile-time constant. This may look puzzling, but the actual difference allows how the compiler treats those two variables.
Static variables are created when the program starts and destroyed when the program stops. Visibility is similar to instance variables. However, most static variables are declared public since they must be available for users of the class. Default values are same as instance variables.
Declaring variables only as static can lead to change in their values by one or more instances of a class in which it is declared. Declaring them as static final will help you to create a CONSTANT. Only one copy of variable exists which can't be reinitialize.
The static keyword means the value is the same for every instance of the class. The final keyword means once the variable is assigned a value it can never be changed. The combination of static final in Java is how to create a constant value.
If the values of the final
variables from class ClassA
happen to be compile-time constants, the compiler might have inlined them into the classes using ClassA
instead of generating a run-time reference. I think, this is what happened in the case you described.
Example:
public class Flags {
public static final int FOO = 1;
public static final int BAR = 2;
}
public class Consumer {
public static void main(String[] args) {
System.out.println(Flags.FOO);
}
}
In this example, the compiler will likely incorporate the value of FOO
into the code generated for Consumer
instead of generating the equivalent run-time reference. If the value of FOO
changes later on, you will have to re-compile Consumer
in order to have it use the new value.
This is an optimization, which has a few advantages with respect to efficiency and speed of the program compiled. For example, inlining the value might enable further optimizations in the expressions, which use it, for example:
int x = Flags.FOO * 10;
In this example, inlining the value (here: 1) enables the compiler to notice, that the multiplication makes no difference, and can be omitted alltogether.
It's a binary compatibility issue. References to constant fields are resolved at compile time. The behaviour you are seeing is correct; if you change the values in class A then you will have to re-compile the client (class B). To avoid such problems consider adding constants using an enum type, introduced in Java release 5.0.
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