Java: internal class
What is an internal class? An internal class refers to defining another class within an external class. An internal class is a member of an external class and is attached to an external class. Internal classes can be static and can be modified using protected and private (while external classes can only use public and default package access permissions ). Internal classes mainly include the following types: member Internal classes, partial internal classes, static internal classes, and anonymous internal classes (1). Internal classes are still independent classes, after compilation, internal classes are compiled into independent classes. class file, but with the class name and $ symbol of the external class. (2) Internal classes cannot be accessed in normal mode. (3) When the internal class is declared static, you cannot access the member variables of the external class. In this case, the internal class can only access the static member variables of the external class. (4) External classes cannot directly access members of internal classes, but internal classes can be accessed through internal class objects, therefore, the internal class can freely access the member variables of the external class, whether it is private or not. Because when an internal class object is created for a peripheral class object, this internal class will capture an implicit reference, which references the peripheral class object that instantiates the internal class object. This pointer can be used to access all States of peripheral class objects. By decompiling the bytecode of the internal class, the analysis is mainly performed in the following steps: 1. the compiler automatically adds a member variable to the internal class, the member variable has the same type as the external class. This member variable is a reference to the external Class Object. 2 The Compiler automatically adds a parameter to the internal class constructor, the parameter type is the type of the external class. In the constructor, use this parameter to assign values to the member variables added in 1. 3. When you call the constructor of an internal class to initialize an internal class object, the external class reference is passed in by default. Why Internal classes? The main reasons are as follows: internal class methods can access the data in the scope of the class definition, including private data internal classes can be hidden from other classes in the same package, generally, non-Internal classes do not allow private and protected permissions, but internal classes can implement multiple inheritance. When you want to define a callback function and do not want to write a large amount of code, the most attractive reason for using anonymous internal classes is that each internal class can be independently inherited from one (Interface) implementation, therefore, no matter whether the peripheral class has inherited a certain (Interface) implementation, it has no impact on the internal class. We all know that Java can only inherit one class. Its Multi-inheritance is implemented using interfaces before we learn internal classes. But sometimes there are a lot of inconveniences when using interfaces. For example, we must implement all the methods in an interface. The internal classes are different. It can make our class inherit from multiple concrete classes or abstract classes. Let's take a look at the following example: copy the code public class Example1 {public String name () {return "liutao" ;}} public class Example2 {public int age () {return 25 ;}} public class MainExample {private class test1 extends Example1 {public String name () {return super. name () ;}} private class test2 extends Example2 {public int age () {return super. age () ;}} public String name () {return new test1 (). name ();} public int age () {re Turn new test2 (). age ();} public static void main (String args []) {MainExample mi = new MainExample (); System. out. println ("name:" + mi. name (); System. out. println ("Age:" + mi. age () ;}} copy the internal class of the code member: the internal class directly defined in a class. The internal class of the Member is no different from that of the common member, it can be modified and restricted like common members. The internal class of the Member cannot contain static variables and methods. 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 () {} // The internal class of the Member cannot define the static member. // The internal class of the member can access all the members of the External class. class Inner {// static int inner_ I = 100; // The internal class cannot define the static variable int j = 100; // instance variables of the internal class and the external class can coexist int inner_ I = 1; void inner_f1 () {System. out. println (I); // directly use the variable name System to access the internal class's own variables. out. println (j); // access the internal class itself in the internal class You can also use this. variable name: System. out. println (this. j); // access instance variables with the same name as the internal class in the internal class using the external class name. this. variable name: System. out. println (Outer. this. j); // if the internal class does not have a variable with the same name as the external class, you can directly use the variable name to access the external class variable System. out. println (k); outer_f1 (); outer_f2 () ;}// non-static method of the external class to access the internal class public void outer_f3 () of the member () {Inner inner = new Inner (); inner. inner_f1 ();} // static method of the external class to access the internal class of the member, the same as the internal class of the external class to access the internal class of the external class, public static void outer_f4 () {// Step 1: Create an external Class Object Outer out = new Outer (); // Step 2: create an internal Class Object Inner inner = out based on the external class object. new Inner (); // Step 3: Access the inner method of the internal class. inner_f1 ();} public static void main (String [] args) {// outer_f4 (); // The output result of this statement is the same as the output result of the following three statements // If You Want To directly create an internal class object, you cannot take it for granted that you only need to add the Outer name of the peripheral class, // you can generate an internal class object as usual, but you must use an object of this peripheral class. // create an object of its internal class: // Outer. inner outin = out. new Inner () // Therefore, unless you already have an object of the peripheral class, it is impossible to generate an object of the internal class. Because this // internal class object will quietly link to the object that creates its peripheral class. If you are using a static internal class, // you do not need to reference its peripheral class object. Outer out = new Outer (); Outer. inner outin = out. new Inner (); outin. inner_f1 () ;}} local internal class: the internal class defined in the method is called a local internal class. Similar to local variables, the local internal class cannot have access specifiers because it is not part of the peripheral class, but it can access constants in the current code block and all members of this peripheral class. Note: (1) the internal class of a method can only be instantiated within the method that defines the internal class. It cannot be instantiated outside of this method. (2) internal class objects of a method cannot use non-final local variables of the method of the internal class. For specific reasons, let's talk about 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; // class Inner {int s = 300; // variables with the same name as external classes can be defined // static int m = 20; // static variables Inner (int k) {inner_f (k) cannot be defined );} int inner_ I = 100; void inner_f (int k) {// if the internal class does not have a variable with the same name as the external class, you can directly access the instance variable System of the external class in the internal class. out. println (out_ I); // you can access the local variables of the external class (that is, the variables in the method ), But the variable must be the final System. out. println (j); // System. out. println (I); // if the internal class has a variable with the same name as the external class, the internal class variable System is accessed directly with the variable name. out. println (s); // use this. the variable name accesses the internal class variable System. out. println (this. s); // use the external class name. this. the internal class variable name accesses the external class variable System. out. println (Outer. this. s) ;}} new Inner (k);} public static void main (String [] args) {// to access a local internal class, you must first have an external Class Object Outer out = new Outer (); out. f (3) ;}} static internal class (nested class): If you do not need to associate an internal class object with its peripheral class object, you can set the internal class Declared as static. This is usually called a nested class ). To understand the meaning of static when applied to an internal class, you must remember that a reference is implicitly saved for a common internal class object, pointing to the peripheral Class Object for creating it. However, this is not the case when the internal class is static. Nested class means: 1. To create an object of the nested class, you do not need the object of its peripheral class. 2. Non-static peripheral class objects cannot be accessed from nested class objects. Public class Outer {private static int I = 1; private int j = 10; public static void outer_f1 () {} public void outer_f2 () {} // static internal classes can be modified using public, protected, and private. // static internal classes can be defined as static or non-static members. private static class Inner {static int inner_ I = 100; int inner_j = 200; static void inner_f1 () {// The static internal class can only access static members of the external class (including static variables and static methods) System. out. println ("Outer. I "+ I); outer_f1 ();} void inner_f2 () {// The static internal class cannot be accessed. Non-static members of the external class (including non-static variables and non-static methods) // System. out. println ("Outer. I "+ j); // outer_f2 () ;}} public void outer_f3 () {// static members of the internal class accessed by the external class: internal class. static member System. out. println (Inner. inner_ I); Inner. inner_f1 (); // non-static members of the internal class accessed by the external class: instantiate the internal class to Inner inner = new Inner (); inner. inner_f2 ();} public static void main (String [] args) {new Outer (). outer_f3 () ;}} generates a static internal class without external class members: this is the difference between the static internal class and the member internal class. Objects of static internal classes can be directly generated: Outer. Inner in = new Outer. Inner (), instead of generating external class objects. In this way, the static internal class is actually a top-level class (normally, you cannot place any code inside the interface, but the nested class can be part of the interface because it is static. Only place the nested class in the interface namespace, which does not violate the interface rules.) Anonymous internal class: Simply put, an anonymous internal class is an internal class without a name. Under what circumstances do I need to use an anonymous internal class? If the following conditions are met, it is appropriate to use an anonymous internal class: only one instance of the class is used. Class is used immediately after definition. The class is very small (SUN recommends following four lines of code). Naming the class will not make your code easier to understand. When using anonymous internal classes, remember the following principles: anonymous internal classes cannot have constructor methods. Anonymous internal classes cannot define any static members, methods, and classes. Anonymous internal classes cannot be public, protected, private, or static. Only one instance of the anonymous internal class can be created. An anonymous internal class must be behind new, and uses it to implicitly implement an interface or implement a class. Because the anonymous internal class is a local internal class, all restrictions on the local internal class take effect. The following code shows how to copy the code public class Parcel7 {public Wrapping wrap (int x) If your base class needs a constructor with parameters) {// 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) ;}} to copy the code, simply pass the appropriate parameters to the base class constructor. Here, x is passed to new Wrapping (x ). The semicolon at the end of an anonymous internal class is not used to mark the end of this internal class (in C ++ ). In fact, it marks the end of the expression, but this expression exactly contains the internal class. Therefore, this is consistent with the semicolon used elsewhere. If you define a member variable in an anonymous class or use a constructor with parameters, you can also perform initialization operations on it: copy the public class Parcel8 {// Argument must be final to use inside // anonymous inner class: public Destination dest (final String name, String city) {return new Destination (name, city) {private String label = name; public String getName () {return label ;};} public static void main (String [] args) {Parcel8 p = new Parcel8 (); Destination d = p. dest ("Tan Zania "," gz ");} abstract class Destination {Destination (String name, String city) {System. out. println (city) ;}abstract String getName () ;}copy the code. Note that the parameter city is not directly used by anonymous internal classes, it is used by the constructor of the abstract class Inner, so it does not need to be defined as final. Overload of internal classes if you create an internal class, inherit its peripheral class, and redefine the internal class, what will happen? That is to say, can internal classes be overloaded? This seems to be a very useful idea, but the "overload" internal class is like it is a method of the peripheral class, in fact, it does not play any role: copy the code 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 () ;}} copy the code output result New Egg () Egg. Yolk () the default constructor is automatically generated by the compiler. Here is the default constructor that calls the base class. You may think that since the BigEgg object is created, the Yolk used should be "overloaded", but you can see from the output that the actual situation is not like this. This example shows that when you inherit a peripheral class, the internal class has not changed significantly. These two internal classes are two completely independent entities, each in their own namespace. Of course, it is also possible to inherit an internal class explicitly: copy the code 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 {pub Lic 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 code is: Egg2.Yolk () New Egg2 () Egg2.Yolk () BigEgg2.Yolk () BigEgg2.Yolk. f () Now BigEgg2.Yolk explicitly inherits this internal class through the extends Egg2.Yolk and reloads the methods in it. The insertYolk () method of Egg2 enables BigEgg2 to transform its own Yolk object upwards and then transmit it to reference y. Therefore, when g () calls y. f (), the new version of f () after the overload is executed. The second call to Egg2.Yolk () is the BigEgg2.Yolk constructor that calls its base class constructor. We can see that the new f () is called when g () is called. The internal class inheritance problem is that the internal class constructor needs to use the reference of its peripheral Class Object. Therefore, when you inherit an internal class, it becomes a little complicated. The problem is that the reference of the "secret" peripheral class object must be initialized, but there is no default object to be connected in the inherited class. To solve this problem, we need to use special syntax to clarify the associations between them: copy the code class WithInner {class Inner {Inner () {System. out. println ("this is a constructor in WithInner. inner ") ;};}} public class InheritInner extends WithInner. inner {//! InheritInner () {}// Won't compile InheritInner (WithInner wi) {wi. super (); System. out. println ("this is a constructor in InheritInner");} public static void main (String [] args) {WithInner wi = new WithInner (); inheritInner ii = new InheritInner (wi) ;}} copy the code and the output result is: this is a constructor in WithInner. innerthis is a constructor in InheritInner. As you can see, InheritInner only inherits from internal classes, not peripheral classes. However, to generate a constructor, the default constructor is not good, and you cannot just pass a reference pointing to a peripheral class object. In addition, you must use the following syntax in the constructor: enclosingClassReference. super (); to provide necessary references before the program can be compiled. Why can't non-static internal classes have static attributes but constants? For example, public class InnerClassDemo {int x; class A {static int a = 0; // The write is invalid. static final int B = 0; // This write is legal} defines a static domain or method, which must be in a static or top-level environment, that is, if static class A is added into A static internal class, the non-static internal class depends on an external class object, static domains/methods do not depend on objects-they are only related to classes (specifically, when loading static domains, there is no external class object at all). Therefore, static domains/methods cannot be defined in non-static internal classes and cannot be compiled. The constant can be (whether static or not), Because java determines all constants during the compilation period and puts them in the so-called constant pool. The mechanism of constants is different from that of common variables.