Why does Java prohibit static fields in inner classes?

Viewed 32881
class OuterClass {
 class InnerClass {
  static int i = 100; // compile error
  static void f() { } // compile error
 }
} 

Although it's not possible to access the static field with OuterClass.InnerClass.i, if I want to record something that should be static, e.g. the number of InnerClass objects created, it would be helpful to make that field static. So why does Java prohibit static fields/methods in inner classes?

EDIT: I know how to make the compiler happy with static nested class (or static inner class), but what I want to know is why java forbids static fields/methods inside inner classes (or ordinary inner class) from both the language design and implementation aspects, if someone knows more about it.

12 Answers

what I want to know is why java forbids static fields/methods inside inner classes

Because those inner classes are "instance" inner classes. That is, they are like an instance attribute of the enclosing object.

Since they're "instance" classes, it doesn't make any sense to allow static features, for static is meant to work without an instance in the first place.

It's like you try to create a static/instance attribute at the same time.

Take the following example:

class Employee {
    public String name;
}

If you create two instances of employee:

Employee a = new Employee(); 
a.name = "Oscar";

Employee b = new Employee();
b.name = "jcyang";

It is clear why each one has its own value for the property name, right?

The same happens with the inner class; each inner class instance is independent of the other inner class instance.

So if you attempt to create a counter class attribute, there is no way to share that value across two different instances.

class Employee {
    public String name;
    class InnerData {
        static count; // ??? count of which ? a or b? 
     }
}

When you create the instance a and b in the example above, what would be a correct value for the static variable count? It is not possible to determine it, because the existence of the InnerData class depends completely on each of the enclosing objects.

That's why, when the class is declared as static, it doesn't need anymore a living instance, to live itself. Now that there is no dependency, you may freely declare a static attribute.

I think this sounds reiterative but if you think about the differences between instance vs. class attributes, it will make sense.

The idea behind inner classes is to operate in the context of the enclosing instance. Somehow, allowing static variables and methods contradicts this motivation?

8.1.2 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).

InnerClass cannot have static members because it belongs to an instance (of OuterClass). If you declare InnerClass as static to detach it from the instance, your code will compile.

class OuterClass {
    static class InnerClass {
        static int i = 100; // no compile error
        static void f() { } // no compile error
    }
}

BTW: You'll still be able to create instances of InnerClass. static in this context allows that to happen without an enclosing instance of OuterClass.

From Java 16 onwards, this is no longer the case. Quoting from JEP 395 (on finalizing records):

Relax the longstanding restriction whereby an inner class cannot declare a member that is explicitly or implicitly static. This will become legal and, in particular, will allow an inner class to declare a member that is a record class.

Indeed, the following code can be compiled with Java 16 (tried with 16.ea.27):

public class NestingClasses {

    public class NestedClass {

        static final String CONSTANT = new String(
                "DOES NOT COMPILE WITH JAVA <16");

        static String constant() {
            return CONSTANT;
        }

    }

}

Because it would cause ambiguity in the meaning of "static".

Inner classes cannot declare static members other than compile-time constants. There would be an ambiguity about the meaning of “static.” Does it mean there is only one instance in the virtual machine? Or only one instance per outer object? The language designers decided not to tackle this issue.

Taken from "Core Java SE 9 for the Impatient" by Cay S. Horstmann. Pg 90 Chapter 2.6.3

In the Java language designers' own words:

Since nested classes were first introduced to Java, nested class declarations that are inner have been prohibited from declaring static members... It simplifies the language's task of resolving and validating references to in-scope variables, methods, etc.

There was never any particularly grand conceptual or philosophical reason to prohibit this.

Simplifying things for the language was deemed an insufficient reason to continue to maintain this restriction. Along with the introduction of records in Java 16, they made the decision to relax the restriction.

Class Inner will be initialize if a static field declared by Inner is used and the field is not a constant variable.

class Outer{

    class Inner{

        static Inner obj = new Inner();
    }

    public static void main(String[] args){

        Inner i = Inner.obj; // It woulds violate the basic rule: without existing Outer class Object there is no chance of existing Inner class Object.
   }
}
Related