Why can't we have static method in a (non-static) inner class (pre-Java 16)?

73,924

Solution 1

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.

Solution 2

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.

Solution 3

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

Solution 4

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.

Solution 5

From: https://docs.oracle.com/javase/tutorial/java/javaOO/nested.html

As with instance methods and variables, an inner class is associated with an instance of its enclosing class and has direct access to that object's methods and fields. Also, because an inner class is associated with an instance, it cannot define any static members itself.

Oracle's explanation is superficial and handwavy. Since there's no technical or syntactic reason to preempt static members within an inner class (it's allowed in other languages such as C#) the Java designers' motivation was likely conceptual taste and/or a matter of technical convenience.

Here's my speculation:

Unlike top-level classes, inner classes are instance-dependent: an inner-class instance is associated with an instance of every one of its outer classes and has direct access to their members. This is the chief motivation for having them in Java. Expressed another way: an inner class is meant for instantiation in the context of an outer class instance. Without an outer class instance, an inner class ought not be any more usable than the other instance members of the outer class. Let's refer to this as the instance-dependent spirit of inner classes.

The very nature of static members (which are NOT object-oriented) clashes with the instance-dependent spirit of inner classes (which IS object-oriented) because you can reference/call a static member of an inner class without an outer class instance by using the qualified inner class name.

Static variables in particular may offend in yet another way: two instances of an inner class that are associated with different instances of the outer class would share static variables. Since variables are a component of state, the two inner class instances would, in effect, share state independently of the outer class instances they're associated with. It’s not that it’s unacceptable that static variables work this way (we accept them in Java as a sensible compromise to OOP purity), but there’s arguably a deeper offense to be had by allowing them in inner classes whose instances are already coupled with outer class instances by design. Forbidding static members within inner classes in favor of the instance-dependent spirit reaps the added bonus of preempting this deeper OOP offense.

On the other hand, no such offense is entailed by static constants, which do not meaningfully constitute state and so these are allowable. Why not forbid static constants for maximum consistency with the instance-dependent spirit? Perhaps because constants need not take up more memory than necessary (if they're forced to be non-static then they’re copied into every inner class instance which is potentially wasteful). Otherwise I can’t imagine the reason for the exception.

It may not be rock-solid reasoning but IMO it makes the most sense of Oracle's cursory remark on the matter.

Share:
73,924

Related videos on Youtube

Rahul Garg
Author by

Rahul Garg

Java Lover :-) and Flex Enthusiast

Updated on July 08, 2022

Comments

  • Rahul Garg
    Rahul Garg almost 2 years

    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.

    • ses
      ses about 10 years
      Because now Java is that old COBOL :)
    • intrepidis
      intrepidis over 7 years
      The bottom line is: because they haven't implemented it yet.
    • user207421
      user207421 over 6 years
      'Non-static inner' is a tautology.
    • Willie Z
      Willie Z about 6 years
      If you don't want to exposure your inner class to others and hope it contain static methods, you can put the modifiers both "private" and "static" on the inner class.
    • Erwin Bolwidt
      Erwin Bolwidt over 5 years
      An inner class is by definition not static. You can have a static nested/member class, and a non-static nested/member class. The latter is also known as an inner class. (Reference: section 8.1.3 of the JLS states "An inner class is a nested class that is not explicitly or implicitly declared static.")
    • DuncG
      DuncG about 3 years
      JDK16 fixes this problem, now you may declare static methods and field on inner classes.
    • maplemaple
      maplemaple almost 3 years
      see this, JDK 16 fixes this problem.
  • TL36
    TL36 over 14 years
    Benedikt, what do you mean when you say "static nested classes are only a means to grouping" ?
  • Lawrence Dol
    Lawrence Dol about 13 years
    But that's just a normal "attempt to access non-static variable from a static context" type error - no different from if a top level static method tries to access it's own class's instance variable.
  • Paul Bellora
    Paul Bellora over 11 years
    -1 I have to disagree with the angle you took here. Certainly we can refer an inner class type, for example Outer.Inner i = new Outer().new Inner(); Also, inner classes are allowed to declare static constants according to JLS §15.28.
  • Eddie
    Eddie over 11 years
    Yes, inner classes can declare static constants. That has nothing to do with static methods! While you can refer to a static method non-statically, this is discouraged. All code quality tools complain at that kind of reference and for good reason. And you missed my point. I never said there is no way to reference a static inner class. I said there is no STATIC way to reference the static method of an inner class of a non-static outer class. Thus, there is no PROPER way to reference it.
  • Paul Bellora
    Paul Bellora over 11 years
    "There's not much point to allowing a static method in a non-static inner class; how would you access it?" You would call Outer.Inner.staticMethod() just like you can access Outer.Inner.CONSTANT. "You cannot access ... a non-static inner class instance without going through an outer class instance." Why would you need an instance? You don't need an instance of Outer to call Outer.staticMethod(). I know this is nitpicky but my point is that it doesn't make sense to frame your answer this way. IMHO the language designers could've allowed it if they wished.
  • Eddie
    Eddie over 11 years
    The difference between Outer.Inner.CONSTANT and Outer.Inner.staticMethod() is that a reference to a constant has no chance of implicitly referencing the instance of Outer in which Inner was instantiated. All references to Outer.staticMethod() share the same exact state. All references to Outer.Inner.CONSTANT share the same exact state. However, references to Outer.Inner.staticMethod() are ambiguous: The "static" state is not truly static, due to the implicit reference to the outer class in each instance of Inner. There is not a truly unambiguous, static way to access it.
  • Eddie
    Eddie over 11 years
    I clarified my answer to explain my reasoning further. Note that the JLS doesn't let you declare static variables in a non-static inner class unless those variables are static final.
  • kzidane
    kzidane over 10 years
    I know an inner class is associated with an instance of its outer class and I know that it's kinda useless that we become able to declare static members within an inner class but I am still asking why not an inner class can declare static members?
  • Industrial-antidepressant
    Industrial-antidepressant over 10 years
    In C++ you can have, so this is a bug in the Java language.
  • Seth Nelson
    Seth Nelson over 10 years
    The word bug...I do not think that word means what you think it means.
  • supercat
    supercat about 10 years
    I think a more fundamental difficulty with allowing non-static inner classes to have non-constant static members is that programmers declaring such members might be intending to have them bound to instances of the outer class, or have them be truly static. In cases where a construct--if legal--could sensibly be specified as meaning either of two different things, and where both of those things can be expressed in other unambiguous ways, specifying that construct as being illegal is often better than specifying it as having either meaning.
  • Theodore Murdock
    Theodore Murdock almost 10 years
    @Eddie You can't refer to instance fields in a static method, so there is no conflict related to the inability to refer to the implicit instance field Outer.this. I do agree with the Java language designers that there is no reason to allow static methods or non-final static fields in inner classes, because everything in an inner class should be within the context of the enclosing class.
  • LoPoBo
    LoPoBo almost 9 years
    I like this anwser because it actually explains why it isn't technically possible, even though it could seem possible syntactically.
  • Vladimir Reshetnikov
    Vladimir Reshetnikov almost 9 years
    There is no such thing as a static inner class. An inner class is by definition non-static (JLS8, 8.1.3). What you meant was probably a static nested class.
  • Angad
    Angad almost 9 years
    A more appropriate phrase would be 'annoying as a mothertrucker'. Don't understand why Java doesn't allow for this. Sometimes, I want an inner class to use properties of the parent class, but keep static methods for better namespacing. Is there something inherently wrong with this? :(
  • Edward Falk
    Edward Falk over 8 years
    Exactly. I want to write a utility inner class. Some of its methods would benefit from access to the outer class, so I can't make it static, but some of its methods are just utility functions. Why can't I call A.B.sync(X) or even (from within A) B.sync(x)?
  • Edward Falk
    Edward Falk over 8 years
    @Eddie a static method is basically a function. The class (or classes) that wrap it are merely name spaces. If my inner class' static method doesn't attempt to access any members from the outer class, then I see no reason why this couldn't be done.
  • Edward Falk
    Edward Falk over 8 years
    @gustafc, I think that was an excellent explanation. But as Lawrence points out, it's only a failure because of the reference to foo, which isn't static. But what if I wanted to write public static double sinDeg(double theta) { ... } an an inner math utilities class?
  • kirelagin
    kirelagin over 7 years
    Unfortunately, I think that this “answer” is not even trying to answer the question (most of it is not even about non-static classes). On the other hand, it seems that the only real answer to this questions is “because the authors of Java want everyone to suffer”.
  • Bill the Lizard
    Bill the Lizard over 7 years
    @kirelagin Note that there are two questions being asked. I answered both of them, so "most of it is not even about non-static classes" is irrelevant.
  • intrepidis
    intrepidis over 7 years
    Inner classes are not a "must" either. However, as the language does provide inner classes, it should provide a complete and meaningful implementation of them.
  • Bill the Lizard
    Bill the Lizard almost 6 years
    @ErikE Yes. You can't declare a method static in a non-static inner class. If you make the inner class static it's allowed.
  • ErikE
    ErikE almost 6 years
    @BilltheLizard Ah, I caught it now. Was missing one keyword.
  • Marcono1234
    Marcono1234 about 3 years
    More information can be found in JDK-8254321.
  • maplemaple
    maplemaple almost 3 years
    But Inner class alows static final constant field
  • Holger
    Holger about 2 years
    @maplemaple in fact, starting with JDK 16, inner classes allow all kind of static members.
  • Holger
    Holger about 2 years
    @kirelagin they changed their mind. Or they want you to suffer in different ways…