简体   繁体   中英

Accessing Static Final Fields in Inner Classes in Java

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

unexpected type System.out.println( new Test().C.i );
                                    ^
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().C.i  );
    }

}

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

Why? If i is static in C, then I shouldn't have to instantiate C. I should just be able to call it through the class C, not a C object.

What am I missing?

The problem is that "." Identifier "." Identifier in the Java syntax expects the identifier to refer to a variable and not a type.

This is specified in 6.5.6.2. Qualified Expression Names 6.5.6.2. Qualified Expression Names of the JLS (among other places):

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

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

Otherwise, if the single accessible member field is not a class variable (that is, it is not declared static), then a compile-time error occurs.

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

The type of the expression Q.Id is the declared type of the class variable after capture conversion (§5.1.10).

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

Otherwise, Q.Id denotes the class variable.

The type of the expression Q.Id is the declared type of the class variable after capture conversion (§5.1.10).

Note that this clause covers the use of enum constants (§8.9), since these always have a corresponding final class variable.

While I can definitely appreciate the logic of why you'd think that it'd work like that - I actually expected it to work as well - it's not a big deal: Since there is always exactly only one i you can refer to it by Test.Ci . If i is non-static new Test().new C().i would be the correct way to access it.

Another way to look at it is to read 15.8. Primary Expressions which has the actual syntax for primary expressions (which is what we deal with here): It allows ClassInstanceCreationExpression (which is why new Test().new C().i works) as well as FieldAccess (which works for Test.Ci because the "class" is resolved recursively - only the last identifier has to refer to a field then).

I think the reason why new Test().new C().i works is because class Test is a top-level class and is treated as static . If you were to change your inner class C to be static then new C().i would work.

However, you should NOT access static members in a non-static way.

To access your static field do:

System.out.println(C.i);

Edit:

For those saying that class Test is not static please refer to this stackoverflow answer .

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

What the static boils down to is that an instance of the class can stand on its own. Or, the other way around: a non-static inner class (= instance inner class) cannot exist without an instance of the outer class. Since a top-level class does not have an outer class, it can't be anything but static.

Because all top-level classes are static, having the static keyword in a top-level class definition is pointless.


Just to show you how dumb of an idea it is to access a static field this way 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(C.i);
    }

}

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() {
    }
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM