Deep understanding of Java: internal class, deep understanding of Java:

Source: Internet
Author: User

Deep understanding of Java: internal class, deep understanding of Java:

Notes for learning Java !!!

If you have any questions or want to obtain learning resources during the learning process, join the Java learning exchange group with the group number 618528494.Let's learn Java together!

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:ChengEmployeeInternalClass, Local internalClass, JingStatusInternalClassAnonymous internalClass

Commonalities of internal classes

(1) The internal class is still an independent class. After compilation, the internal class will be compiled into an independent. class file, but it is preceded by 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 they can be accessed through internal class objects.

 

An internal class is a member of an external class, so 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 internal class bytecode, the analysis is mainly done through 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 constructor of the internal class. The parameter type is the type of the external class. In the constructor, assign a value to the member variable added in 1;
3. When the internal class constructor is called to initialize the internal class object, the reference of the external class is passed in by default.

Why Internal classes?

The main reasons are as follows:

  • Internal class methods can access the data of 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

  • But implement multi-Inheritance

  • It is easier to use anonymous internal classes 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 internal classes is:

Each internal class can inherit from one (Interface) implementation independently, so no matter whether the peripheral class has inherited a (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:

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 () {return 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 ());}}
Member internal class:

That is, an internal class directly defined in a class. The internal class of a Member is no different from that of a common member. It can be modified and restricted like a common member. 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's own 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 O Uter (); // 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 that:

(1) The internal class of a method can only be instantiated within the method that defines the internal class. It cannot be instantiated outside the method.

(2) internal class objects of a method cannot use non-final local variables of the method of the internal class.

Wait for the specific reason.

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 in the internal class Inner {int s = 300; // variable with the same name as the external class can be defined // static int m = 20; // The static variable Inner (int k) {inner_f (k);} int inner_ I = 100; void inner_f (int k) cannot be defined) {// 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 variables must be 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 declare the internal class 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 classes mean:

1. To create nested class objects, you do not need the objects 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 access 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 ();}}

Generating a static internal class does not require 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: in short, 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 a class does not make your code easier to understand.
When using anonymous internal classes, remember the following principles:
  • No constructor is allowed for anonymous internal classes.

  • 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 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 constructors of the base class. 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:
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("Tanzania", "gz");    }    abstract class Destination {        Destination(String name, String city) {            System.out.println(city);        }        abstract String getName();    }}
Note that the city parameter is not directly used by the anonymous internal class, but 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:
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 result is: the default constructor of New Egg () Egg. Yolk () is automatically generated by the compiler. The default constructor of the base class is called here. 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:
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();       }}
Output result: 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:
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);        }}
The output result is: this is a constructor in WithInner. Innerthis is a constructor in InheritInner. You can see that 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 }}

Defining A static domain or method requires the static environment or the top-level environment. That is, if static class A is added and becomes 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.

Notes for learning Java !!!

If you have any questions or want to obtain learning resources during the learning process, join the Java learning exchange group with the group number 618528494.Let's learn Java together!

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.