Why can't we have static method in a (non-static) inner class (pre-Java 16)?
Why can't we have static method in a non-static inner class?
public class Foo {
class Bar {
static void method() {} // Compiler error
}
}
If I make the inner class static it works. Why?
public class Foo {
static class Bar { // now static
static void method() {}
}
}
In Java 16+, both of these are valid.
Because an instance of an inner class is implicitly associated with an instance of its outer class, it cannot define any static methods itself. Since a static nested class cannot refer directly to instance variables or methods defined in its enclosing class, it can use them only through an object reference, it's safe to declare static methods in a static nested class.
There's not much point to allowing a static method in a non-static inner class; how would you access it? You cannot access (at least initially) a non-static inner class instance without going through an outer class instance. There is no purely static way to create a non-static inner class.
For an outer class Outer
, you can access a static method test()
like this:
Outer.test();
For a static inner class Inner
, you can access its static method innerTest()
like this:
Outer.Inner.innerTest();
However, if Inner
is not static, there is now no purely static way to reference the method innertest
. Non-static inner classes are tied to a specific instance of their outer class. A function is different from a constant, in that a reference to Outer.Inner.CONSTANT
is guaranteed to be unambiguous in a way that a function call Outer.Inner.staticFunction();
is not. Let's say you have Inner.staticFunction()
that calls getState()
, which is defined in Outer
. If you try to invoke that static function, you now have an ambiguous reference to the Inner class. That is, on which instance of the inner class do you invoke the static function? It matters. See, there is no truly static way to reference that static method, due to the implicit reference to the outer object.
Paul Bellora is correct that the language designers could have allowed this. They would then have to carefully disallow any access to the implicit reference to the outer class in static methods of the non-static inner class. At this point, what is the value to this being an inner class if you cannot reference the outer class, except statically? And if static access is fine, then why not declare the whole inner class static? If you simply make the inner class itself static, then you have no implicit reference to the outer class, and you no longer have this ambiguity.
If you actually need static methods on a non-static inner class, then you probably need to rethink your design.
I have a theory, which may or may not be correct.
First, you should know some things about how inner classes are implemented in Java. Suppose you've got this class:
class Outer {
private int foo = 0;
class Inner implements Runnable {
public void run(){ foo++; }
}
public Runnable newFooIncrementer(){ return new Inner(); }
}
When you compile it, the generated bytecode will look as if you wrote something like this:
class Outer {
private int foo = 0;
static class Inner implements Runnable {
private final Outer this$0;
public Inner(Outer outer){
this$0 = outer;
}
public void run(){ this$0.foo++; }
}
public Runnable newFooIncrementer(){ return new Inner(this); }
}
Now, if we did allow static methods in non-static inner classes, you might want to do something like this.
class Outer {
private int foo = 0;
class Inner {
public static void incrFoo(){ foo++; }
}
}
... which looks fairly reasonable, as the Inner
class seems to have one incarnation per Outer
instance. But as we saw above, the non-static inner classes really are just syntactic sugar for static "inner" classes, so the last example would be approximately equivalent to:
class Outer {
private int foo = 0;
static class Inner {
private final Outer this$0;
public Inner(Outer outer){
this$0 = outer;
}
public static void incrFoo(){ this$0.foo++; }
}
}
... which clearly won't work, since this$0
is non-static. This sort of explains why static methods aren't allowed (although you could make the argument that you could allow static methods as long as they didn't reference the enclosing object), and why you can't have non-final static fields (it would be counter-intuitive if instances of non-static inner classes from different objects shared "static state"). It also explains why final fields are allowed (as long as they don't reference the enclosing object).
The only reason is "not a must", so why bother to support it?
Syntactically,there is no reason to prohibit an inner class from having static members. Although an instance of Inner
is associated with an instance of Outer
, it's still possible to use Outer.Inner.myStatic
to refer a static member of Inner
if java decides to do so.
If you need to share something among all the instances of Inner
, you can just put them into Outer
as static members. This is not worse than you use static members in Inner
, where Outer
can still access any private member of Inner
anyway(does not improve encapsulation).
If you need to share something among all the instances of Inner
created by one outer
object,it makes more sense to put them into Outer
class as ordinary members.
I don't agree the opinion that "a static nested class is pretty much just a top level class". I think its better to really regard a static nested class/inner class as a part of the outer class, because they can access outer class's private members. And members of outer class are "members of inner class" as well. So there is no need to support static member in inner class. An ordinary/static member in outer class will suffice.