Access Static Finite Fields in Java Inner Classes

When I try to compile the following code, I get a compilation error:

unexpected type System.out.println( new Test().Ci ); ^ required: class,package found: value 

 class Test { class C { static final int i = 0; } public static void main(String... z) { System.out.println( new Test().Ci ); } } 

But, if I change new Test().Ci to new Test().new C().i , it compiles just fine.

Why? If I'm static in C, then I don’t need to instantiate C. I should just be able to call it through the C class, not the C object.

What am I missing?

+8
java variables class
source share
2 answers

The problem is that "." Identifier "." Identifier in Java syntax expects an identifier to reference a variable, not a type.

This is indicated in 6.5.6.2. Qualified Expression Names 6.5.6.2. Qualified Expression Names JLS (among other places):

If Q is a type name that names the class type (Β§8 (Classes)), then:

If there is no one accessible (Β§6.6) member of the class type that is a field named Id, then a compile-time error occurs.

Otherwise, if the one available field of an element is not a class variable (that is, it is not declared static), then a compilation time error occurs.

Otherwise, if the class variable is declared final, then Q.Id denotes the value of the class variable.

Expression type Q.Id is the declared type of the class variable after the capture transformation (Β§5.1.10).

If Q.Id appears in a context that requires a variable rather than a value, then a compile-time error occurs.

Otherwise, Q.Id denotes a class variable.

Expression type Q.Id is the declared type of the class variable after the capture transformation (Β§5.1.10).

Note that this sentence covers the use of enumeration constants (Β§8.9), since they always have the corresponding final class variable.

While I can definitely appreciate the logic of why you think it will work, I really expected it to work - it doesn't really matter: since there is always only one i can refer to it Test.Ci If i non-static new Test().new C().i will be the correct way to access it.

Another way to look at this is to read 15.8. Primary expressions that have the actual syntax for primary expressions (what we have here): it allows ClassInstanceCreationExpression (therefore new Test().new C().i works), as well as FieldAccess (which works for Test.Ci because the "class "recursively resolved - only the last identifier should refer to the field).

+5
source share

I think the reason new Test().new C().i works is because the Test class is a top-level class and is considered static . If you changed your inner class C to static, then new C().i would work.

However, you must NOT access static members in an unsteady manner.

To access your static field:

 System.out.println(Ci); 

Edit:

For those who say that the Test class is not static, refer to this stackoverflow description.

All top-level classes are, by definition, static.

What static is reduced to the fact that the class instance can stand on its own. Or vice versa: a non-static inner class (= inner class of an instance) cannot exist without an instance of an outer class. Since the top-level class does not have an outer class, it cannot be anything but static.

Since all top-level classes are static, with the static keyword in the definition of a top-level class is pointless.


Just to show you how a dumb idea is to access a static field, so I created the following project:

 class Test { class C { static final int i = 0; } public static void main(String[] args) { // BAD: System.out.println(new Test().new C().i); // Correct: System.out.println(Ci); } } 

If you compile the class and view it in jd-gui , you can see how it was compiled:

 class Test { public static void main(String[] args) { void tmp13_10 = new Test(); tmp13_10.getClass(); new C(); System.out.println(0); System.out.println(0); } class C { static final int i = 0; C() { } } } 
-2
source share

All Articles