java foundation - Inner Class

Keywords: Java data structure

java foundation - Inner Class

1.1 non static internal class

   defining an internal class is very simple. Just put one class inside another. The "class interior" here includes any position in the class. Internal classes can be defined even in methods (the internal classes defined in methods are called local internal classes). The syntax format of the internal class definition is as follows:

public class OutClass {
	// Class and part classes are defined here
}

  most of the time, inner classes are defined as member inner classes, not as local inner classes. Member inner class is a class member similar to member variables, methods, constructors and initialization blocks; Local inner classes and anonymous inner classes are not class members.
   member inner classes are divided into two types: static inner classes and non-static inner classes. Member inner classes decorated with static are static inner classes, and member inner classes not decorated with static are non-static inner classes.
  because the inner class is a member of its outer class, you can use any access control characters, such as private, protected and public. The upper program unit of an external class is a package, so it has only two scopes: within the same package and anywhere. Therefore, only two kinds of access permissions are required: package access permission and public access permission, which correspond to omitting the access control character and public access control character. The omitted access control character is the package access right, that is, other classes in the same package can access the members of the omitted access control character. Therefore, if an external class does not use any access control modifier, it can only be accessed by other classes in the same package. The upper program unit of the internal class is the external class, which has four scopes: the same class, the same package, parent-child classes and any location. Therefore, four kinds of access control permissions can be used.
  the following program defines a non static inner class of CowLeg in the Cow class, and directly accesses the instance variable of Cow's private access permission in the instance method of CowLeg class.

public class Cow {
    private double weight;

    // Two overloaded constructors for external classes
    public Cow() {
    }

    public Cow(double weight) {
        this.weight = weight;
    }

    // Define a non static inner class
    private class CowLeg {
        // Two instance variables of a non static inner class
        private double length;
        private String color;

        // Two overloaded constructors of non static inner classes
        public CowLeg() {
        }

        public CowLeg(double length, String color) {
            this.length = length;
            this.color = color;
        }

        // The setter and getter methods of length and color are omitted below
        public void setLength(double length) {
            this.length = length;
        }

        public double getLength() {
            return this.length;
        }

        public void setColor(String color) {
            this.color = color;
        }

        public String getColor() {
            return this.color;
        }

        // Instance method of non static inner class
        public void info() {
            System.out.println("The current corbel color is:"
                    + color + ", Height:" + length);
            // Direct access to private decorated member variables of external classes
            System.out.println("The weight of the cow where the leg is located:" + weight);   // ①
        }
    }

    public void test() {
        CowLeg cl = new CowLeg(1.12, "Black and white");
        cl.info();
    }

    public static void main(String[] args) {
        Cow cow = new Cow(378.9);
        cow.test();
    }
}

  the CowLeg class in the above program is a common class definition, but because this class definition is placed inside another class, it becomes an internal class. You can use the private modifier to modify this class.
  the external class Cow contains a test() method, which creates a CowLeg object and calls the info() method of the object. It is not difficult for readers to find that using non static internal classes in external classes is not much different from using ordinary classes.
   after compiling the above program, you can see that two class files are generated in the path of the file, one is Cow.class, and the other is Cow$CowLeg.class. The former is the class file of the external class Cow, and the latter is the class file of the internal class CowLeg, that is, the internal class of the member (including static internal class and non static internal class) The class file is always in this form: OuterClass$InnerClass.class.
   as mentioned earlier, you can directly access the private members of the external class in the non static internal class. In the above program, System.out.println("the cow weight of this corbel:" + weight)// ① Code is to directly access the private instance variable of its external class in the method of CowLeg class. This is because in the non static internal class object, a reference to the parasitic external class object is saved (when calling the instance method of the non static internal class, there must be a non static internal class instance, and the non static internal class instance must be parasitic in the external class instance). The following figure shows the memory diagram when the above program runs.

   when accessing a variable in the method of a non static internal class, the system gives priority to finding out whether there is a local variable with that name in the method, and if so, use the variable; If it does not exist, go to the internal class where the method is located to find out whether there is a member variable with that name. If so, use the member variable; If it does not exist, find out whether there is a member variable with this name in the external class where the internal class is located. If so, use the member variable; If     still does not exist, a compilation error will appear: prompt that the variable cannot be found.
Therefore, if the external class member variable and the internal class member variable have the same name as the local variable of the method in the internal class, they can be distinguished by using this and the external class name. This as qualifications. The following procedure is shown.

public class DiscernVariable {
    private String prop = "Instance variables of external classes";

    private class InClass {
        private String prop = "Instance variable of inner class";

        public void info() {
            String prop = "local variable";
            // Access the external class instance variable through the external class class name. this.varName
            System.out.println("Instance variable value of external class:" + DiscernVariable.this.prop);
            // Access the variables of the inner class instance through this.varName
            System.out.println("Instance variable value of inner class:" + this.prop);
            // Direct access to local variables
            System.out.println("Value of local variable:" + prop);
        }
    }

    public void test() {
        InClass in = new InClass();
        in.info();
    }

    public static void main(String[] args) {
        new DiscernVariable().test();
    }
}

  System.out.println("instance variable value of external class:" + DiscernVariable.this.prop) in the above program; Code and System.out.println("instance variable value of inner class:" + this.prop); Access instance variables of external classes and instance variables of non static internal classes respectively. Access the instance variable of the external class in the form of OuterClass.this.propName, and access the instance variable of the non static internal class in the form of this.propName.
  members of non static internal classes can access instance members of external classes, but the reverse is not true. If an external class needs to access instance members of a non static internal class, you must explicitly create a non static internal class object to call to access its instance members. The following procedure demonstrates this rule.

public class Outer {
    private int outProp = 9;

    class Inner {
        private int inProp = 5;

        public void accessOuterProp() {
            // Non static inner classes can directly access private instance variables of outer classes
            System.out.println("External class outProp value:" + outProp);
        }
    }

    public void accessInnerProp() {
        // External classes cannot directly access instance variables of non static internal classes,
        // The following code has a compilation error
         System.out.println("Inner class inProp value:" + inProp);
        // To access an instance variable of an inner class, you must explicitly create an inner class object
        System.out.println("Inner class inProp value:" + new Inner().inProp);
    }

    public static void main(String[] args) {
        // Execute the following code, only the external class object has been created, and the internal class object has not been created
        Outer out = new Outer();      // ①
        out.accessInnerProp();
    }
}

   the reason why external classes are not allowed to access instance members of non static internal classes is that Outer out = new Outer() of main() method in the above program; The code creates an external class object and calls the accessinnerprop () method of the external class object. At this time, the non static internal class object does not exist at all. If the accessInnerProp() method is allowed to access the instance members of the non static internal class, it will certainly cause an error.
  according to the rule that static members cannot access non static members, static methods and static code blocks of external classes cannot access non static internal classes, including non static internal classes cannot be used to define variables and create instances. In short, non static inner classes are not allowed to be used directly in static members of external classes. The following procedure is shown.

public class StaticTest {
    // Define a non static inner class, which is an empty class
    private class In {
    }

    // Static methods of external classes
    public static void main(String[] args) {
        // The following code throws a compilation exception because of the static member (main() method)
        // Cannot access non static member (In class)
        new In();
    }
}

  Java does not allow static members to be defined in non static inner classes. The following program demonstrates that the inclusion of static members in a non static inner class will cause a compilation error.

public class InnerNoStatic {
    private class InnerClass {
        /*
        The following three static declarations will cause the following compilation errors:
        A non static inner class cannot have a static declaration
        */
        static {
            System.out.println("==========");
        }

        private static int inProp;

        private static void test() {
        }
    }
}

ps: non static internal classes cannot have static initialization blocks, but can contain ordinary initialization blocks. The function of non static internal class ordinary initialization block is exactly the same as that of external class initialization block.

1.2 static internal class

  if you use static to decorate an inner class, the inner class belongs to the outer class itself, not an object of the outer class. Therefore, the inner class decorated with static is called class inner class, which is also called static inner class in some places.
The   static keyword is used to change the members of a class into class related rather than instance related, that is, the members modified by static belong to the whole class rather than a single object. The upper level program unit of an external class is a package, so static modification cannot be used; The upper program unit of the internal class is the external class. Using static modification, the internal class can become related to the external class rather than the external class instance. Therefore, the static keyword cannot modify an external class, but it can modify an internal class.
  static inner classes can contain static members or non static members. According to the rule that static members cannot access non static members, static internal classes cannot access instance members of external classes, but only class members of external classes. Even the instance method of the static inner class cannot access the instance members of the outer class, but only the static members of the outer class. The following program demonstrates this rule.

public class StaticInnerClassTest {
    private int prop1 = 5;
    private static int prop2 = 9;

    static class StaticInnerClass {
        // Static inner classes can contain static members
        private static int age;

        public void accessOuterProp() {
            // An error occurred in the following code:
            // Static inner classes cannot access instance variables of outer classes
//			System.out.println(prop1);
            // The following code is normal
            System.out.println(prop2);
        }
    }
}

Why can't instance methods of static internal classes access instance properties of external classes? - > Because the static inner class is related to the class of the outer class, not the object of the outer class. In other words, the static internal class object is not parasitic in the instance of the external class, but in the class itself of the external class. When the static internal class object exists, there is no external class object parasitized by it. The static internal class object only holds the class reference of the external class and does not hold the reference of the external class object. If the instance method of the static inner class is allowed to access the instance member of the outer class, but the parasitic outer class object cannot be found, this will cause an error.

   static inner class is a static member of external class. Therefore, static inner class can be used in all methods and initialization blocks of external class to define variables, create objects, etc.
    the external class still cannot directly access the members of the static internal class, but you can use the class name of the static internal class as the caller to access the class members of the static internal class, or you can use the static internal class object as the caller to access the instance members of the static internal class. The following procedure demonstrates this rule.

public class AccessStaticInnerClass {
    static class StaticInnerClass {
        private static int prop1 = 5;
        private int prop2 = 9;
    }

    public void accessInnerProp() {
//		System.out.println(prop1);
        // There is an error in the above code, which should be changed to the following form:
        // Class members of static inner classes are accessed by class names
        System.out.println(StaticInnerClass.prop1);
//		System.out.println(prop2);
        // There is an error in the above code, which should be changed to the following form:
        // Access instance members of static inner classes through instances
        System.out.println(new StaticInnerClass().prop2);
    }
}

   in addition, Java also allows defining internal classes in the interface. The internal classes defined in the interface are decorated with public static by default, that is, the internal classes of the interface can only be static internal classes. If you specify an access control character for an interface internal class, you can only specify a public access control character; If the access control character is omitted when defining an interface internal class, the internal class defaults to public access control permission.

1.3 local internal class

  if an inner class is defined in a method, the inner class is a local inner class, which is only valid in the method. Since local inner classes cannot be used outside the methods of external classes, local inner classes cannot be decorated with access control characters and static modifiers.
  for local members, whether they are local variables or local internal classes, their upper level program units are methods, not classes. It is meaningless to use static to modify them. Therefore, all local members cannot be decorated with static. Moreover, because the scope of local members is the method, other program units can never access local members in another method, so all local members cannot be modified with access control characters.
  if you need to define variables, create instances or derive subclasses with local inner classes, you can only do so in the method where the local inner class is located.

public class LocalInnerClass {
    public static void main(String[] args) {
        // Define local inner classes
        class InnerBase {
            int a;
        }
        // Defines a subclass of a local inner class
        class InnerSub extends InnerBase {
            int b;
        }
        // Create an object of a local inner class
        InnerSub is = new InnerSub();
        is.a = 5;
        is.b = 8;
        System.out.println("InnerSub Object a and b The instance variables are:" + is.a + "," + is.b);
    }
}

   after compiling the above program, you can see that three class files are generated: LocalInnerClass.class, LocalInnerClass InnerBase.class and LocalInnerClass InnerSub.class, which indicates that the class files of local internal classes always follow the following naming format: OuterClass$NInnerClass.class. Note that the file name of the class file of the local internal class is one more number than the file name of the class file of the member internal class, because it is impossible to have two member internal classes with the same name in the same class, while there may be more than two local internal classes with the same name in the same class (in different methods), Therefore, Java adds a number to the class file name of the local internal class to distinguish.
  local internal class is a very "chicken rib" syntax. It is rarely defined in actual development because the scope of local internal class is too small: it can only be used in the current method. Most of the time, after defining a class, of course, you want to reuse the class many times, but the local internal class cannot leave its method. Therefore, the local internal class is rarely used in actual development.

1.4 anonymous inner class

  anonymous inner classes are suitable for creating classes that only need to be used once, such as the Command object required when the Command mode is introduced earlier. The syntax of anonymous inner class is a little strange. When creating an anonymous inner class, an instance of the class will be created immediately, and the class definition will disappear immediately. Anonymous inner classes cannot be reused.
   the format of defining anonymous inner classes is as follows:

new Implementation interface() | Parent constructor(Argument list)
{
	The body part of an anonymous inner class
}

  as can be seen from the above definition, an anonymous inner class must inherit a parent class or implement an interface, but can only inherit a parent class or implement an interface at most.
  there are two other rules about anonymous inner classes.
    anonymous inner class cannot be an abstract class, because when the system creates an anonymous inner class, the object of the anonymous inner class will be created immediately. Therefore, anonymous inner classes are not allowed to be defined as abstract classes.
    anonymous inner classes cannot define constructors. Since the anonymous inner class does not have a class name, the constructor cannot be defined, but the anonymous inner class can define an initialization block, which can be used to complete what the constructor needs to do through the instance initialization block.
  the most common way to create an anonymous inner class is to create an object of an interface type, as shown in the following program.

interface Product {
    double getPrice();
    String getName();
}

public class AnonymousTest {
    public void test(Product p) {
        System.out.println("Bought one" + p.getName() + ",It's gone" + p.getPrice());
    }

    public static void main(String[] args) {
        AnonymousTest ta = new AnonymousTest();
        // When calling the test() method, you need to pass in a Product parameter,
        // Pass in an instance of its anonymous implementation class here
        ta.test(new Product() {
            public double getPrice() {
                return 567.8;
            }

            public String getName() {
                return "AGP Graphics card";
            }
        });
    }
}

    the AnonymousTest class in the above program defines a test() method, which requires a Product object as a parameter, but Product is only an interface and cannot be created directly. Therefore, consider creating an object of the Product interface implementation class and passing it in this method - if the Product interface implementation class needs to be reused, The implementation class should be defined as a separate class; If the Product interface implementation class only needs to be used once, you can define an anonymous inner class in the way in the above program.
As you can see in the above program, the class keyword is not required to define an anonymous inner class, but the object of the anonymous inner class is directly generated when defining an anonymous inner class. above

       public double getPrice() {
           return 567.8;
       }

       public String getName() {
           return "AGP Graphics card";
       }

The code part is the class body part of the anonymous inner class.
  since anonymous inner classes cannot be abstract classes, anonymous inner classes must implement all abstract methods contained in their abstract parent classes or interfaces.
  when creating an anonymous inner class, you must implement all abstract methods in the interface or abstract parent class. If necessary, you can override the normal methods in the parent class.
   before Java 8, Java required that local variables accessed by local internal classes and anonymous internal classes must use final modification. Starting from Java 8, this restriction has been removed, and Java 8 is more intelligent: if local variables are accessed by anonymous internal classes, the local variables are equivalent to automatically using final modification. For example, the following procedure.

interface A {
    void test();
}

public class ATest {
    public static void main(String[] args) {
        int age = 8;     // ①
        // The following code will cause compilation errors
        // Since the age local variable is accessed by an anonymous inner class, age is equivalent to being modified by final
		age = 2;
        A a = new A() {
            public void test() {
                // Before Java 8, the following statement will prompt an error: age must use the final modifier
                // Starting from Java 8, anonymous inner classes and local inner classes allow access to non final local variables
                System.out.println(age);
            }
        };
        a.test();
    }
}

   JDK of java version 8 and later calls this function "effectively final", which means that local variables accessed by anonymous internal classes can be modified with or without final modification, but they must be used in the way of final modification - that is, after one assignment, they cannot be re assigned in the future.

1.5 using internal classes

  the main function of defining a class is to define variables, create instances and inherit as a parent class. The main function of defining internal classes is the same, but there are some small differences between using internal classes to define variables and create instances and external classes. The usage of inner classes is discussed in three cases.

1. Use the inner class inside the outer class

    as can be seen from the previous program, there is no big difference between using the internal class inside the external class and using the ordinary class. Similarly, variables can be defined directly through the internal class name, and instances can be created by calling the internal class constructor through new.
   the only difference is: do not use non static inner classes in static members of external classes (including static methods and static initialization blocks), because static members cannot access non static members.
  defining a subclass of an internal class inside an external class is not much different from defining a subclass normally.

2. Use a non static inner class outside the outer class

  if you want to access the internal class (including static and non-static) outside the external class, the internal class cannot use private access control permission, and the internal class modified by private can only be used inside the external class. Internal classes decorated with other access control characters can be used within the access permissions corresponding to the access control characters.
                      .
The inner class decorated with protected can be accessed by other classes and subclasses of the outer class in the same package as the outer class.
The internal class decorated with public can be accessed anywhere.
    the syntax format of defining internal class (including static and non-static) variables outside the external class is as follows:

Outerclass.Innerclass varname

   since the objects of non static internal classes must be parasitic in the objects of external classes, the external class objects must be created before creating non static internal class objects. The syntax for creating a non static internal class instance outside the external class is as follows:

outerinstance.new Innerconstructor()

  as can be seen from the above syntax format, to create a non static internal class instance outside the external class, you must use the external class instance and new to call the constructor of the non static internal class. The following program demonstrates how to create an object of a non static inner class outside the outer class and assign it to a variable of a non static inner class type.

class Out {
    // Define an internal class without using access control characters,
    // That is, only other classes in the same package can access the internal class
    class In {
        public In(String msg) {
            System.out.println(msg);
        }
    }
}

public class CreateInnerInstance {
    public static void main(String[] args) {
        Out.In in = new Out().new In("Test information");
		/*
		The above code can be changed to the following three lines of code:
		Define internal class variables in the form of OuterClass.InnerClass
		Out.In in;
		Create an external class instance in which the non static internal class instance will be hosted
		Out out = new Out();
		Create a non static internal class instance by calling the internal class constructor through the external class instance and new
		in = out.new In("Test information ");
		*/
    }
}

  the bold code line in the above program creates a non static internal class object. As can be seen from the above code, the constructor of a non static internal class must be called with an external class object.
   if you need to create subclasses of non static internal classes outside the external class, pay particular attention to the above rule: the constructor of non static internal classes must be called through its external class object.
   when creating a subclass, the subclass constructor always calls the constructor of the parent class. Therefore, when creating a subclass of a non-static internal class, it must be ensured that the subclass constructor can call the constructor of a non-static internal class. When calling the constructor of a non-static internal class, it must exist In an external class object. The following program defines a subclass that inherits the non static inner class of the Out class and the In class.

public class SubClass extends Out.In {
    //Displays the constructor that defines the SubClass
    public SubClass(Out out) {
        //Explicitly call the constructor of In through the passed In Out object
        out.super("hello");
    }
}

  as can be seen from the above code, if you need to create a SubClass object, you must first create an Out object. This is reasonable because SubClass is a SubClass of the non static inner class In class. There must be a reference to the Out object In the non static inner class In object, and its SubClass subclass object should also hold a reference to the Out object. When creating a SubClass object, the Out object passed to the constructor is the object pointed to by the Out object reference In the SubClass object.
   both the non static inner class In object and the SubClass object must hold references to the Outer object. The difference is that when creating the two objects, the Out object is passed In in different ways: when creating the object of the non static inner class In class, the new keyword must be called through the Outer object; When creating an object of a SubClass class, you must use the Outer object as the caller to call the constructor of the In class.
    like the subclass instance of a non static inner class, it is necessary to retain a reference that points to the object of the outer class where its parent class is located. That is, if an object of an inner class subclass exists, there must be an outer class object corresponding to it.

3. Use a static inner class outside the outer class

  because static inner classes are related to external classes, there is no need to create external class objects when creating static inner class objects. The syntax for creating a static internal class instance outside the external class is as follows:

new Outerclass.Innerconstructor()

  the following program demonstrates how to create an instance of a static inner class outside the outer class.

class StaticOut {
    // Define a static internal class without using access control characters,
    // That is, other classes in the same package can access the internal class
    static class StaticIn {
        public StaticIn() {
            System.out.println("Constructor of static inner class");
        }
    }
}

public class CreateStaticInnerInstance {
    public static void main(String[] args) {
        StaticOut.StaticIn in = new StaticOut.StaticIn();
		/*
		The above code can be changed into the following two lines of code:
		Define internal class variables in the form of OuterClass.InnerClass
		StaticOut.StaticIn in;
		Use new to call the inner class constructor to create a static inner class instance
		in = new StaticOut.StaticIn();
		*/
    }
}

  as can be seen from the above code, the syntax for declaring variables is exactly the same for both static internal classes and non static internal classes. The difference is that when creating an internal class object, the static internal class only needs to use the external class to call the constructor, while the non static internal class must use the external class object to call the constructor.
  because there is no need to use an external class object when calling the constructor of the static internal class, it is relatively simple to create a subclass of the static internal class. The following code defines an empty subclass for the static internal class StaticIn class.

public class Staticsubclass extends Staticout.Staticin {}

  as can be seen from the above code, when defining a static internal class, its external class is very much like a package space.

Posted by duelist on Thu, 18 Nov 2021 21:54:10 -0800