91
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.

Micha Wiedenmann
  • 19,979
  • 21
  • 92
  • 137
Jichao
  • 40,341
  • 47
  • 125
  • 198

12 Answers12

60

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.

Nisse Engström
  • 4,738
  • 23
  • 27
  • 42
OscarRyz
  • 196,001
  • 113
  • 385
  • 569
  • 4
    I'll buy your explanation for static *properties* of the inner class, but as @skaffman points out in a comment to my answer, what about static *methods*? It seems as though methods should be allowed without mandating that they be detached from any instance. Indeed, in java, you can call static methods on instances (although it's considered bad style). BTW: I asked a colleague to attempt to compile the OP's code as C# and it *does* compile. So C# apparently allows this which demonstrates that what the OP wants to do doesn't violate some fundamental OO principle. – Asaph Dec 23 '09 at 18:19
  • 2
    Happens exactly the same with the methods. The point here is not the *attributes* or the *methods* being statis or not, but the fact the inner class it self being **instance** "stuff". I mean, the problem here is that an instance of such inner class doesn't exists until the outer class is created. Hence what method would be dispatched then if there is nothing. You would hit air only because you'll need an instance in first place. – OscarRyz Dec 23 '09 at 18:29
  • 1
    About C# ... well. It is not OO valid just because C# allows it, I don't mean it is wrong, but C# includes several paradigms to make the development easier even at cost of consistency ( you have to learn new things with each .NET release ) and it allows this and other kinds of things among others. I think that's a good thing. If the community feel an extra feature is cool enough C# may have it in the future. – OscarRyz Dec 23 '09 at 18:32
  • 2
    @OscarRyz Why do you need instances of the inner class to use its *static* methods/fields? And an example of [useful] static method in inner class *is* private helper method. – Leonid Semyonov Dec 04 '14 at 09:55
  • 1
    With use of `final` , static fields is allowed in inner class in java. How do you explain this scenario ? – Number945 Jul 09 '18 at 02:10
  • As explained in the answer when you use `static int x;` inside inner class and declare two instances of outer class then how can you say what is the correct value of x? Since x is static it should be same irrespective of instances. Now compare that to `static final int x=5;` which is a static compile time constant and can't be changed and thus remain same. – Yug Singh Oct 02 '18 at 11:10
  • Hence it is because the inner is always (by the Java implementation) linked to an instance of the enclosing class; so that class is pertinent to (i.e. a member of) this last one, and as a non-static member of the enclosing class, for every instance of it, the inner and all its members are allocated in the instance memory, becoming dependant from the very instance life – Bento Sep 05 '19 at 20:54
36

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

Community
  • 1
  • 1
Gregory Pakosz
  • 69,011
  • 20
  • 139
  • 164
  • 21
    maybe it's just **decided** like that – Gregory Pakosz Dec 23 '09 at 16:16
  • 3
    you can't *instantiate* the non-static inner without a parent reference, but you can still *initialize* it. – skaffman Dec 23 '09 at 16:35
  • 1
    If the ClassLoaders keep a cache that says "Class X has been initialized", then their logic cannot be used for initializing multiple instances of Class [objects representing] X (which is what is needed when Class objects must be instantiated as inner classes inside several distinct objects). – Erwin Smout Sep 22 '15 at 20:01
  • @skaffman It still doesn't make sense. The static properties of the inner class will only be initialized once, so what would be the problem? Right now, I have a static hashmap and I have about 4 methods that manipulate only this map, making it more ideal to group everything in an inner class. However, the static hashmap would now have to live outside, and possibly other things related, which is just plain stupid. What would be the problem with having static properties initialized? – mjs Apr 01 '16 at 11:05
  • 4
    Since Java 16, since is no longer the case - see [this answer](https://stackoverflow.com/a/65147661/2525313). – Nicolai Parlog Dec 04 '20 at 17:03
34

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.

Asaph
  • 159,146
  • 25
  • 197
  • 199
  • 6
    `InnerClass` does *not* belong to `OuterClass`, *instances* of it do. The two classes themselves have no such relationship. The question of why you can't have static methods in `InnerClass` still stands. – skaffman Dec 23 '09 at 16:43
22

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;
        }

    }

}
Nicolai Parlog
  • 47,972
  • 24
  • 125
  • 255
  • 3
    More information can be found in [JDK-8254321](https://bugs.openjdk.java.net/browse/JDK-8254321). – Marcono1234 Mar 30 '21 at 00:10
  • Why `CONSTANT = **new** String(...)` instead of `CONSTANT = "..."`? – Lii Oct 20 '21 at 07:23
  • 5
    @Lii Because Java has long allowed static constant variables like string literals in non-static nested classes. With `CONSTANT = "..."`, you get no compile error on Java < 15. – Nicolai Parlog Oct 27 '21 at 12:43
11

Actually, you can declare static fields if they are constants and are written in compile time.

class OuterClass {
    void foo() {
        class Inner{
            static final int a = 5; // fine
            static final String s = "hello"; // fine
            static final Object o = new Object(); // compile error, because cannot be written during compilation
        }
    }
}
doughting
  • 382
  • 4
  • 10
9
  1. class Initialization sequence is a critical reason.

As inner classes are dependent on the instance of enclosing/Outer class, so Outer class need to be initialized before the initialization of the Inner class.
This is JLS says about class Initialization. The point we need is, class T will be initialize if

  • A static field declared by T is used and the field is not a constant variable.

So if inner class have an static field accessing that will cause initializing the inner class, but that will not ensure that the enclosing class is initialized.

  1. It would violate some basic rules. you can skip to the last section (to two cases) to avoid noob stuff

One thing about static nested class, when some nested class is static it will behave just like a normal class in every way and it is associated with the Outer class.

But the concept of Inner class/ non-static nested class is it will be associated with the instance of outer/enclosing class. Please note associated with instance not the class. Now associating with instance clearly means that (from the concept of instance variable) it will exist inside a instance and will be different among instances.

Now, when we make something static we expect it will be initialized when the class is being loaded and should be shared among all instances. But for being non-static, even inner classes themselves (you can definitely forget about instance of inner class for now) are not shared with all instance of the outer/enclosing class (at least conceptually), then how can we expect that some variable of inner class will be shared among all the instance of the inner class.

So if Java allow us to use static variable inside not static nested class. there will be two cases.

  • If it is shared with all the instance of inner class it will violate the concept of context of instance(instance variable). It's a NO then.
  • If it is not shared with all instance it will violate the the concept of being static. Again NO.
Saif
  • 6,804
  • 8
  • 40
  • 61
5

Here is the motivation that I find best suitable for this "limit": You can implement the behavior of a static field of an inner class as an instance field of the outer object; So you do not need static fields/methods. The behaviour I mean is that all inner class instances of some object share a field(or method).

So, suppose you wanted to count all the inner class instances, you would do:

public class Outer{
    int nofInner; //this will count the inner class 
                  //instances of this (Outer)object
                  //(you know, they "belong" to an object)
    static int totalNofInner; //this will count all 
                              //inner class instances of all Outer objects
    class Inner {
        public Inner(){
            nofInner++;
            totalNofInner++;
        }
    }
}
Community
  • 1
  • 1
ianos
  • 143
  • 1
  • 8
  • 2
    But the question is that what is the reason for allowing static fields when they are declared `final` then? – Solace Jun 09 '16 at 15:42
  • if you look at [http://stackoverflow.com/a/1954119/1532220] (OscarRyzs answer above): His motivation is that a value can not be associated to the variable. Of course, if the variable is final, you can quite easily know what value to assign(you must know). – ianos Jun 10 '16 at 18:56
2

In simple words, non-static inner classes are instance variable for outer class, and they are created only when an outer class is created and an outer class object is created at run-time while static variables are created at class loading time. So non-static inner class is runtime thing that's why static not the part of a non-static inner class.

NOTE: treat inner classes always like a variable for an outer class they may be static or non-static like any other variables.

Mannu
  • 35
  • 3
0

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

0

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.

Michael
  • 41,989
  • 11
  • 82
  • 128
0

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.
   }
}
Lucas de Lima
  • 51
  • 1
  • 3
-1

I guess it's for consistency. While there doesn't seem to be any technical limitation for it, you wouldn't be able to access static members of the internal class from the outside, i.e. OuterClass.InnerClass.i because the middle step is not static.

Chochos
  • 5,155
  • 22
  • 27