This problem that has bitten me in the ass a few times, and I'd love to hear any bright ideas on how y'all avoid it.
Suppose you have an interface that defines some useful constants:
public interface foo {
int five = 6;
}
and a class that uses those constants:
public class bar {
public static void main(String[]args) {
System.out.println("five: "+foo.five);
}
}
All well and good, until you realize that five isn't really 6, it's 5. Whoops, change the foo
java file and rebuild, right? Well, if you use javac *.java
to do this (as you might, if you only have the foo
and bar
files), then you'll be alright.
But, if you're like the other 99% of the java development world, and you use a build tool, like ant, smart enough to look at timestamps, you'll still get 6 for the output of java bar
. Ant is smart enough to look at the timestamps of .class and .java files to determine which .java files have changed since it last did a compilation. But it is too dumb to realize that the bar
class has a dependency on foo
, and should thus be recompiled even though bar.java
is older than bar.class
. (I haven't looked at the byte code, but I expect that the value of five
is just inlined into the bar
class because it's a final variable.) If you're using a make based build system, I believe you can use javadeps to build out the correct dependency list, but I haven't seen anything similar for ant. Another options is to just remember to blow away your build directory anytime you change your 'constants'.
I guess this is why properties files might be a better choice for this type of configuration information, because they're always read in anew at startup, and thus cannot be inlined (since they're a runtime thing). Of course, then you lose the benefits of type checking. Not sure what the correct answer is.
Posted by moore at April 21, 2004 12:38 AM | TrackBackWell, and what do you think about such code to prevent constant inlining?
public class foo {
public static final int five;
static {
five = 5;
}
}
or (especially for String constants)
public class foo {
public static final String five = "five".toString();
}