An inner class is a class that is redefined inside an outer class. An inner class exists as a member of an external class and is attached to an external class.
Inner classes can be static, available with protected and private adornments (while external classes can only use public and default package access).
Inner classes are mainly of the following categories: Member inner class, local inner class, Static inner class, Anonymous inner class
Why do I need an internal class?
Typically, an inner class inherits from a class or implements an interface, and the inner class's code operation creates an object of its outer class. So you can assume that the inner class provides some kind of window into its outer class. The most appealing reasons for using inner classes are:
Each inner class can inherit itself from one (interface) implementation independently, so no matter whether the perimeter class has inherited an implementation of (an interface), there is no effect on the inner class. Some design and programming problems can be difficult to solve without the ability of an inner class to inherit multiple concrete or abstract classes. From this point of view, the inner class makes the solution of multiple inheritance complete. The interface solves some of the problems, while the inner class effectively implements "multiple inheritance."
A: Member Inner class
exists as a member of an external class, in parallel with the properties and methods of the outer class.
public class Outer {
private static int i = 1;
private int j = 10;
private int k = 20;
public static void Outer_f1 () {}
public void Outer_f2 () {}
A static member cannot be defined in a member inner class
member Inner class, you can access all members of an external class
Class Inner {
static int inner_i = 100; Defining static variables is not allowed in inner classes
INTJ = 100; instance variables for inner and outer classes can coexist
int inner_i = 1;
void Inner_f1 () {
System.out.println (i);
Accessing internal classes within the inner class of their own variables directly with the variable name
System.out.println (j);
You can also use this to access internal classes of your own variables in internal classes. Variable Name
System.out.println (THIS.J);
Accessing an instance variable in an external class with the same name as an inner class in an inner class with an external class name. This variable name
System.out.println (OUTER.THIS.J);
If there is no variable with the same name as the outer class in the inner class, you can access the outer class variable directly with the variable name
System.out.println (k);
Outer_f1 ();
Outer_f2 ();
}
}
Non-static methods for external classes access member inner classes
public void Outer_f3 () {
Inner Inner = new Inner ();
Inner.inner_f1 ();
}
A static method of an external class accesses a member's inner class, just as it accesses a member's inner class outside the outer category
public static void Outer_f4 () {
Step1 creating an External class object
Outer out = new Outer ();
Step2 building an inner class object based on an external class object
Inner Inner = Out.new Inner ();
Step3 methods for accessing inner classes
Inner.inner_f1 ();
}
public static void Main (string[] args) {
Outer_f4 (); The output of the statement is the same as the output of the following three statements
If you want to create an object of an inner class directly, you cannot assume that just add the name of the outer class outer,
You can create an object of an inner class as you normally would, but you must use an object of this outer class to
Create an object of its inner class:
Outer.Inner Outin = out.new Inner ()
Therefore, it is not possible to generate an object of an inner class unless you already have an object of the outer class. Because of this
An object of an inner class is silently linked to the object that created its perimeter class. If you're using a static inner class,
It does not require a reference to its perimeter class object.
Outer out = new Outer ();
Outer.Inner Outin = Out.new Inner ();
Outin.inner_f1 ();
}
}
Note: An inner class is a compile-time concept that, once compiled successfully, becomes a completely different class.
For an external class named Outer and its internally defined inner class named inner. There are two classes of Outer.class and Outer$inner.class after the compilation is complete.
B: Local inner class
The inner class defined in the method is called a local inner class. Like a local variable, a local inner class cannot have an access specifier because it is not part of a perimeter class, but it can access constants within the current code block, and all members of this perimeter class.
public class Outer {
private int s = 100;
private int out_i = 1;
public void f (final int k) {
Final int s = 200;
int i = 1;
Final int j = 10;
Defined inside a method
Class Inner {
int s = 300; You can define a variable with the same name as an external class
static int m = 20; Static variables cannot be defined
Inner (int k) {
Inner_f (k);
}
int inner_i = 100;
void inner_f (int k) {
If the inner class does not have a variable with the same name as the outer class, the instance variable of the outer class can be accessed directly in the inner class
System.out.println (out_i);
You can access the local variables of the outer class (that is, the variables within the method), but the variables must be final
System.out.println (j);
System.out.println (i);
If there is a variable with the same name as the outer class in the inner class, the variables of the inner class are accessed directly with the variable name
System.out.println (s);
The internal class variable is also accessed with the this variable name.
System.out.println (THIS.S);
Use the external class name. this. The internal class variable name accesses the outer class variable
System.out.println (OUTER.THIS.S);
}
}
New Inner (k);
}
public static void Main (string[] args) {
Access to the local inner class must have an outer class object first
Outer out = new Outer ();
OUT.F (3);
}
}
C: Static inner Class (nested Class): (Note: The first two inner classes are similar to variables, so you can control the reference variable)
If you don't need a connection between an inner class object and its enclosing class object, you can declare the inner class as static. This is often referred to as nested classes (nested Class). To understand the meaning of static when applied to inner classes, you must remember that a normal inner class object implicitly holds a reference to the outer class object that created it. However, this is not the case when the inner class is static. A nested class means:
1. To create an object of a nested class, the object of its enclosing class is not required.
2. Non-static perimeter class objects cannot be accessed from objects in the nested class.
public class Outer {
private static int i = 1;
private int j = 10;
public static void Outer_f1 () {}
public void Outer_f2 () {}
Static inner classes can be modified with public,protected,private
Static or non-static members can be defined in a statically internal class
Static Class Inner {
static int inner_i = 100;
int inner_j = 200;
static void Inner_f1 () {
Static inner classes can access only static members of external classes (including static variables and static methods)
System.out.println ("outer.i" + i);
Outer_f1 ();
}
void Inner_f2 () {
Static inner classes cannot access non-static members of external classes (including non-static variables and non-static methods)
System.out.println ("Outer.i" +j);
Outer_f2 ();
}
}
public void Outer_f3 () {
External classes Access static members of inner classes: inner classes. Static Members
System.out.println (Inner.inner_i);
Inner.inner_f1 ();
An external class accesses a non-static member of an inner class: instantiates an inner class to
Inner Inner = new Inner ();
Inner.inner_f2 ();
}
public static void Main (string[] args) {
New Outer (). OUTER_F3 ();
}
}
Generating a static inner class does not require an external class member: This is the difference between a static inner class and a member inner class. Objects of the static inner class can be generated directly: Outer.Inner in = new Outer.Inner (); It does not need to be generated by generating an external class object. This actually makes the static inner Class A top class (under normal circumstances, you cannot place any code inside the interface, but the nested class can be part of the interface because it is static.) Just place the nested class inside the interface's namespace, which does not violate the rules of the interface)
D: Anonymous inner class (from thinking in Java 3th)
To put it simply: an anonymous inner class is an inner class without a name. Under what circumstances do I need to use anonymous internal classes? Using an anonymous inner class is appropriate if some of the following conditions are true:
• Only one instance of the class is used.
• The class is used immediately after the definition.
• The class is very small (sun recommended is below 4 lines of code)
• Naming a class does not make your code easier to understand.
Here are a few principles to keep in mind when using anonymous inner classes:
• Anonymous inner classes cannot have a constructor method.
• Anonymous inner classes cannot define any static members, methods, and classes.
• Anonymous inner class cannot be public,protected,private,static.
• Only one instance of an anonymous inner class can be created.
• An anonymous inner class must be behind new, implementing an interface with its implication or implementing a class.
• Because the anonymous inner class is a local inner class, all restrictions on the local inner class are applied to it.
The following example looks a bit strange:
Returns an anonymous inner class in the method
public class Parcel6 {
Public Contents cont () {
return new Contents () {
private int i = 11;
public int value () {
return i;
}
}; A semicolon is required here
}
public static void Main (string[] args) {
Parcel6 p = new Parcel6 ();
Contents C = P.cont ();
}
}
The Cont () method merges the following two actions: the generation of the return value, and the definition of the class that represents the return value! Further, this class is anonymous and it has no name. What's worse, it looks like you're about to create a contents object:
return new Contents ()
But before you reach the semicolon at the end of the statement, you say, "Wait, I want to insert the definition of a class here":
return new Contents () {
private int i = 11;
public int value () {return i;}
};
This strange syntax refers to the creation of an object that inherits from the anonymous class of contents. The reference returned by the new expression is automatically converted upward to a reference to contents. The syntax of an anonymous inner class is a shorthand for the following example:
Class Mycontents implements Contents {
private int i = 11;
public int value () {return i;}
}
return new mycontents ();
In this anonymous inner class, the default constructor is used to generate the contents. The following code shows what to do if your base class needs a constructor with parameters:
public class Parcel7 {
Public wrapping Wrap (int x) {
Base Constructor Call:
return new Wrapping (x) {//Pass constructor argument.
public int value () {
return Super.value () * 47;
}
}; Semicolon Required
}
public static void Main (string[] args) {
PARCEL7 p = new Parcel7 ();
Wrapping W = p.wrap (10);
}
}
Simply pass the appropriate parameters to the constructor of the base class, where x is passed into the new wrapping (x). The semicolon at the end of the anonymous inner class is not used to mark the end of this inner class (as in C + +). In fact, it marks the end of the expression, except that the expression happens to contain the inner class. Therefore, this is consistent with the semicolon used elsewhere.
If you define a member variable in an anonymous class, you can also perform initialization on it:
public class Parcel8 {
Argument must is final to use inside
Anonymous inner class:
Public Destination dest (final String dest) {
return new Destination () {
Private String label = dest;
Public String Readlabel () {return label;}
};
}
public static void Main (string[] args) {
Parcel8 p = new Parcel8 ();
Destination d = p.dest ("Tanzania");
}
}
If you have an anonymous inner class that uses an object that is defined outside of it, the compiler will require that its parameter reference be final, just like the parameter in Dest (). If you forget, you will get a compile-time error message. If you simply assign a value to a member variable, the method in this example is possible. But what if you want to behave like a constructor? It is not possible to have a named constructor in an anonymous class (because it has no name at all!). ), but with instance initialization, you can achieve the effect of "making" a constructor for an anonymous inner class. Do it like this:
Abstract class Base {
Public Base (int i) {
System.out.println ("Base constructor, i =" + i);
}
public abstract void f ();
}
public class Anonymousconstructor {
public static Base getbase (int i) {
return new Base (i) {
{
System.out.println ("Inside instance initializer");
}
public void F () {
System.out.println ("in Anonymous F ()");
}
};
}
public static void Main (string[] args) {
Base base = GetBase (47);
BASE.F ();
}
}
In this case, it is not required that the variable I must be final. Because I is passed to the constructor of the base class of an anonymous class, it is not used directly inside the anonymous class. The following example is the "parcel" form with instance initialization. Note that the parameters of dest () must be final, because they are used within anonymous classes.
public class Parcel9 {
Public destinationdest (Final String dest, final float price) {
return new Destination () {
private int cost;
Instance initialization for each object:
{
Cost = Math.Round (price);
if (Cost > 100)
System.out.println ("over budget!");
}
Private String label = dest;
Public String Readlabel () {return label;}
};
}
public static void Main (string[] args) {
Parcel9 p = new Parcel9 ();
Destination d = p.dest ("Tanzania", 101.395F);
}
}
In the part of the instance initialization, you can see that there is a piece of code that could not have been executed as part of the initialization of the member variable (that is, the IF statement). So for anonymous classes, the actual effect of instance initialization is the constructor. Of course it's restricted: You can't overload instance initialization, so you can only have one constructor.
Accessing external from a multilayer nested class
It does not matter how many layers an inner class is nested, and it transparently accesses all members of the enclosing class that it embeds, as follows:
Class MNA {
private void F () {}
Class A {
private void G () {}
public class B {
void H () {
g ();
f ();
}
}
}
}
public class Multinestingaccess {
public static void Main (string[] args) {
MNA MNA = new MNA ();
MNA. A Mnaa = Mna.new A ();
MNA. A.B Mnaab = Mnaa.new B ();
Mnaab.h ();
}
}
You can see that in mna.a.b, calling Methods G () and F () does not require any conditions (even if they are defined as private). This example also shows how to create a basic syntax for nested inner class objects from different classes. The ". New" syntax produces the correct scope, so you do not have to qualify the class name when you call the constructor.
Overloading problems for internal classes
What happens if you create an inner class and then inherit its perimeter class and redefine this inner class? In other words, can internal classes be overloaded? This may seem like a useful idea, but the "overloaded" inner class is as if it were a method of the outer class, and it doesn't really work:
Class Egg {
private yolk y;
Protected class Yolk {
Public yolk () {
System.out.println ("Egg.yolk ()");
}
}
Public Egg () {
System.out.println ("New Egg ()");
y = new yolk ();
}
}
public class Bigegg extends Egg {
public class Yolk {
Public yolk () {
System.out.println ("Bigegg.yolk ()");
}
}
public static void Main (string[] args) {
New Bigegg ();
}
}
The output is:
New Egg ()
Egg.yolk ()
The default constructor is generated automatically by the compiler, which is the default constructor for calling the base class. You might think that since you created the Bigegg object, you should be using "overloaded" yolk, but you can see from the output that this is not the case.
This example shows that when you inherit an outer class, the inner class does not have a particularly magical change. These two inner classes are completely independent of the two entities, each within their own namespace. Of course, it is also possible to explicitly inherit an inner class:
Class Egg2 {
Protected class Yolk {
Public yolk () {
System.out.println ("Egg2.yolk ()");
}
public void F () {
System.out.println ("Egg2.yolk.f ()");
}
}
Private yolk y = new yolk ();
Public Egg2 () {
System.out.println ("New Egg2 ()");
}
public void insertyolk (yolk yy) {
y = yy;
}
public void G () {
Y.F ();
}
}
public class BigEgg2 extends Egg2 {
public class Yolk extends Egg2.yolk {
Public yolk () {
System.out.println ("Bigegg2.yolk ()");
}
public void F () {
System.out.println ("Bigegg2.yolk.f ()");
}
}
Public BigEgg2 () {
Insertyolk (new yolk ());
}
public static void Main (string[] args) {
EGG2 e2 = new BigEgg2 ();
E2.G ();
}
}
The output is:
Egg2.yolk ()
New Egg2 ()
Egg2.yolk ()
Bigegg2.yolk ()
Bigegg2.yolk.f ()
Bigegg2.yolk now explicitly inherits this inner class through extends Egg2.yolk, and overloads the method. The Egg2 insertyolk () method enables BIGEGG2 to transform its own yolk object upward and then pass it to reference Y. So when G () calls Y.F (), the overloaded new version of F () is executed. The second call to Egg2.yolk () is the constructor of the Bigegg2.yolk constructor that called its base class. You can see that the new version of F () is called when G () is called.
Inheritance issues for internal classes (thinking in Java 3th p294)
Because the constructor of the inner class uses references to its outer class objects, things get a little complicated when you inherit an inner class. The problem is that the reference to the "secret" outer class object must be initialized, and there is no default object to join in the inherited class. To solve this problem, you need to use specialized syntax to clearly clarify the correlation between them:
Class Withinner {
Class Inner {
Inner () {
System.out.println ("This was a constructor in Withinner.inner");
};
}
}
public class Inheritinner extends Withinner.inner {
// ! Inheritinner () {}//Won ' t compile
Inheritinner (Withinner WI) {
Wi.super ();
System.out.println ("This was a constructor in Inheritinner");
}
public static void Main (string[] args) {
Withinner WI = new Withinner ();
Inheritinner II = new Inheritinner (WI);
}
}
The output is:
This was a constructor in Withinner.inner
This was a constructor in Inheritinner
As you can see, Inheritinner only inherits from the inner class, not the outer class. But when you want to build a constructor, the default constructor isn't good, and you can't just pass a reference to a perimeter class object. In addition, you must use the following syntax within the constructor:
Enclosingclassreference.super ();
This provides the necessary references before the program can be compiled.
Java Internal classes