public static final variable in an imported java class
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 n开发者_StackOverflowothing 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. :)
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.
Suppose ClassA looks like this:
public class ClassA {
public static final int FOO = 1;
public static final int BAR = 2;
}
If you recompile it, ClassB will continue using the old values. I guess it could depend on the compiler, but I think this is the typical behaviour. If you don't want to recompile ClassB everytime a constant in ClassA changes, you'll have to do something like this:
public class ClassA {
public static final int FOO = CONST(1);
public static final int BAR = CONST(2);
public static int CONST(int i) { return i; }
}
Becuase now javac is unwilling to inline the constants. Instead it will call the CONST(int) method when ClassA's static initializer runs.
Why are you trying to compile the classes individually?
Use a build system like maven or ant or just let your IDE do it.
The only safe thing to do is to recompile every java which depends of a java class which has changed until every class which could be effected has been re-compiled.
If you are not using the values in a switch you can do this instead:
public class A
{
public static final int FOO;
public static final String BAR;
static
{
FOO = 42;
BAR = "Hello, World!";
}
}
then the compiler will no longer hard code the values in the other classes that are using them.
精彩评论