I understand that the compiler needs the expression to be known at compile time to compile a switch, but why isn’t Foo.BA_ constant?
While they are constant from the perspective of any code that executes after the fields have been initialized, they are not a compile time constant in the sense required by the JLS; see §15.28 Constant Expressions for the specification of a constant expression1. This refers to §4.12.4 Final Variables which defines a “constant variable” as follows:
We call a variable, of primitive type or type String, that is final and initialized with a compile-time constant expression (§15.28) a constant variable. Whether a variable is a constant variable or not may have implications with respect to class initialization (§12.4.1), binary compatibility (§13.1, §13.4.9) and definite assignment (§16).
In your example, the Foo.BA* variables do not have initializers, and hence do not qualify as “constant variables”. The fix is simple; change the Foo.BA* variable declarations to have initializers that are compile-time constant expressions.
In other examples (where the initializers are already compile-time constant expressions), declaring the variable as
final may be what is needed.
You could change your code to use an
enum rather than
int constants, but that brings another couple of different restrictions: