Declaring a variable as final doesn't make it a compile-time constant.

According to the Java Language Specification, compile-time constant has to be initialized with the compile-time constant expression, which means that it has to have an initializer right where it's declared.

That's why in the first case "a" is a compile-time constant, and "c" is not.

Also, according to JLS, a compile-time constant may be composed of a simple name that refers to a constant variable or a qualified name of the form TypeName.Identifier that refers to a constant variable.

So in the second case you're using s.a and s.c, where s is not a type name, it's an instance name, so those are not compile time expressions.