It's not, in general.
farewell is a special kind of
static final: one whose value is a constant, as
defined by JLS 15.28. That means that it's
not being initialized at that location, which is
what's actually disallowed in non-static classes
(including local classes), as per JLS 8.1.3.
The JLS states this explicitly (and in bold
font) in 8.1.3 (note the "unless" part):
It is a compile-time error if an
inner class declares a member that is explicitly
or implicitly static, unless the member is a
constant variable (§4.12.4).
If you change that line to either remove the
final modifier or make the expression
non-constant (for example,
bye")), then you'll get the compilation
error you expect:
Test.java:5: error: Illegal static
declaration in inner class EnglishGoodbye
public static final String farewell =
new String("Bye bye");
modifier 'static' is only allowed in constant
A bit more:
The reason this is allowed is that constant
variables are treated specially by the compiler.
In particular, it's allowed to inline them -- the
resulting bytecode doesn't have the
farewell field at all! If you
decompile the class (
YourClassName), you'll see something like
public void sayGoodbyeInEnglish();
0: getstatic #2 // Field
3: ldc #3 //
String Bye bye
5: invokevirtual #4 //
The above corresponds to this line:
It's a bit daunting, but notice that "3:" line.
The program isn't loading the value of the field
farewell, it's loading constant #3
(which it note in a comment is the String "Bye
bye") (you can see a list of the bytecodes on wikipedia).
farewell is a constant
variable (and not a "real" static member), and
thus can be inlined in the code, it doesn't matter
where you define it -- the variable's lifecycle is
essentially that of the whole JVM, not any one
class or instance, and thus it can be declared