Why can't inner classes have static (non-final) fields and methods?
This question has been posted before but the posted answers were: it's a design decision or because inner classes happen in the context of the outer class and cannot declare static methods.
Yet these answers do not clarify my question. What would be the consequences of allowing static fields and methods on inner classes? My guess is that both restrictions are connected. Since static methods would require access to other static methods and non-final static variables of the inner class or even from the outer class (to be able to change internal states), this would lead a inner class to behave like a static one. The JVM could limit access from static methods in inner classes to static methods and data inside the inner class, though. Yet this raises the question: why can't we declare static non-final variables inside inner classes?
Is this design or there are problems?
Kind regards
Declaring static variables in non-static inner class seems contradictory to intend of creating inner non-static class.
If you declaring some variables and methods static you do it when it make sense to access them without creating instance of class, if you declaring inner class non-static its instance type, so intent is to access it via its instance not staticly. If you declare inner class static, therefore separate it from outer class, you can declare variables and methods static.
You asked what would be consequences if java allowed you to declare static methods/fields in inner non-static classes. Well probably there would be none. But it just doesn't make sense, therefore it's a design choice.
To answer why... ->
Inner class object is strongly associated with Outer class object that means without existing Outer class object there is no chance of existing Inner class Object, so defining any static variable/method inside Inner class would not fulfill this requirement
In case of static nested class -> Inner class object is NOT strongly associated with Outer class object
Related
I know that an inner class has access to everything in the outer class (because it's a member of that class) but what about the other way around?
Does the outer class have access to private variables and methods within an inner class?
I've seen articles mentioning that inner classes should be private so that they are accessible only to the outer class. What does that do to the accessibility of that inner class?
What is best practices in dealing with access levels when it comes to your inner classes? I'm assuming more encapsulation the better but does that come at the expense of accessibility?
This topic is covered in some detail by Effective Java (2nd edition) Item 22: "Favor static member classes over nonstatic".
A brief summary:
An inner class should not have access to an outer class instance, unless that access is required, i.e. inner classes should be static by default. To get technical, Effective Java calls these static member classes, as opposed to inner classes, and uses the term nested class to encompass both the static and nonstatic versions.
An outer class always has access to the members of its inner classes, even when those members are private. In this way, an inner class can expose itself only to its outer class.
"An inner class should exist only to serve its outer class."
Personally, I'm inclined to implement an inner class whenever doing so allows the inner class's constructors to be private, i.e. when a class can only be instantiated from one other (outer) class. Any additional encapsulation, such as making the entire inner class private, is desirable; but public inner classes are perfectly acceptable. There are many examples in Java, such as AbstractMap.SimpleEntry.
If I declare a variable as private in an inner class, the variable is visible to the outer class. I am unable to understand the logic here. Shouldn't it ideally be only accessible within an inner class?
I think the answer is subjective as the question basically seems to be asking why Sun/Oracle's language designers decided to allow a certain behavior.
That said, here is an attempt at an answer...
First some terminology, a class declared within a class is a nested class. An inner class is a non-static nested class which must reside within an instance of the outer class. So the inner class is a part of the outer class and in that sense, all members of the inner class are to an extent members of the outer class.
http://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.
Another thought is that the valid use cases for an inner class preclude the necessity to allow the inner class to hide members from the outer class. That is, there is no notion that the outer class would not be coupled to the inner class.
Why allow private at all then? Because private members can still be hidden from other classes which may gain access to an instance of an inner class.
The Java Tutorial says that the static nested classes are accessed by using the name of the enclosing class like new EnclosingClassNameHere.StaticNestedClassNameHere()
Why would i want to create an instance of a static class at all? Can somebody please explain?
"static" in this case can be misleading. What it really means is that the class can exist independently. Non-static inner classes can't exist without an instance of the enclosing class.
IMO, when you start using an inner class outside the class that it's in, you need to consider moving it and making it its own top level class. There are very few cases where the relationship between the classes is so tightly coupled that you need to keep it as an inner class.
In your code example:
OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass();
You're creating a stand-alone instance of StaticNestedClass.
If it wasn't static, you couldn't do that. You could only create instances of StaticNestedClass() from an instance of OuterClass.
If you moved it to its own .java file, you could treat it nearly identically:
StaticNestedClass notNestedAnymore = new StaticNestedClass();
As to your real question: Why would you want to create an instance of it? For the same reason that you create instances of any class - it does some piece of work that you need.
There is nothing confusing with this code. Static nested class is just a way to introduce yet another namespace.
By creating a static nested class you express very strong relationship between outer and inner class. Typically nested class is a helper or a part of the outer class. For instance when you create a Tree class, Node class is a good candidate for a nested static class. The Tree.Node clearly explains the purpose of the Node class.
In fact, static keyword usage is consistent with static fields. In both cases you can access static entity without an instance of enclosing class. When it comes to static classes it basically means: "I can create an instance of this static nested class without having an instance of outer class". By default (when static keyword is not used) the nested class becomes inner class. In this case you cannot simply write:
new OuterClass.StaticNestedClass();
Instead you are required to pass OuterClass instance with a bit obscure syntax:
OuterClass outerClassInstance = new OuterClass();
outerClassInstance.new InnerClass();
Fortunately when new InnerClass() is executed inside an OuterClass body, this is implictly used as enclosing instance.
In java inner classes have an implicit reference to an instance of the outer class. This way you can access members of the outer class directly, which is usefull in annonymous classes used for callbacks.
class A{
private int a = 3;
class Inner{
Inner(){
System.out.println(a);//also A.this.a
}
}
static class StaticInner{
StaticInner(){
System.out.println(a);//FAILS
}
}
}
Declaring an inner class static simply removes this implicit reference and that is the only difference between static and non static inner classes.
Alright, I know it's the rule:
According to JLS: 8.1.3 Inner Classes and Enclosing Instances, inner
classes may not declare static initializers or member interfaces.
Inner classes may not declare static members, unless they are
compile-time constant fields.
According to 8.5.2 Static Member Type Declarations, "Member interfaces
are always implicitly static. It is permitted but not required for the
declaration of a member interface to explicitly list the static
modifier". They are always top-level, not inner.
I just wonder why. What may happen if we are allowed to declare interface within an inner class? Won't inner class become top-level class if I put it into another Class file?
Won't inner class become top-level class if I put it into another Class file?
No, it still is an inner class, which the filename indicates (IIRC it's OuterClass$InnerClass.class).
Inner classes have access to the outer class' attributes, i.e. they depend on their outer class' instance. With interfaces you couldn't do this. Think of a completely unrelated class that would have to be created by the corresponding outer class' instance. How would that be done if the outer class doesn't know who implements that interface?
What you can do is declare static interfaces in your outer class, thus merely using the outer as a namespace:
public class OuterClass {
public static interface InnerInterface { //protected and private would be fine too, depending on what makes sense
}
}
Edit: actually, I misread the question and since interfaces are static anyways, here's an updated code snippet:
public class OuterClass {
public static InnerClass { //static inner class making OuterClass just be a namespace
public interface InnerInnerInterface { //protected and private would be fine too, depending on what makes sense
}
}
}
As a workaround you could define an abstract inner inner class, with the drawback that you have to stick to the single inheritance constraint.
Think of it in terms of static vs. non-static context. A "top-level" class establishes a static context because it can be accessed without any enclosing instance. I.e. you can access top-level classes from a main method. The same applies to any static members of a top-level class. An inner class, however, neither exists in* nor establishes any static context. Therefore it can't have any static members, and it can only be accessed via an instance of its containing class, like constructors and other instance members. From a main method, you wouldn't be able to say Outer.Inner.SOME_FIELD because members of an inner class only have meaning with respect to the containing class.
*sort of
By definition a top level class and its inner class(es) are tightly coupled. Interfaces are a means of reducing coupling.
Inner classes are supposed to be implementation details of the top-level class and should therefore be invisible to the client. Any functionality you wish to access of an inner class should be done so through the top-level class, because conceptually speaking, that functionality should be visible only as functionality of the top-level class, so that the class designer can swap out or otherwise drastically change inner classes without breaking clients' builds.
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Why cant we have static method in an inner class?
Hi all, in java what exactly is the reason that we cannot declare static methods in [public] inner classes unless those inner classes are also declared static?
Amazingly top level classes can have any number of static methods without the need to have any special modifier
Non-static inner classes come into existence only in the context of an instance of the outer class.
So ... if you're going to have a static method, the whole inner class has to be static. Without doing that, you couldn't guarantee that the inner class existed when you attempted to call the static method.
The question to ask is -- if you do have a static method inside an inner class, how would you call that static method? The answer is, you can't.
An inner class is tied to instances of the outer class.
From Effective Java -- "Each instance of a nonstatic [nested] class is implicitly associated with an enclosing instance of its containing class".
This is the reason for making the "inner" class static. This actually a static nested class and its a full-blown class thats merely present in the enclosing class for packaging convenience.