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
Related
Java The Complete Reference says
A static nested class is one that has the static modifier applied. Because it is static, it must access the non-static
members of its enclosing class through an object. That is, it
cannot refer to non-static members of its enclosing class
directly. Because of this restriction, static nested classes are
seldom used.
What does it mean by "through an object", and "cannot ... directly"?
Java in a Nutshell says
• A static member type can access (only) the static members of the class that contains it.
• A static member type has access to all the static members (including any other static member types) of its
containing type.
Are the two sentences redundant to each other? What are the differences between the two sentences?
Do the quotes from the two books contradict each other? The first
quote says a static nested class can access non-static member of the
enclosing class, while the second quote says a static member type
can access only the static members of the enclosing class.
Thanks.
In Java nested non - static classes have a hidden reference to the instance of the parent class. That's why they can access all non-static members. The nested class doesn't have such an instance. However, its scope allows it to access the parent members if the parent class passes this.
So what the second quote is saying that the access doesn't happen automatically. You pass the reference to the enclosing class and the nested static class can access it. Otherwise, it doesn't know the address of the enclosing class.
No static method may access an instance field directly without first qualifying it with an object of the containing class.
class Foo {
int myField;
public void main(String[] args) {
Foo foo = new Foo();
access(foo);
}
public static void access(Foo obj) {
System.out.println(myField); // <-- error, can't access myField from static
//context.
System.out.println(obj.myField); // OK here
}
}
The same is true for accessing instance fields via inner static classes.
A java static nested class can access the static members of the nested class and the static members of the parent class. This makes sense when you understand the position of a class and object in memory – that there is only one class but multiple objects and you need to decide what each instance of an object needs absolutely necessarily and what is actually redundant and can stay in the class (doesn't need to be duplicated), so all methods (static and non static) and all static members
What members of the enclosing class can a static nested class access?
You can gain clarity to the answer for this question by assigning the following meaning for the Java keyword static:
"Static" in Java means without regard for or association with any instance of any class.
A static field belongs to the class in which it is declared and is not encapsulated by any instance of that class. Any instance of the class that is subsequently constructed (or any instance or any method of any class that is in scope) can access the static field (this is why static fields can be dangerous in concurrent environments).
A static method is defined for the class in which it is declared and has no associated instance of that class. A static method knows of no class instances and can not access any of them unless a reference to an instance is passed to it as an argument.
A static member class is in every way that matters the same as an ordinary top level class that has been packaged within an enclosing class for packaging convenience. Just like a top level class, its instances know nothing of any instance of the enclosing class (unless a reference to an enclosing class instance is passed to them during construction).
A static initializer block is used to initialize static fields for a class, but it knows nothing of any instances of that class. Therefore, they cannot initialize instance fields since they cannot access them.
Therefore, the answer becomes intuitive: a static nested class can access all members of an enclosing class that can be accessed without an instance of that class.
If an enclosing class instance is passed to the static nested class's constructor, then the members of that instance (including the private ones) will be in scope. Logically, passing an enclosing class instance to a static nested class constructor is very similar to using a nested member class. The difference is that for the former, the association is an explicit dependency injection; whereas for the latter, the association between instances is implicit.
Here are two statements I found concerning inner classes
JavaDocs:
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.
On another site I found this:
A nested class, for the most part, is just that—a class declared in
the definition of an enclosing class. It does not inherit anything
from the enclosing class, and an instance of the nested class cannot
be assigned to a variable reference to the enclosing class.
Aren't the bold marked lines contradicting?
How can you not inherit a surrounding objects fields and methods and at the same time have access to its fields and methods?
No, they do not conflict. Look at the following example:
public class A {
public void foo() {
//some code
}
public class B {
public void bar() {
foo();
}
}
}
In this example, the innerclass B can access the method of A (or any of its' fields, actually), but in no way does inheritance takes place.
For instance, the following change to B would result in a compilation error:
public class B {
public void bar() {
super.foo();
}
}
Because B does not inherit from A. It can access its' instance members, but it does not extend (inherit) from it.
Please do not see the terms nested class and inner class as an opposite or something similar. In fact, a nested class simply describes all sorts of classes that are declared inside another class:
Nested classes that are declared static are simply called static nested classes.
Non-static nested classes are called inner classes. There are three types of them (see JLS §8.1.3 for more info):
A non-static member class.
A local class.
An anonymous class.
The first paragraph you quoted explains that an inner class has access (read: access, not inherit) to the methods and fields of the enclosing instance. Note, it is about an instance, not the class.
The second paragraph tries to explain that there is no relationship between a class and a nested class inside it, except for their locations.
class OuterClass {
class InnerClass {
static int i = 100; // compile error
static void f() { } // compile error
}
}
Although it's not possible to access the static field with OuterClass.InnerClass.i, if I want to record something that should be static, e.g. the number of InnerClass objects created, it would be helpful to make that field static. So why does Java prohibit static fields/methods in inner classes?
EDIT: I know how to make the compiler happy with static nested class (or static inner class), but what I want to know is why java forbids static fields/methods inside inner classes (or ordinary inner class) from both the language design and implementation aspects, if someone knows more about it.
what I want to know is why java forbids static fields/methods inside inner classes
Because those inner classes are "instance" inner classes. That is, they are like an instance attribute of the enclosing object.
Since they're "instance" classes, it doesn't make any sense to allow static features, for static is meant to work without an instance in the first place.
It's like you try to create a static/instance attribute at the same time.
Take the following example:
class Employee {
public String name;
}
If you create two instances of employee:
Employee a = new Employee();
a.name = "Oscar";
Employee b = new Employee();
b.name = "jcyang";
It is clear why each one has its own value for the property name, right?
The same happens with the inner class; each inner class instance is independent of the other inner class instance.
So if you attempt to create a counter class attribute, there is no way to share that value across two different instances.
class Employee {
public String name;
class InnerData {
static count; // ??? count of which ? a or b?
}
}
When you create the instance a and b in the example above, what would be a correct value for the static variable count? It is not possible to determine it, because the existence of the InnerData class depends completely on each of the enclosing objects.
That's why, when the class is declared as static, it doesn't need anymore a living instance, to live itself. Now that there is no dependency, you may freely declare a static attribute.
I think this sounds reiterative but if you think about the differences between instance vs. class attributes, it will make sense.
The idea behind inner classes is to operate in the context of the enclosing instance. Somehow, allowing static variables and methods contradicts this motivation?
8.1.2 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).
InnerClass cannot have static members because it belongs to an instance (of OuterClass). If you declare InnerClass as static to detach it from the instance, your code will compile.
class OuterClass {
static class InnerClass {
static int i = 100; // no compile error
static void f() { } // no compile error
}
}
BTW: You'll still be able to create instances of InnerClass. static in this context allows that to happen without an enclosing instance of OuterClass.
From Java 16 onwards, this is no longer the case. Quoting from JEP 395 (on finalizing records):
Relax the longstanding restriction whereby an inner class cannot declare a member that is explicitly or implicitly static. This will become legal and, in particular, will allow an inner class to declare a member that is a record class.
Indeed, the following code can be compiled with Java 16 (tried with 16.ea.27):
public class NestingClasses {
public class NestedClass {
static final String CONSTANT = new String(
"DOES NOT COMPILE WITH JAVA <16");
static String constant() {
return CONSTANT;
}
}
}
Actually, you can declare static fields if they are constants and are written in compile time.
class OuterClass {
void foo() {
class Inner{
static final int a = 5; // fine
static final String s = "hello"; // fine
static final Object o = new Object(); // compile error, because cannot be written during compilation
}
}
}
class Initialization sequence is a critical reason.
As inner classes are dependent on the instance of enclosing/Outer class, so Outer class need to be initialized before the initialization of the Inner class.
This is JLS says about class Initialization. The point we need is, class T will be initialize if
A static field declared by T is used and the field is not a constant variable.
So if inner class have an static field accessing that will cause initializing the inner class, but that will not ensure that the enclosing class is initialized.
It would violate some basic rules. you can skip to the last section (to two cases) to avoid noob stuff
One thing about static nested class, when some nested class is static it will behave just like a normal class in every way and it is associated with the Outer class.
But the concept of Inner class/ non-static nested class is it will be associated with the instance of outer/enclosing class. Please note associated with instance not the class.
Now associating with instance clearly means that (from the concept of instance variable) it will exist inside a instance and will be different among instances.
Now, when we make something static we expect it will be initialized when the class is being loaded and should be shared among all instances. But for being non-static, even inner classes themselves (you can definitely forget about instance of inner class for now) are not shared with all instance of the outer/enclosing class (at least conceptually), then how can we expect that some variable of inner class will be shared among all the instance of the inner class.
So if Java allow us to use static variable inside not static nested class. there will be two cases.
If it is shared with all the instance of inner class it will violate the concept of context of instance(instance variable). It's a NO then.
If it is not shared with all instance it will violate the the concept of being static. Again NO.
Here is the motivation that I find best suitable for this "limit":
You can implement the behavior of a static field of an inner class as an instance field of the outer object;
So you do not need static fields/methods.
The behaviour I mean is that all inner class instances of some object share a field(or method).
So, suppose you wanted to count all the inner class instances, you would do:
public class Outer{
int nofInner; //this will count the inner class
//instances of this (Outer)object
//(you know, they "belong" to an object)
static int totalNofInner; //this will count all
//inner class instances of all Outer objects
class Inner {
public Inner(){
nofInner++;
totalNofInner++;
}
}
}
In simple words, non-static inner classes are instance variable for outer class, and they are created only when an outer class is created and an outer class object is created at run-time while static variables are created at class loading time.
So non-static inner class is runtime thing that's why static not the part of a non-static inner class.
NOTE: treat inner classes always like a variable for an outer class they may be static or non-static like any other variables.
Because it would cause ambiguity in the meaning of "static".
Inner classes cannot declare static members other than
compile-time constants. There would be an ambiguity about the meaning
of “static.” Does it mean there is only one instance in the virtual
machine? Or only one instance per outer object? The language designers
decided not to tackle this issue.
Taken from "Core Java SE 9 for the Impatient" by Cay S. Horstmann. Pg 90 Chapter 2.6.3
In the Java language designers' own words:
Since nested classes were first introduced to Java, nested class
declarations that are inner have been prohibited from declaring static
members... It simplifies the language's task of resolving and
validating references to in-scope variables, methods, etc.
There was never any particularly grand conceptual or philosophical reason to prohibit this.
Simplifying things for the language was deemed an insufficient reason to continue to maintain this restriction. Along with the introduction of records in Java 16, they made the decision to relax the restriction.
Class Inner will be initialize if a static field declared by Inner is used and the field is not a constant variable.
class Outer{
class Inner{
static Inner obj = new Inner();
}
public static void main(String[] args){
Inner i = Inner.obj; // It woulds violate the basic rule: without existing Outer class Object there is no chance of existing Inner class Object.
}
}
I guess it's for consistency. While there doesn't seem to be any technical limitation for it, you wouldn't be able to access static members of the internal class from the outside, i.e. OuterClass.InnerClass.i because the middle step is not static.
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.
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.