One class defines the internal definition of another class, which is called the internal class.
Public class out1 {
Private string name;
Public static int health;
Class in {// The internal class of the member is not static
Public void myprint (){
System. Out. Print ();
}
}
Static class in2 {// static member internal class
}
Public void show () {// Method
Int x = 10; // local variable
Class in3 () {// local internal class
}
}
}
Anonymous internal class
Role of internal classes:
1. Internal classes provide better encapsulation.
Only external classes can be directly accessed, and other classes in the same package cannot be directly accessed.
2. The internal class can directly access the private attributes of the external class,
Internal classes are considered members of their external classes.
However, external classes cannot directly access internal attributes of internal classes.
Use Cases of internal classes:
Because the internal class provides better encapsulation features, and can easily access the attributes of the external class.
Therefore, the internal class is usually preferred when providing services only for the external class.
Classification of internal classes:
Internal member classes (private, proteted, and public can be used for any modification.
Class file: External class $ internal class. Class)
Internal class access features:
1. The internal class can directly access members in the external class.
2. To access internal classes, external classes must create internal class objects.
There is another thing in the description of this thing, and this thing is still accessing the content of the described thing.
In this case, another thing is defined as an internal class to describe.
1. Member internal class
The internal class can directly access the members of the External class because the internal class holds the reference of the external class.
You can use the external class name. This. member variable of the internal class to access the internal class method.
2. Local internal class
The internal class can access the local variables modified by final in the local location (in the method.
3. Anonymous internal class
Is the abbreviated format of the internal class. It is actually an anonymous subclass object.
Prerequisites: the internal class must inherit or implement an external class or interface.
Syntax: new parent class or interface () {subclass content}
4. static internal class
If the internal class defines static members, the internal class must also be static
Example:
Member internal class
Class outter {
Private int age = 10;
Class inner {
Public int inage = 20;
// Member methods of internal classes
Public void innershow (){
System. Out. Print (AGE );
System. Out. Print (inage );
System. Out. Print (outter. This. inage );
}
}
// Member methods of external classes
Public void outshow (){
New inner (). innershow ();
}
}
Local internal class
Class Outer
{
Int num = 3;
Object method ()
{
Final int x = 9;
Class inner
{
Public String tostring ()
{
Return "show..." + X;
}
}
Object in = new inner ();
Return in;
}
}
Class innerclassdemo3
{
Public static void main (string [] ARGs)
{
Outer out = new outer ();
Object OBJ = out. Method ();
System. Out. println (OBJ );
}
}
Anonymous internal class
Abstract class demo
{
Abstract void show ();
}
Class Outer
{
Int num = 4;
/*
Class inner extends demo
{
Void show ()
{
System. Out. println ("show..." + num );
}
}
*/
Public void method ()
{
// New inner (). Show ();
New demo () // anonymous internal class.
{
Void show ()
{
System. Out. println ("show..." + num );
}
}. Show ();
}
}
Class innerclassdemo4
{
Public static void main (string [] ARGs)
{
New outer (). Method ();
}
}
I. Internal Basics
2. in-depth understanding of internal classes
Iii. Use Cases and benefits of internal classes
4. Common internal-related written examination questions
I. Internal Basics
In Java, a class can be defined in another class or a method. Such a class is called an internal class.
In a broad sense, internal classes generally include these four types: member Internal classes, local internal classes, anonymous internal classes, and static internal classes. The following describes the usage of these four internal classes.
1. Member internal class
The member internal class is the most common internal class, which is defined as located inside another class, in the form of the following:
Classcircle {
Double Radius = 0;
Public circle (double radius ){
This. radius = radius;
}
Classdraw {// internal class
Public void drawsahpe (){
System. Out. println ("drawshape ");
}
}
}
In this way, the draw class looks like a member of the circle class, which is called an external class.
The internal class of a member can unconditionally access all member attributes and member methods (including private and static members) of the external class ).
Classcircle {
Private Double Radius = 0;
Public static int COUNT = 1;
Public circle (double radius ){
This. radius = radius;
}
Classdraw {// internal class
Public void drawsahpe (){
System. Out. println (RADIUS); // Private member of the external class
System. Out. println (count); // static member of the external class
}
}
}
Note that:
When a Member's internal class has a member variable or method with the same name as the external class,
Hidden, that is, by default, members of the internal class of the member are accessed.
To access members with the same name as an external class, you need to access the external class in the following form:
External class. This. member variable;
External class. This. Member method;
Although the internal class of a member can access members of an external class unconditionally,
The external Class Members who want to access the internal class of the member are not so casual.
Cannot be accessed directly. You need to create an internal class object for access.
To access members of a Member's internal class in an external class:
1) You must first create an object for the internal class of the member,
2) access the service by referencing the object:
Classcircle {
Private Double Radius = 0;
Public circle (double radius ){
This. radius = radius;
Getdrawinstance (). drawsahpe (); // you must first create an object for the member's internal class and then access} private draw getdrawinstance () {returnnewdraw ();} classdraw {// internal class public void drawsahpe () {system. out. println (RADIUS); // Private member of the external class }}}
The internal class of a member is attached to an external class,
That is to say, to create an object of the member's internal class, the premise is that an object of the external class must exist.
The general method for creating class objects within a Member is as follows:
Publicclass test {
Public static void main (string [] ARGs ){
// Method 1:
Outter = newoutter ();
Outter. Inner inner = outter. New inner (); // You must create an outter object.
// Method 2: outter. Inner inner1 = outter. getinnerinstance ();
}
}
Class outter {
Private inner = NULL;
// External class Constructor
Public outter (){
}
// Common external Class Method
Public inner getinnerinstance (){
If (inner = NULL)
Inner = newinner ();
Return inner;
}
// Internal class
Class inner {
Public inner () {// internal class Constructor
}
}
}
Internal classes can have private access, protected access, public access, and package access permissions.
For example:
If the inner class of the member is modified using private, only internal access of the outer class is allowed,
If it is modified using public, it can be accessed anywhere;
If protected is used for modification, it can only be accessed under the same package or inherit external classes;
If it is the default access permission, it can only be accessed under the same package.
This is a little different from the external class. The external class can only be modified by the public and package access permissions.
My personal understanding: because the internal class of a Member looks like a member of an external class,
Therefore, you can have multiple permissions like a member of a class.
2. Local internal class
A local internal class is a class defined in a method or scope,
The difference between the class and the member internal class is that the access of the local internal class is limited to the method or the scope.
Class People {
Public people (){
}
}
Class man {
Public man () {// Constructor
}
Public people getwoman (){
// Local internal class
Class woman extends people {
Int age = 0;
}
Return New Woman (); // the return value of the method is a people-type object, which can be a people of the parent type or a women subclass object.
}
}
Note:
The local internal class is like a local variable in the method,
Public, protected, private, and static modifiers are not allowed.
3. Anonymous internal class
Anonymous internal classes should be the most commonly used for code writing,
It is not only convenient to use anonymous internal classes when writing event listening code, but also makes the code easier to maintain.
The following code is a piece of Android event listening code:
Scan_bt.setonclicklistener (newonclicklistener (){
@ Override
Public void onclick (view v ){
// Todo auto-generated method stub
}
});
History_bt.setonclicklistener (newonclicklistener (){
@ Override
Public void onclick (view v ){
// Todo auto-generated method stub
}
});
This Code sets the listener for the two buttons. The anonymous internal class is used here.
In this Code:
Newonclicklistener (){
@ Override
Public void onclick (view v ){
// Todo auto-generated method stub }}
Is the use of anonymous internal classes.
In the code, you need to set the listener object for the button,
Using an anonymous internal class can generate a corresponding object while implementing methods in the parent class or interface,
However, the premise is that this parent class or interface must exist before it can be used in this way.
Of course, this method is also possible, which is the same as using anonymous internal classes.
Private void setlistener (){
Scan_bt.setonclicklistener (newlistener1 ());
History_bt.setonclicklistener (newlistener2 ());
}
Class listener1 implements
View. onclicklistener {
@ Override
Public void onclick (view v ){
// Todo auto-generated method stub
}
}
Class listener2 implements
View. onclicklistener {
@ Override
Public void onclick (view v ){
// Todo auto-generated method stub
}
}
Although this method can achieve the same effect, it is lengthy and difficult to maintain,
Therefore, we generally use anonymous internal class methods to write event listening code.
Similarly, anonymous internal classes cannot have access modifiers and static modifiers.
An anonymous internal class is the only class without a constructor.
Because there is no constructor, the use of anonymous internal classes is very limited. Most anonymous internal classes are used for interface callback.
During compilation, the anonymous internal class is automatically named outter $1. class by the system.
Generally, anonymous internal classes are used to inherit other classes or implement interfaces,
You do not need to add additional methods, but only implement or override the inherited methods.
4. static internal class
Static internal classes are also defined in another class, except that a keyword static is added before the class.
Static internal classes do not need to depend on external classes. This is a bit similar to static member attributes of classes, and they cannot use non-static member variables or methods of external classes, because you can create static internal class objects without external class objects, conflicts may occur if you allow access to non-static members of the external class, because non-static members of external classes must be attached to specific objects.
Public class test {
Public static void main (string [] ARGs ){
Outter. Inner inner = newoutter. Inner ();}
}
Class outter {
Public outter (){
}
Static class inner {
Public inner (){
}
}
}
2. in-depth understanding of internal classes
1. Why can the internal class of a member unconditionally access members of an external class?
Before that, we have discussed that the internal class of a member can access members of an external class unconditionally,
So how exactly is it implemented?
The following describes how to decompile the bytecode file.
In fact, when the compiler is compiling,
The internal class of the member is compiled into a bytecode file. The Code of outter. Java is as follows:
Public class outter {
Private inner = NULL;
Public outter (){
}
Public inner getinnerinstance (){
If (inner = NULL ){
Inner = newinner ();
}
Return inner;
}
Protected class inner {
Public inner (){
}
}
}
After compilation, two bytecode files are displayed:
Decompile the outter $ inner. Class file to obtain the following information:
Content: Final com. cxh. test2.outterthis $0;
This line is a pointer to an external class object. You may be very surprised to see it here.
That is to say, the compiler adds a reference to an external Class Object to the member internal class by default,
How does this reference assign an initial value?
Next we will look at the constructor of the internal class:
Public com. cxh. test2.outter $ inner (COM. cxh. test2.outter );
It can be seen from this that, although the constructor of the defined internal class is a non-argument constructor,
The compiler adds a parameter by default. The parameter type is a reference pointing to an external class object,
Therefore, the outter this & 0 pointer in the member's internal class points to the external class object,
Therefore, you can freely access members of an external class in the member's internal class.
It also indirectly shows that the internal class of the member is dependent on the external class,
If no external class object is created, the outter this & 0 reference cannot be initialized and assigned a value,
In this case, you cannot create an object for the internal class of the member.
2. Why can only local final variables be accessed by local internal classes and anonymous internal classes?
Presumably, this issue has plagued many people. Before discussing this issue, let's take a look at the following code:
Public class test {
Public static void main (string [] ARGs ){
}
Public void test (final int B ){
Final int A = 10;
New thread (){
Public void run (){
System. Out. println ();
System. Out. println (B );
};
}. Start ();
}
}
This code is compiled into two class files: Test. Class and test1.class.
By default, the compiler names anonymous internal classes and local internal classes as outter1.class.
By default, the compiler name the anonymous internal class and local internal class outterx. Class (X is a positive integer ).
The anonymous internal class name in the test method is named test $1.
In the code, if any final before variables A and B is removed, this Code cannot be compiled.
Let's first consider the following question:
After the test method is executed, the lifecycle of variable A is over,
At this time, the life cycle of the thread object is likely not over yet,
Then it becomes impossible to continue accessing variable A in the thread run method, but to achieve this effect,
What should we do?
Java adopts the replication method to solve this problem.
Decompile the bytecode of this code to get the following content:
We can see that there is a command in the run method: Bi push 10
This command indicates that the number 10 is pushed to the stack, indicating that a local variable is used.
This process is performed by the compiler by default during compilation. If the value of this variable can be determined during compilation,
By default, the compiler will be in the constant pool of anonymous internal classes (Local internal classes ).
Add a literal with equal content or directly embed the corresponding bytecode into the execution bytecode.
In this way, the variable used by the anonymous internal class is another local variable,
The value is equal to the value of the local variable in the method, so it is completely independent from the local variable in the method.
Let's look at another example:
Public class test {
Public static void main (string [] ARGs ){
}
Public void test (final int ){
Newthread (){
Public void run (){
System. Out. println ();
};
}. Start ();
}
}
Decompilation:
The test $1 constructor in the anonymous internal class contains two parameters,
One is a reference to an external class object, and the other is an int variable,
Obviously, the form parameter A in the test method of the variable is passed in as a parameter to copy an anonymous internal class.
(Copy of variable A) for value assignment initialization.
That is to say, if the value of the local variable can be determined during compilation, a copy is directly created in the anonymous body.
If the value of the local variable cannot be determined during compilation, the copy is initialized and assigned by passing parameters by the constructor.
As shown above, variable a accessed in the run method is not a local variable A in the test method at all.
This solves the previously mentioned inconsistency in the lifecycle.
But a new problem arises,
Since the variable a accessed in the run method and the variable A in the test method are not the same variable,
What happens when the value of variable A is changed in the run method?
Yes, it will cause data inconsistency, so that the original intention and requirements are not met.
To solve this problem, the Java compiler restricts variable A to a final variable,
Variable A cannot be changed (for variables of the reference type, it is not allowed to point to new objects ),
In this way, the data inconsistency problem is solved.
At this point, we must be clear why the local variables and parameters in the method must be defined using final.
3. Is there anything special about the static internal class?
As we can see earlier, static internal classes do not depend on external classes,
That is to say, you can create an internal class object without creating an external class object. In addition, static internal classes do not hold references pointing to external class objects. This reader can decompile the class file by himself and check it. There is no reference to outter this & 0.
Iii. Use Cases and benefits of internal classes
Why Internal classes are required in Java? To sum up, there are four main points:
1. Each internal class can inherit the implementation of an interface independently,
Therefore, no matter whether the external class has inherited a certain (Interface) implementation, it has no impact on the internal class.
Internal classes make the multi-inheritance solution complete,
2. classes with certain logical relationships can be organized together and hidden from the outside world.
3. Easy to compile the event driver
4. Convenient thread code writing
The existence of internal classes makes Java's multi-Inheritance Mechanism more complete.
4. Common internal-related written examination questions
1. Enter the code at (1), (2), (3) According to the annotation.
Public class test {
Public static void main (string [] ARGs ){
// Initialize bean1 (1)
Bean1. I ++;
// Initialize bean2 (2)
Bean2.j ++;
// Initialize bean3 (3)
Bean3.k ++;
}
Class bean1 {
Public int I = 0;
}
Static class bean2 {
Public Int J = 0;
}
}
Class bean {
Class bean3 {
Public int K = 0;
}
}
We can see from the above that for the internal class of the member,
An instantiated object of an external class must be generated before an instantiated object of an internal class can be generated.
Static internal classes can generate instantiation objects of internal classes without the need to generate instantiation objects of external classes.
The general form of creating static internal class objects is:
External class name. Internal class name xxx = new external class name. Internal Class Name ()
The general form of creating a member's internal class object is:
External class name. Internal class name xxx = External Class Object Name. New internal class name ()
Therefore, the code at (1), (2), and (3) is:
1 test = newtest ();
Test. bean1 bean1 = test. newbean1 ();
2 test. bean2 b2 = test. bean2 ();
3 bean = new bean ();
Bean. bean3 bean3 = bean. New bean3 ();
2. What is the output result of the following code?
Public class test {
Public static void main (string [] ARGs ){
Outter = newoutter ();
Outter. New inner (). Print ();
}
}
Class outter {
Private int A = 1;
Class inner {
Private int A = 2;
Public void print (){
Int A = 3;
System. Out. println ("local variable:" + a); // 3
System. Out. println ("internal class variable:" + this. A); // 2
System. Out. println ("external class variable:" + outter. This. a); // 1
}
}
}
Result: 321
Last, I would like to add a bit of knowledge:
About the inheritance of internal classes of members.
Generally, internal classes are rarely used for inheritance.
But when used for inheritance, pay attention to two points:
1) the reference method of the member's internal class must be outter. Inner.
2) The constructor must have a reference pointing to an external Class Object and call Super () through this reference ().
This code is taken from Java programming thoughts.
Class withinner {
Class inner {
}
}
Class inheritinner extends withinner. Inner {
// Inheritinner () cannot be compiled. You must add the form parameter.
Inheritinner (withinnerwi ){
WI. Super (); // This call is required
}
Public static void main (string [] ARGs ){
Withinner Wi = new withinner ();
Inheritinner OBJ = new inheritinner (WI );
}
}
Internal supplementary content