This seemingly simple concept has some quirks attached to it.
At the outset, it seemed like (or I understood it as) the variables that are static & final are compile time constants.
I stumbled upon this when experimenting with inner classes. I will use the same example here to illustrate.
// Main.java
class OuterClass {
class InnerClass {
static final String CONSTANT = new String("A CONSTANT VALUE");
}
}
So we have a static final String variable CONSTANT in the above code and is initialized by creating a new String object. We know that the value of CONSTANT cannot be changed after this initialization.
But this does not make CONSTANT a compile time constant. Compiling the above code gives this verdict
>javac Main.java
Main.java:5: error: Illegal static declaration in inner class OuterClass.InnerClass
static final String CONSTANT = new String("A CONSTANT VALUE");
^
modifier 'static' is only allowed in constant variable declarations
1 error
A little exploration and we find that the issue is in the way CONSTANT is initialized - using new String(). If we instead initialize it with String literal, it will be a compile time constant. Below code compiles without complaining
// Main1.java
class OuterClass {
class InnerClass {
static final String CONSTANT = "A CONSTANT VALUE";
}
}
as does the below code, in which an expression concatenating two strings is assigned to CONSTANT
// Main2.java
class OuterClass {
class InnerClass {
static final String CONSTANT = "A CONSTANT VALUE" + "THAT CANNOT CHANGE";
}
}
But the below code which assigns null to CONSTANT complains its not compile time constant.
// Main3.java
class OuterClass {
class InnerClass {
static final String CONSTANT = null;
}
}
Definition of a constant is given here
A constant variable is a final variable of primitive type or type String that is initialized with a constant expression (§15.28).
From this definition, a constant variable must be
- Declared as final
- Should be of primitive type or a String
- Must be initialized when it is declared
- And must be initialized with a constant expression
The definition of constant expression is given here
A key takeaway from this definition is a constant variable need not be static.
Stealing from the examples from the definition page, all the below are valid compile time constants
// Main4.java
class OuterClass {
class InnerClass {
final boolean CONSTANT1 = true;
static final short CONSTANT2 = (short)(1*2*3*4*5*6);
final int CONSTANT3 = Integer.MAX_VALUE / 2;
static final double CONSTANT4 = 2.0 * Math.PI;
final String CONSTANT5 = "The integer " + Long.MAX_VALUE + " is mighty big.";
}
}