javainner-classes

Java inner class with a static method


I really want to know why instead of going to the documentation. Suppose I have class like this:

public class OuterClass{
public static void main(String[] args)throws Exception{
    System.out.println(OuterClass.InnerClass.yearOfBorn);//works ok
    System.out.println(OuterClass.InnerClass.returnYearOfBorn());//not works
    System.out.println(OuterClass.InnerClass.returnYearOfBornAsPublic());//not works
}    
private final class InnerClass{
    private static final int yearOfBorn=13;
    private static int returnYearOfBorn(){
        return yearOfBorn;
    }        
    public static int returnYearOfBornAsPublic(){
        return yearOfBorn;
    }            
}
}

Both static method is throwing a error stating that

modifier 'static' is only allowed in constant variable declarations

I know that the docs states that this is described in the Java Language Specification Section §8.1.3

8.1.3 Inner Classes and Enclosing Instances

An inner class is a nested class that is not explicitly or implicitly declared static. Inner classes may not declare static initializers (§8.7) or member interfaces. Inner classes may not declare static members, unless they are compile-time constant fields (§15.28).

But my question what is the difference between calling a simple value or property vs calling a static method not matter if is public or private? Why calling a property is possible but not a method?


Solution

  • Non-static inner classes have something special.

    static inner classes do not have it. top-level classes don't have it. any inner interface or enum doesn't have it.

    That special thing is an invisible field.

    This invisible field is of type Outer, and it is final. It is initialized as first thing in its constructor, and, yes, EVERY constructor of a non-static inner class has a magic invisible parameter, of type Outer, to serve as this field.

    So, when you write:

    public class Outer {
        public class Inner {
        }
    }
    

    The compiler will compile this code as if you actually wrote:

    public class Outer {
        public static class Inner {
            private final Outer I_AM_MAGIC;
    
            public Inner(Outer outer) {
                this.I_AM_MAGIC = outer;
            }
        }
    }
    

    You can see this hidden magic using the javap decompilation tool; pass in -verbose and -private and you'll see these. The reason this magic exists is that you can invoke instance methods of your outer from within your inner, but.. on what instance are you calling these outer methods? On that hidden instance!

    Note that this exotic, seemingly weird code: someOuter.new Inner() is in fact legal java code. When calling new Inner() from within a non-static context in Outer, the this instance is passed as invisible parameter to that constructor, but if you're not there, the code simply does not compile at all... unless you use the outer.new Inner() syntax.

    The reason the compiler will stop you from adding static methods to Inner is that it was believed to lead to some confusion. Basically, the answer to your question is: "No good reason.. just... the spec says that a java compiler must not allow it, therefore, javac does not allow it".

    Note that in actual fact these non-static inner classes are the confusing thing. I strongly suggest you teach yourself to ALWAYS make your inner classes static unless you really know what you're doing. And even then, think twice. Then think twice again. Then maybe consider making a non-static inner class.