Each inner class can inherit independently from an implementation, so it doesn’t matter whether the enclosing class already inherits an implementation.

Without the ability provided by inner classes to inherit from multiple concrete or abstract classes, some design and programming problems are difficult to solve. From this perspective, inner classes complete the solution to multiple inheritance, the interface solves part of the problem, and inner classes effectively implement multiple inheritance. Similar to the JDK dynamic proxy and CGLIB relationship.

Typical inner class

When an inner class object is generated, there is a connection between the object and the peripheral object that made it, so it can access all the members of its peripheral object without any special conditions, and the inner class also has access to all the elements of its peripheral class.

Since this feature can share enclosing class elements between multiple inner classes, which may inherit or implement the same abstract interface, these inner classes appear to be isolated to external client programs, but are actually related to each other.

When an object of a enclosing class creates an inner class object, the inner class object must secretly capture a reference to that enclosing class object, and then use that reference to select the enclosing class member when you access it. The compiler takes care of all the details for you, and an object of an inner class can only be created if it is associated with an object of its enclosing class (the inner class is not allowed to be static; this is called a nested class).

A normal inner class cannot have static data and static fields (it cannot have any components independent of the enclosing class object), and it cannot contain nested classes.

Private inner classes give class designers a way to combine up transition, completely block any type-dependent coding, and completely hide implementation details.

interface Selector { boolean ene(); Object current(); void next(); } public class Sequence { private Object[] item; private int next = 0; public Sequence(int size) { items = new Object[size]; } public void add(Object x) { if (next < items.length) { items[next++] = x; } } private class SequenceSelector implements Selector { private int i= 0; public boolean end() { return i == items.length; } public Object current() { return items[i]; } public void next() { if (i < items.length) { i++; } } } public Selector selector() { return new SequenceSelector(); } public static void main(String[] args) { Sequence sequence = new Sequence(10); for(int i = 0; i < 10; i++) { sequence.add(Integer.toString(i)); } Selector selector = sequence.selector(); while(! selector.end()) { System.out.println(selector.current() + " "); selector.next(); }}}Copy the code

The outerClassobject.new InnerClassName() syntax is used to create an inner class that is not a method inside the outer class.

public class DotNew { public class Inner {} public static void main(String[] args) { DotNew dn = new DotNew(); DotNew.Inner dni = db.new Inner(); }}Copy the code

Outerclassname.this syntax can be used if an external program wants to return a reference to an outer class object from an inner class object.

Public class DotThis {void f() {} public class Inner {public DotThis outer() {return dotthis.this; } } public Inner inner() { return new Inner(); } public static void main(String[] args) { DotThis dt = new DotThis(); DotThis.Inner dti = dt.inner(); dti.outer().f(); }}Copy the code

Local inner class

Creating a complete class within the scope of a method (as opposed to the scope of another class) is called a local inner class. This means putting the class definition inside a method, or even in a scope such as if.

Scenarios using local inner classes instead of anonymous inner classes:

  • A named constructor is required, or an overloaded constructor is required.
  • More than one object of the inner class is required.

Anonymous inner class

Like a local inner class, but without a class name of its own, this class simply transitions up and returns.

public class Parcel7 { public Contens contents() { return new Contents() { private int i = 1l; public int value() { return i; }}; // Semicolon required in this case; } public static void main(String[] args) { Parcel7 p = new Parcel7(); Contents c = p.contents(): } }Copy the code

If you define an anonymous inner class and want it to use an object defined outside of it, the compiler will require its parameter references to be final.

The life cycle of a local variable is inconsistent with that of a local inner class object. A copy of the final local variable is directly used as the data member of the local inner class object. Final realizes the unification of variables inside and outside.

public class Parcel9 { public Destination destination(final Stirng dest) { return new Destination() { privatr String label = dest; public String readLabel() { return label; } } } public static void main(String[] args) { Parcel9 p = new Parcel9(); Destination p = p.destination("Tss"); }}Copy the code

Nested classes

If you don’t need a connection between an inner class object and its enclosing class object, you can declare the inner class static, which is called a nested class.

  • To create an object of a nested class, you do not need an object of its enclosing class.
  • A non-static enclosing class object cannot be accessed from an object of a nested class (not without an object reference).

Normally, you can’t put any code inside an interface, but nested classes can be part of an interface, so any class you put in an interface is automatically public and static, because classes are static, just putting nested classes in the namespace of the interface doesn’t violate the rules of the interface, You can even implement its peripheral interfaces in an inner class.

If you want to create some common code that can be shared by all the different implementations of an interface, using nested classes inside the interface can be handy.

public interface ClassInInterface { void howdy(); class Test implements ClassInInterface { public void howdy() { System.out.println("Howdy!" ); } public static void main(String[] args) { new Test().howdy(); }}}Copy the code

Inheritance of inner classes

When we inherit from a enclosing class and define an inner class of the same name, the two inner classes are not related, unless the original enclosing class opens an inner class object reference interface so that the enclosing class can pass the corresponding inner class.