21

Possible Duplicate:
Why does Java prohibit static fields in inner classes?

I was going through the specification and got that it is not possible to have the static member in the inner class which is not final compile time constant .

class HasStatic {
    static int j = 100;
}
class myInnerClassTest {
    class Inner extends HasStatic {
        static final int x = 3;  // OK: compile-time constant
        static int y = 4;  // Compile-time error: an inner class
    }
    static class NestedButNotInner{
        static int z = 5;    // OK: not an inner class
    }
    interface NeverInner {}   // Interfaces are never inner
}

Whereas I got from the Why can we have static final members but cant have static method in an inner class? that it can inherit the static member from its owner class. But why it shouldn't? What OOP's principal it hurts?

Community
  • 1
  • 1
Virendra
  • 387
  • 1
  • 7
  • 15
  • Inner classes cannot have a static initialisation blocks (exactly why I don't know). Primitives known at compile time can have a default value without a static initialisation block. – Peter Lawrey Oct 04 '12 at 12:27
  • 3
    Non-static nested classes only really exist within an instance of the outer class. As a result, there's no real "static" context in such a class, so static members (other than constants) don't make sense. – Wormbo Oct 04 '12 at 12:42
  • @Wormbo: Why 'constants' in your '(other than constants)' make sense? – NeoZoom.lua Apr 13 '19 at 05:27
  • @LiSeeLeiCow-Q__Q A (compile-time) constant value will just be inlined by the compiler whenever it is used anywhere. It always has the same meaning, regardless of context. See the answer by Denys Séguret for details. – Wormbo Apr 13 '19 at 23:08
  • @Wormbo: So since it's done in compile-time, it can be static even though the inner class is tied to an instance? Another question is what do you mean '"static" context' in your first comment? Can I say that "static" means anything done in compile time? – NeoZoom.lua Apr 14 '19 at 03:51
  • @Wormbo: From the answer you mentioned it seems like one should just follow the JSL but it can't be asked about why, correct? – NeoZoom.lua Apr 14 '19 at 04:01

5 Answers5

12

Your class myInnerClassTest isn't declared as static. So what would that exactly mean for it to have a static field ?

Would it be

  • the same for all instances whatever the enclosing instance ?
  • the same for all instances of this inner class having the same enclosing instance ?

At first sight most programmers would probably think it's the first case, while the encapsulation logic of the (non static) inner class should probably lead to the second choice. Either case (or both with different modifiers) would need a new definition of static which probably wasn't seen as necessary. And in either case programmers would be confused about the exact meaning.

From the specification :

An inner class is a nested class that is not explicitly or implicitly declared static.

Inner classes include local (§14.3), anonymous (§15.9.5) and non-static member classes (§8.5).

Inner classes may not declare static initializers (§8.7) or member interfaces, or a compile-time error occurs.

Inner classes may not declare static members, unless they are constant variables (§4.12.4), or a compile-time error occurs.

Denys Séguret
  • 372,613
  • 87
  • 782
  • 758
  • 1
    I don't get this point: "Would it be the same for all instances whatever the enclosing class" . There can be (and is) just one enclosing class... The statics in inner class could "share" the same area as enclosing class, but the visibility would be different. – Adam Dyga Oct 04 '12 at 12:38
  • 1
    @AdamDyga you instantiate an inner class with `outer.new Inner();` – Raffaele Oct 04 '12 at 12:40
  • @Raffaele Inner has always exactly one and the same enclosing class. I still don't see any problem with static in inner class – Adam Dyga Oct 04 '12 at 12:44
  • @wulfgar.pro Inner classes, put simply, are nothing else than normal classes with implicit reference to outer class. Why should it prevent them from having a static variable shared by inner class instances? – Adam Dyga Oct 04 '12 at 12:59
  • @AdamDyga - Because, as dystroy has pointed out, it changes the meaning of static - if the inner class is a _member_ of the outer class, shouldn't it's static member also be a static member of the outer class? – wulfgarpro Oct 04 '12 at 13:01
  • @wulfgar.pro Yes, it could be under the hood. But it's visibility would be different (eg. private static would be only visible to Inner class) – Adam Dyga Oct 04 '12 at 13:10
  • @wulfgar.pro Let have a Example of Department (as a outer class ) and Person(as a inner class).Person has a static field " deptAssociated " so for a particular instance of Department(say ManufactureDept) , inner class person would have static field assigned "manuFactureDept" . So for this ex , i would need to have static for inner which couldn't be good to be static at outer class . As Dept's static is common for all Dept. But i only need to have for a particular instance of Dept , inner class Person would have static data – Virendra 3 mins ago – Virendra Oct 04 '12 at 13:29
  • @dystroy after your edit I would opt for "the same for all instances whatever the enclosing instance" . Wouldn't it work? It wouldn't need a new definition of static – Adam Dyga Oct 04 '12 at 14:38
  • 4
    The problem is that instances of inner classes of two different enclosing instances should be considered as in different worlds, a little like instances of the "same" class in two different jvm are different (see the comment of Wormbo at the top for a different way to say the same thing). You make a non static inner class because you want to encapsulate and dedicate your class to an enclosing instance, so they shouldn't share variables. Of course your choice would make sense too, that's why I think this would be confusing. – Denys Séguret Oct 04 '12 at 14:42
  • So after this long discussion it basically seems that it's been decided this way just to avoid confusion and keep things simple. +1 for the comment – Adam Dyga Oct 04 '12 at 14:52
  • 2
    @AdamDyga “*I would opt for ‘the same for all instances whatever the enclosing instance’ . Wouldn't it work?*” It does work. Starting with JDK 16. – Holger May 04 '22 at 14:44
11

According to JLS: -

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

Any local variable, formal method parameter or exception handler parameter used but not declared in an inner class must be declared final. Any local variable, used but not declared in an inner class must be definitely assigned (§16) before the body of the inner class.

Apart from these two things, which I found important.. There are many more that you can get it from there.. There is a huge explanation about inner classes, anonymous inner classes, and nested classes..

UPDATED EXPLANATION : -

Just think about it. Static block is executed during class initialization, and you cannot initialize a non-static inner class without having an instance of the enclosing class, that's the reason.

Inner classes are associated with the instance of the enclosing class.. They are like other instance attributes of the enclosing class.. Now, it doesn't make sense to embed a static field in a non-static context.. However, if you declare them as Compile Time Constants they would be allowed.

NOTE: - static final Object = null is not compile time constants.. So, you can't have them inside your inner class

On the other hand, had your inner class been static, that is actually a nested class, then you can declare your field static, as they will still be associated with the class, so you can access them even before enclosing class in instantiated..

I hope that makes sense..

UPDATE 2 : -

public class A {
   class B {
        static int x = 0;
   }
}

In the above code, static variable x will be common for every instance of class B.. Also, each instance of class A, will have it's own copy of class B (Since JVM will have to load class B every time an instance of A is created)..

So, static variable x could not have been shared between every instance of class A, unless it is a compile time constants.. (To make it more straight foreward: - You can do - B.x if you see B as outer class.. But class B is itself different for each instance of class A. So, B.x will be different for each instance of class A.. So, static variable x is not actually shared between different instances of class A.. Doesn't make sense for a static variable.)

I hope now, that makes sense..

Rohit Jain
  • 209,639
  • 45
  • 409
  • 525
  • 1
    Your answer only shows what the specificaiton says. But the question is why such restriction was actually put in the specs? There must be a reason. – Adam Dyga Oct 04 '12 at 12:48
  • @AdamDyga.. Now I have added an explanation.. I think that would be clear now.. :) – Rohit Jain Oct 04 '12 at 12:59
  • "Static block is executed during class initialization, and you cannot initialize a non-static inner class without having an instance of the enclosing class, that's the reason. " This is still not convincing me. There must be a point where Outer$Inner.class (the file) is loaded by JVM (probably right after Outer.class file). And this is the place when the static initialization could be done - right after static initialization of Outer. Static initialization of Outer also occurs when there are no instances created (yet). – Adam Dyga Oct 04 '12 at 13:06
  • @AdamDyga.. See UPDATE 2.. I think that will explain better.. – Rohit Jain Oct 04 '12 at 13:10
  • @RohitJain each instance of class A has copy of class B? What do you mean by that? A copy of class body in the sense that the class loader creates a copy of Class every time? I don't get it – Adam Dyga Oct 04 '12 at 13:17
  • @AdamDyga Exactly.. Since inner class B is an instance field of class A.. And you know that `instance field` are different for each instance.. So, will be with instance inner class.. They will be loaded for each instance, every time.. I think now you got it.. – Rohit Jain Oct 04 '12 at 13:21
  • @AdamDyga.. Where as if you take `static inner class B`.. That will be common for every instance A.. And in cycle, `static variable x` will be common for every instance of class B.. So, `B.x` will be common for every instance of class A.. That makes sense now for static inner class right?? – Rohit Jain Oct 04 '12 at 13:23
  • @RohitJain Just to be sure that we are on the same page: a copy of CLASS is something different from a copy of class INSTANCE. Is this what you mean? – Adam Dyga Oct 04 '12 at 13:36
  • @AdamDyga. Yes.. Thats true.. Not that you would have different instance of that class.. You would in fact have different class in all.. – Rohit Jain Oct 04 '12 at 13:39
  • @AdamDyga.. So, for every instance of class A created, JVM will load the inner class B every time... – Rohit Jain Oct 04 '12 at 13:45
  • @AdamDyga.. If the answers clears your doubt, you can accept it as your answer.. – Rohit Jain Oct 04 '12 at 13:55
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/17559/discussion-between-adam-dyga-and-rohit-jain) – Adam Dyga Oct 04 '12 at 14:06
  • Good answer..especially the 2nd update..The jvm will do inner class loading everytime an instance of outer class is created – Kumar Abhinav Jul 21 '14 at 12:59
1

All the restrictions are documented in JLS #8.1.3. Inner Classes and Enclosing Instances

Because static declarations is associated with Class if you declare it inside inner class it will get associated with instance rather than class.

innerclass

Non static inner classes are members of Object. And for members initialization only happens when instance of object is created. If static variables were allowed then initialization would have happened before creation of instance.

That is why there are separate non-static and static inner classes.

You always need outer class instance to access inner class Outer.Inner only exception is static inner class for which there are no constraints which are applicable to non-static inner classes.

static class Inner {
    static final int x = 3; // OK: compile-time constant
    static int y = 4;// OK
    static class NestedButNotInner {// OK

    }

    interface NeverInner {// OK
    };
}

However constants are permitted and it is documented in JLS

Community
  • 1
  • 1
Amit Deshpande
  • 19,001
  • 4
  • 46
  • 72
  • Inner class, all in all, has also it's own class (Outer$Inner). I still don't see why the instances can't have and share a static field. – Adam Dyga Oct 04 '12 at 12:53
  • @AdamDyga Though it has a class it is a non static member and for non static members initialization occurs only when Class instance is created. Declaration of static variables would have created initialization before. That is why there are two separate inner class static and non-static. – Amit Deshpande Oct 04 '12 at 13:25
  • "Declaration of static variables would have created initialization before." - doesn't the same happen with normal classes? Static initialization takes place before any instance is created. What's more you don't even have to create any instance, it's enough if you just "touch" the class (eg. call a static method). – Adam Dyga Oct 04 '12 at 13:56
  • Yes that the point as you have explained. Now if you `touch` non-static inner class initialization will happen which should not. You should treat inner class as Object instance variable and then imagine the same now you are violating the rule. – Amit Deshpande Oct 04 '12 at 14:01
  • "Now if you touch non-static inner class initialization will happen which should not." But why not? :) I can invoke static initialization of normal class without creating an instance, why can't it be done with inner classes? Wouldn't it be enough if we defined that static initialization of inner class always takes place right after static initialization of outer class? I don't want to troll here and I know there must be some good reason Java designers did it this way, but I just didn't see any good justification (so far). – Adam Dyga Oct 04 '12 at 14:15
0

Because the inner class in intimately associated to the top level class you must have an instance of the outer class to create an inner via

Outer o = new Outer();
Inner i = o.new Inner();

This is therefore associated with an instance and not a class.

Denys Séguret
  • 372,613
  • 87
  • 782
  • 758
Dave Whittingham
  • 338
  • 3
  • 11
  • So why can you still use Inner.class and do with it anything you can do with Outer.class ? – Adam Dyga Oct 04 '12 at 13:01
  • You are free to access the ".class" static once the inner class has been instantiated. The whole point of the inner class defined above is that its attached to the outer class. Making the inner class static makes it a top-level class and it will allow you to create a non-final static member – Dave Whittingham Oct 04 '12 at 14:43
  • You may get some more info from [link](http://stackoverflow.com/questions/1953530/why-does-java-prohibit-static-fields-in-inner-classes) – Dave Whittingham Oct 04 '12 at 14:44
-1

As you know, inner class can inherit static member from its owner class.

class HasStatic {
    static int j = 100;
}
class myInnerClassTest {
    class Inner extends HasStatic {
    }      
    public static void main(String[] args){
        System.out.println(Inner.j);
    }
}

And it prints "100".

cameron
  • 2,976
  • 3
  • 23
  • 35