Java inner class and static nested class

ID : 474

viewed : 137

Tags : javainner-classesstatic-classesjava





Top 5 Answer for Java inner class and static nested class

vote vote

92

From the Java Tutorial:

Nested classes are divided into two categories: static and non-static. Nested classes that are declared static are simply called static nested classes. Non-static nested classes are called inner classes.

Static nested classes are accessed using the enclosing class name:

OuterClass.StaticNestedClass 

For example, to create an object for the static nested class, use this syntax:

OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass(); 

Objects that are instances of an inner class exist within an instance of the outer class. Consider the following classes:

class OuterClass {     ...     class InnerClass {         ...     } } 

An instance of InnerClass can exist only within an instance of OuterClass and has direct access to the methods and fields of its enclosing instance.

To instantiate an inner class, you must first instantiate the outer class. Then, create the inner object within the outer object with this syntax:

OuterClass outerObject = new OuterClass() OuterClass.InnerClass innerObject = outerObject.new InnerClass(); 

see: Java Tutorial - Nested Classes

For completeness note that there is also such a thing as an inner class without an enclosing instance:

class A {   int t() { return 1; }   static A a =  new A() { int t() { return 2; } }; } 

Here, new A() { ... } is an inner class defined in a static context and does not have an enclosing instance.

vote vote

84

The Java tutorial says:

Terminology: Nested classes are divided into two categories: static and non-static. Nested classes that are declared static are simply called static nested classes. Non-static nested classes are called inner classes.

In common parlance, the terms "nested" and "inner" are used interchangeably by most programmers, but I'll use the correct term "nested class" which covers both inner and static.

Classes can be nested ad infinitum, e.g. class A can contain class B which contains class C which contains class D, etc. However, more than one level of class nesting is rare, as it is generally bad design.

There are three reasons you might create a nested class:

  • organization: sometimes it seems most sensible to sort a class into the namespace of another class, especially when it won't be used in any other context
  • access: nested classes have special access to the variables/fields of their containing classes (precisely which variables/fields depends on the kind of nested class, whether inner or static).
  • convenience: having to create a new file for every new type is bothersome, again, especially when the type will only be used in one context

There are four kinds of nested class in Java. In brief, they are:

  • static class: declared as a static member of another class
  • inner class: declared as an instance member of another class
  • local inner class: declared inside an instance method of another class
  • anonymous inner class: like a local inner class, but written as an expression which returns a one-off object

Let me elaborate in more details.


Static Classes

Static classes are the easiest kind to understand because they have nothing to do with instances of the containing class.

A static class is a class declared as a static member of another class. Just like other static members, such a class is really just a hanger on that uses the containing class as its namespace, e.g. the class Goat declared as a static member of class Rhino in the package pizza is known by the name pizza.Rhino.Goat.

package pizza;  public class Rhino {      ...      public static class Goat {         ...     } } 

Frankly, static classes are a pretty worthless feature because classes are already divided into namespaces by packages. The only real conceivable reason to create a static class is that such a class has access to its containing class's private static members, but I find this to be a pretty lame justification for the static class feature to exist.


Inner Classes

An inner class is a class declared as a non-static member of another class:

package pizza;  public class Rhino {      public class Goat {         ...     }      private void jerry() {         Goat g = new Goat();     } } 

Like with a static class, the inner class is known as qualified by its containing class name, pizza.Rhino.Goat, but inside the containing class, it can be known by its simple name. However, every instance of an inner class is tied to a particular instance of its containing class: above, the Goat created in jerry, is implicitly tied to the Rhino instance this in jerry. Otherwise, we make the associated Rhino instance explicit when we instantiate Goat:

Rhino rhino = new Rhino(); Rhino.Goat goat = rhino.new Goat(); 

(Notice you refer to the inner type as just Goat in the weird new syntax: Java infers the containing type from the rhino part. And, yes new rhino.Goat() would have made more sense to me too.)

So what does this gain us? Well, the inner class instance has access to the instance members of the containing class instance. These enclosing instance members are referred to inside the inner class via just their simple names, not via this (this in the inner class refers to the inner class instance, not the associated containing class instance):

public class Rhino {      private String barry;      public class Goat {         public void colin() {             System.out.println(barry);         }     } } 

In the inner class, you can refer to this of the containing class as Rhino.this, and you can use this to refer to its members, e.g. Rhino.this.barry.


Local Inner Classes

A local inner class is a class declared in the body of a method. Such a class is only known within its containing method, so it can only be instantiated and have its members accessed within its containing method. The gain is that a local inner class instance is tied to and can access the final local variables of its containing method. When the instance uses a final local of its containing method, the variable retains the value it held at the time of the instance's creation, even if the variable has gone out of scope (this is effectively Java's crude, limited version of closures).

Because a local inner class is neither the member of a class or package, it is not declared with an access level. (Be clear, however, that its own members have access levels like in a normal class.)

If a local inner class is declared in an instance method, an instantiation of the inner class is tied to the instance held by the containing method's this at the time of the instance's creation, and so the containing class's instance members are accessible like in an instance inner class. A local inner class is instantiated simply via its name, e.g. local inner class Cat is instantiated as new Cat(), not new this.Cat() as you might expect.


Anonymous Inner Classes

An anonymous inner class is a syntactically convenient way of writing a local inner class. Most commonly, a local inner class is instantiated at most just once each time its containing method is run. It would be nice, then, if we could combine the local inner class definition and its single instantiation into one convenient syntax form, and it would also be nice if we didn't have to think up a name for the class (the fewer unhelpful names your code contains, the better). An anonymous inner class allows both these things:

new *ParentClassName*(*constructorArgs*) {*members*} 

This is an expression returning a new instance of an unnamed class which extends ParentClassName. You cannot supply your own constructor; rather, one is implicitly supplied which simply calls the super constructor, so the arguments supplied must fit the super constructor. (If the parent contains multiple constructors, the “simplest” one is called, “simplest” as determined by a rather complex set of rules not worth bothering to learn in detail--just pay attention to what NetBeans or Eclipse tell you.)

Alternatively, you can specify an interface to implement:

new *InterfaceName*() {*members*} 

Such a declaration creates a new instance of an unnamed class which extends Object and implements InterfaceName. Again, you cannot supply your own constructor; in this case, Java implicitly supplies a no-arg, do-nothing constructor (so there will never be constructor arguments in this case).

Even though you can't give an anonymous inner class a constructor, you can still do any setup you want using an initializer block (a {} block placed outside any method).

Be clear that an anonymous inner class is simply a less flexible way of creating a local inner class with one instance. If you want a local inner class which implements multiple interfaces or which implements interfaces while extending some class other than Object or which specifies its own constructor, you're stuck creating a regular named local inner class.

vote vote

79

I don't think the real difference became clear in the above answers.

First to get the terms right:

  • A nested class is a class which is contained in another class at the source code level.
  • It is static if you declare it with the static modifier.
  • A non-static nested class is called inner class. (I stay with non-static nested class.)

Martin's answer is right so far. However, the actual question is: What is the purpose of declaring a nested class static or not?

You use static nested classes if you just want to keep your classes together if they belong topically together or if the nested class is exclusively used in the enclosing class. There is no semantic difference between a static nested class and every other class.

Non-static nested classes are a different beast. Similar to anonymous inner classes, such nested classes are actually closures. That means they capture their surrounding scope and their enclosing instance and make that accessible. Perhaps an example will clarify that. See this stub of a Container:

public class Container {     public class Item{         Object data;         public Container getContainer(){             return Container.this;         }         public Item(Object data) {             super();             this.data = data;         }      }      public static Item create(Object data){         // does not compile since no instance of Container is available         return new Item(data);     }     public Item createSubItem(Object data){         // compiles, since 'this' Container is available         return new Item(data);     } } 

In this case you want to have a reference from a child item to the parent container. Using a non-static nested class, this works without some work. You can access the enclosing instance of Container with the syntax Container.this.

More hardcore explanations following:

If you look at the Java bytecodes the compiler generates for an (non-static) nested class it might become even clearer:

// class version 49.0 (49) // access flags 33 public class Container$Item {    // compiled from: Container.java   // access flags 1   public INNERCLASS Container$Item Container Item    // access flags 0   Object data    // access flags 4112   final Container this$0    // access flags 1   public getContainer() : Container    L0     LINENUMBER 7 L0     ALOAD 0: this     GETFIELD Container$Item.this$0 : Container     ARETURN    L1     LOCALVARIABLE this Container$Item L0 L1 0     MAXSTACK = 1     MAXLOCALS = 1    // access flags 1   public <init>(Container,Object) : void    L0     LINENUMBER 12 L0     ALOAD 0: this     ALOAD 1     PUTFIELD Container$Item.this$0 : Container    L1     LINENUMBER 10 L1     ALOAD 0: this     INVOKESPECIAL Object.<init>() : void    L2     LINENUMBER 11 L2     ALOAD 0: this     ALOAD 2: data     PUTFIELD Container$Item.data : Object     RETURN    L3     LOCALVARIABLE this Container$Item L0 L3 0     LOCALVARIABLE data Object L0 L3 2     MAXSTACK = 2     MAXLOCALS = 3 } 

As you can see the compiler creates a hidden field Container this$0. This is set in the constructor which has an additional parameter of type Container to specify the enclosing instance. You can't see this parameter in the source but the compiler implicitly generates it for a nested class.

Martin's example

OuterClass.InnerClass innerObject = outerObject.new InnerClass(); 

would so be compiled to a call of something like (in bytecodes)

new InnerClass(outerObject) 

For the sake of completeness:

An anonymous class is a perfect example of a non-static nested class which just has no name associated with it and can't be referenced later.

vote vote

70

I think that none of the above answers explain to you the real difference between a nested class and a static nested class in term of application design :

OverView

A nested class could be nonstatic or static and in each case is a class defined within another class. A nested class should exist only to serve is enclosing class, if a nested class is useful by other classes (not only the enclosing), should be declared as a top level class.

Difference

Nonstatic Nested class : is implicitly associated with the enclosing instance of the containing class, this means that it is possible to invoke methods and access variables of the enclosing instance. One common use of a nonstatic nested class is to define an Adapter class.

Static Nested Class : can't access enclosing class instance and invoke methods on it, so should be used when the nested class doesn't require access to an instance of the enclosing class . A common use of static nested class is to implement a components of the outer object.

Conclusion

So the main difference between the two from a design standpoint is : nonstatic nested class can access instance of the container class, while static can't.

vote vote

56

In simple terms we need nested classes primarily because Java does not provide closures.

Nested Classes are classes defined inside the body of another enclosing class. They are of two types - static and non-static.

They are treated as members of the enclosing class, hence you can specify any of the four access specifiers - private, package, protected, public. We don't have this luxury with top-level classes, which can only be declared public or package-private.

Inner classes aka Non-stack classes have access to other members of the top class, even if they are declared private while Static nested classes do not have access to other members of the top class.

public class OuterClass {     public static class Inner1 {     }     public class Inner2 {     } } 

Inner1 is our static inner class and Inner2 is our inner class which is not static. The key difference between them, you can't create an Inner2 instance without an Outer where as you can create an Inner1 object independently.

When would you use Inner class?

Think of a situation where Class A and Class B are related, Class B needs to access Class A members, and Class B is related only to Class A. Inner classes comes into the picture.

For creating an instance of inner class, you need to create an instance of your outer class.

OuterClass outer = new OuterClass(); OuterClass.Inner2 inner = outer.new Inner2(); 

or

OuterClass.Inner2 inner = new OuterClass().new Inner2(); 

When would you use static Inner class?

You would define a static inner class when you know that it does not have any relationship with the instance of the enclosing class/top class. If your inner class doesn't use methods or fields of the outer class, it's just a waste of space, so make it static.

For example, to create an object for the static nested class, use this syntax:

OuterClass.Inner1 nestedObject = new OuterClass.Inner1(); 

The advantage of a static nested class is that it doesn't need an object of the containing class/top class to work. This can help you to reduce the number of objects your application creates at runtime.

Top 3 video Explaining Java inner class and static nested class







Related QUESTION?