I have an inner class (non-static) which is using a reference to an enclosing class in its initialization. Will the inner class keep a reference to the enclosing class now?
class Enclosing {
class Inner {
private final ABC innerField = outerField.computeSomething();
}
private final XYZ outerField = something();
}
UPDATE
I am very much aware that one can reference the outer class with Enclosing.this.
But, if the class doesn't use the reference, must the reference be there after compilation? Is it necessary even if the reference is only used in the initialization?
Where does it say that an inner class always holds a reference to the outer class?
A non-static nested class always holds a reference to the enclosing class. In your example, you can reference the enclosing class from Inner as Enclosing.this.
JLS 8.1.3 "Inner classes and Enclosing Instances":
"An instance i of a direct inner class C of a class O is associated with an instance of O, known as the immediately enclosing instance of i. The immediately enclosing instance of an object, if any, is determined when the object is created (§15.9.2)."
Yes. An inner class (or non-static nested class) is just like any other instance member of the outer class, and as such always needs a reference of the enclosing class.
Where does it say that an inner class always holds a reference to the outer class?
In the same place it defines the Outer.this syntax. The existence of this syntax is the existence of the reference. There is nothing to suggest that it is suppressed if not used.
There are two cases of nested-classes:
static nested-classes. The nested-class does not keep reference to the outer-class.
non-static nested-classes. The nested-class does keep a reference to the outer-class.
The case of a static nested-class that extends the outer-class is not as interesting as the
non-static nested-class extending the outer-class.
An important thing to remember is that non static nested classes are simply called inner classes.
Related
I have three classes
class WithInner {
class Inner {}
}
public class InheritInner extends WithInner.Inner
{ //constructor
InheritInner(WithInner wi) {
wi.super();
}
}
This example is taken from Eckel's Thinking in Java. I can't understand why we can't call wi = new WithInner(); instead of .super()? And while calling wi.super() we are calling Object's default constructor, aren't we?
Inner classes maintain a reference to an outer instance (the exception is static inner classes). In this case, a WithInner.Inner instance has a reference to the containing WithInner instance. This association is created when the inner class is instantiated.
You cannot create an instance of the inner class without a reference to the outer class. A class that extends such an inner class also has by implication such a reference, and needs to delegate to the inner class constructor in order to set up the association. The syntax for doing that is as shown in your example:
wi.super();
Here, super() essentially refers to the superclass constructor - that is, the WithInner.Inner constructor. The constructor takes no parameters formally, but it still needs a reference to the outer instance (of type WithInner). The line as a whole essentially means "call the superclass constructor, and associate with the wi instance".
Compare to the syntax for instantiation of an inner class with explicit association:
wi.new WithInner.Inner()
Yes, that's also valid syntax. It's not commonly seen in the wild, though (because inner class instances are normally only created from within the outer class anyway, and in that case the association is implicit - there's no need in that case for this syntax, which provides the association explicitly).
With specific reference to your question:
I can't understand why we can't call wi = new WithInner(); instead of .super()?
This would not associate the created WithInner instance with the inner class instance. You'd get a compile-time error because your InheritInner constructor wouldn't any longer be explicitly calling the synthesized superclass constructor, and it can't be called implicitly because it needs the outer instance reference for association. It's probably easiest to think of the outer instance reference as a hidden parameter to the inner class constructor (indeed, that's how it's implemented under the hood).
And while calling wi.super() we are calling Object's default constructor, aren't we?
No, you're calling the WithInner.Inner constructor, which has a "hidden" parameter for the outer instance reference; wi is essentially passed to the WithInner.Inner constructor as a hidden parameter value.
class OuterClass {
static int j=99;
static class InnerClass {
public void doSomething() {
while(true)
OuterClass.j= 100;
}
}
}
}
Using the above code, is there any issue with garbage collection when the OuterClass needs to garbage collect but lets say doSomething is referencing a static variable will it be an issue ? What i'm concerned with is that the inner class has a reference to the outer class by accessing the variable j and im wondering if that will affect the OuterClass being GC.
Although you've named it InnerClass, it is not an inner class. It is simply a static nested class.
An instance of such a class has no reference to any instance of the enclosing class. What's more, you're referencing a static field of the enclosing class. There is absolutely no reference to any instance of OuterClass.
Nothing in your InnerClass can prevent an instance of the type OuterClass from being garbage collected.
Did I misunderstand your question? Are you asking about classes being garbage collected?
Classes aren't affected by GC, objects are. If you create an object of type InnerClass, GC will not touch anything referred to by it. However, because you are only referencing a static variable, you are not referencing any objects of type OuterClass (in that code fragment anyway). Thus, GC is free to remove any unneeded objects of type OuterClass without affecting, in any way, the functioning of objects of type InnerClass.
Note that if all you're doing is referring to a static variable in OuterClass from your InnerClass, you should probably not define InnerClass as a nested class.
Since the j field is static, it exists beyond the scope of a single instance of OuterClass. The fact that InnerClass is static decouples it from any instance of OuterClass.
As with class methods and variables, a static nested class is
associated with its outer class. And like static class methods, 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.
Note: A static nested class interacts with the instance members of its
outer class (and other classes) just like any other top-level class.
In effect, a static nested class is behaviorally a top-level class
that has been nested in another top-level class for packaging
convenience.
Nested classes explained in the Java tutorial
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.
An inner class is said to be a member of the outer class. Does that mean that whenever an object of the outer class is created, an instance of inner class is also created implicitly?
No. An instance of the inner class is created only when you instantiate it.
Note that the constructor of the inner class requires an instance of the outer class (although this is masked by the compiler). This is true for non-static nested classes. Static nested classes can be instantiated without a parent instance (since they are static)
There are different types of inner classes each acting differently.
Static member classes
Member classes
Local classes
Anonymous classes
You can find a good overview of all of them here :
http://www.javaworld.com/javaworld/javaqa/2000-03/02-qa-innerclass.html
It means that you need an instance of the outer class before you can have an instance of the inner class
All the crazy Java scoping rules are making my head spin and the public static void nonsense isn't helping matters. So far all the programming languages I have used either lexical scoping or some approximation of it without any access modifiers, i.e. inner stuff captures outer stuff and has access to the outer stuff as long as the inner stuff exists.
So how do I make sense of the scoping rules for inner classes in Java? Do they get access to variables declared in the outer class or is there some weird edge cases I have to worry about because of all the public static private stuff floating around?
Static nested classes1 are exactly like external classes except that they have access to all members of the outer class, regardless of access qualifier. They exist apart from any instance of the outer class, so need a reference to an instance in order to access any instance variables or non-static methods of the outer class.
Non-static nested classes (called inner classes) come into existence only in the context of an instance of the outer class. When constructed, they have a second this field automatically generated, which you can access from within the inner class using the syntax Outer.this. Each instance of the inner class is enclosed by a single instance of the outer class. Again, all the access privileges of static nested classes apply to inner classes. But since they already have an instance of the outer class available, they can automatically access instance variables and methods of the outer class.
For a nice (and very detailed) discussion of inner classes and access specifiers, you can read through the Inner Class Specification. It describes, among other things, how a nested class gets access to private members of its outer class(es). A gentler read is the Nested Classes tutorial.
An off-topic aside: Suppose you have this class structure:
public class O {
public O() { ... }
public class I { // an inner class
public I() { ... }
...
}
...
}
and you've created an instance of O:
O outer = new O();
Now suppose you want to create an instance of O.I. you can't just use new O.I() because the new instance of I needs to be enclosed by a specific instance of O. For this, Java provides the following syntax:
O.I inner = outer.new O.I();
Then inner will then have its second this field set to refer to outer.
Note that this "qualified new operator" syntax is only used for inner classes; it would be unnecessary (in fact, an error) if I were a static nested class.
1 You'll often come across the phrase "static inner class" (including, embarrassingly, in an earlier version of this answer). This is incorrect terminology. In Java, "inner classes" are specifically non-static nested classes.
You have to differenciate:
Static inner classes have access to all static members outside their declaration.
Instance inner classes have access to all class members outside their declaration, AND to final fields in the function they are declared in.
Have in mind that a non-static inner class also has a hidden variable with the instance of the outer class, to access the members there. And that all referenced final fields (therefore they must be final) are copied into the inner class in other hidden member variables when the inner class is instantiated.
Example:
public void doStuff(final int a, int b) {
final int c; // Can be referenced
int d; // Cannot be referenced, not final
executer.execute( new Runnable() {
public void run() {
System.out.println("a: "+a+" c: "+c);
}
}
b++; // Not final, not referencable
System.out.println(b);
}
I don't know if it helps, but from the java tutorials:
Static Nested Classes
As with class methods and variables, a static nested class is associated with its outer class. And like static class methods, 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.
Note: A static nested class interacts with the instance members of its outer class (and other classes) just like any other top-level class. In effect, a static nested class is behaviorally a top-level class that has been nested in another top-level class for packaging convenience.
Inner Classes [Non-Static Nested class?]
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.
You should check the java tutorial on nested classes.
Rules of the Inner classes in Java
In Java it is possible to define a class inside another class such classes are called nested classes or inner class.
There are 3 types of the Inner classes Instance Inner class, static inner class and anonymous inner class
If the Inner class is declared as instance inner class then it can access all of the members of the outer enclosing class including private members
If the Inner class is declared as static then it can only access the static members of the outer class (including the private static members). But it can NOT access the instance members
Consider that there is a variable x is defined in both the outer class and the instance inner classes then general form for accessing the variable from the inner class is this.x for the inner x and OuterClassname.this.x for the outer x.
You can also define an inner class inside any method or any other block
The general form for instantiating the inner class from outside the outer class is
Outer.Inner ob = new Outer.new Inner();
The general form for instantiating the inner class from outside the outer class is (if the inner class is declared as static)
Outer.Inner ob = new Outer.Inner();
The Inner classes can be declared with any of the access modifier keywords
If the Inner class is declared as private then it can NOT be instantiated from outside the outer class. Also in this case you can NOT access the members of the Inner class from outside the outer class even you have an object reference and even if the members of the private inner class are declared as public.
If the Inner class is declared as instance inner class then it can also access the superclass members of the outer class through the general statement
Outer.super.variable; Outer.super.method(params);
Rules for inner class
Outer class accessed by inner class
Inner class can't be accessed by outer class
The inner class members only used the methods and members within the class only access the fulled information
Method Scoped inner classes:-
Can only access the final members of the outer class.