7

Why can we have static final members but cant have static method in an non static inner class ?

Can we access static final member variables of inner class outside the outer class without instantiating inner class ?

Ashish
  • 2,521
  • 2
  • 21
  • 21

1 Answers1

7

YOU CAN have static method in a static "inner" class.

public class Outer {
    static String world() {
        return "world!";
    }
    static class Inner {
        static String helloWorld() {
            return "Hello " + Outer.world();
        }
    }   
    public static void main(String args[]) {
        System.out.println(Outer.Inner.helloWorld());
        // prints "Hello world!"
    }
}

To be precise, however, Inner is called a nested class according to JLS terminology (8.1.3):

Inner classes may inherit static members that are not compile-time constants even though they may not declare them. Nested classes that are not inner classes may declare static members freely, in accordance with the usual rules of the Java programming language.


Also, it's NOT exactly true that an inner class can have static final members; to be more precise, they also have to be compile-time constants. The following example illustrates the difference:

public class InnerStaticFinal {
    class InnerWithConstant {
        static final int n = 0;
        // OKAY! Compile-time constant!
    }
    class InnerWithNotConstant {
        static final Integer n = 0;
        // DOESN'T COMPILE! Not a constant!
    }
}

The reason why compile-time constants are allowed in this context is obvious: they are inlined at compile time.

polygenelubricants
  • 376,812
  • 128
  • 561
  • 623
  • The compile-time in-lining is an implementation detail. Much more significant is the fact that in cases where code might legally use either, the behavior of a final static field which is loaded with a constant is indistinguishable from the behavior of a static instance field which is loaded with that same constant. The proper behavior of a static members of non-static inner class would be ambiguous, but for static final fields loaded with constants, both possible ways of resolving the ambiguity would yield the same result. – supercat Mar 18 '14 at 20:29
  • Why usage of `Integer` makes it NOT a compile-time constant? – Vinay Sharma Feb 06 '22 at 18:34
  • 1
    @supercat the “compile-time in-lining” is not an implementation detail. It’s [mandated by the specification](https://docs.oracle.com/javase/specs/jls/se17/html/jls-13.html#jls-13.1-110-C): “*A reference to a field that is a constant variable (§4.12.4) must be resolved at compile time to the value V denoted by the constant variable's initializer.*” The issue with non-constant `static` variables has been revised, in the meanwhile. Starting with JDK 16, you can use `static` variables and methods inside an inner class. – Holger May 04 '22 at 14:54
  • 1
    @VinaySharma because [the specification says so](https://docs.oracle.com/javase/specs/jls/se17/html/jls-15.html#jls-15.29). Only primitive values and strings can be compile-time constants. – Holger May 04 '22 at 14:56
  • @Holger: Oops. To what extent does the Java specification impose requirements upon the byte code generated from a particular source? If a compiler were to e.g. treat a `static double foo=2.0;` within an inner class as a static member of an outer class, but then included `foo=2;` (the code for which I think would be less than eight bytes) to the initialization of that outer class, would that be an observable deviation from spec? – supercat May 04 '22 at 15:34
  • 1
    @supercat you don’t have to, as there are no technical problems in placing the `static` field inside the inner class. But the exact form of inner classes is indeed surprisingly vague in the JLS. Since inner and outer class are always generated together, there can be implementation specific details which would not work if both classes were produced by different compilers (in fact, there were such differences in the past and still might be). – Holger May 04 '22 at 17:34
  • @Holger: I think that sort of thing is what I meant when I said that the distinction between static and run-time initialization was an implementation detail. From a run-time perspective, there would be no way to distinguish the behaviors, but if e.g. one were to inspect a class file that contained a static final field initialized to 2.0, I don't think there's any guarantee that the constant would be stored anywhere in the class file if the field isn't public, and perhaps not even then. – supercat May 05 '22 at 15:41
  • 1
    @supercat that’s a different thing. In your previous comment, you posted an example without `final`. But when the field fulfills the formal criteria of a compile-time constant, its format *is* mandated. There are two implications. First, the JVM itself will initialize the field, before any class initializer code is run. Second, when compiling new code against that class and there’s an access to the field, the compiler must read the constant value from the class file and use it. The specification mandates that this (source code) access does not lead to class initialization (no runtime access). – Holger May 05 '22 at 16:14