views:

1397

answers:

5

hi all,

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. :)

+11  A: 

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.

Dirk
so, you're saying public static final is compile time constant? didn't know that. thought it was just a constant and can't be modified in runtime! thanks for your help.
tony_le_montana
Good anwser. If you want to see that the variable is being inlined, you can use javap to see how the class was compiled, e.g. "javap -c Flags".
John Paulett
+2  A: 

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.

Simon
+1  A: 

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.

Peter Lawrey
One or other of the classes may not be under your control.
DJClayworth
A: 

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.

TofuBeer
A: 

This is exactly the problem with me too. There is a class with all public staic final varibles. In eclipse when I change any of these, the IDE bulids the project again, and recomplies the classes using the psf varible. So thats the only solution upto may me jdk 1.4, psf variables are hard coded.

--Best Regards

Adi