Java internal class learning !!

Source: Internet
Author: User

Today, a student asked me a question that led to my research on internal classes in Java. This is his problem. I wrote an Stu class which contains an internal class student. There was no problem during compilation, But I encountered Java during runtime. lang. nosuchmethoderror student. setid (). However, this student class has no problem. Another problem is that it only exists on his computer and runs on other computers, so it is determined that the classpath of the environment variable has a problem. Finally, the problem is solved by changing the classpath, so that no error can be made during running.

But why is such an error? So I did some research on Java internal classes. However, the research results are based on others. People do write well, so they learned.

Tip:If you are not familiar with Java reflection, you can use the JD-GUI Java decompilation software, it can help you directly generate Java through The Decompilation generated. Class FileCodeTo help us understand the relationship between the internal class and the external class.

There are two internal classes:

(1) define a class in the class (private internal class, static internal class)

(2) define a class in the method (Local internal class, anonymous internal class)

1. Private internal class-internal class defined between methods, non-static

First, let's look at the two features of the internal class in the class:

(1) You can create any internal class object within the scope of the external class, even if the internal class is private (private internal class ). That is, the internal class is visible to the external class surrounding it.

Java code
    1. // Code 1: internal class externally visible
    2. ClassOuter {
    3. // Create a private internal Class Object
    4. PublicInner in =NewInner ();
    5. // Private internal class
    6. Private ClassInner {
    7. ...
    8. }
    9. }

(2) The internal class can access all the domains of its external class, even the private domain. That is, the external class is visible to the internal class.

Java code
  1. // Code 2: The External class is visible to the internal class
  2. ClassOuter {
  3. // External private data domains
  4. Private IntData =0;
  5. // Internal class
  6. ClassInner {
  7. VoidPrint (){
  8. // Internal class access to external private data domains
  9. System. Out. println (data );
  10. }
  11. }
  12. }

The question is: How do we implement the above two features? What happened to the "internal" of the internal class?

In fact, internal classes are implemented by the Java compiler. The virtual machine does not know what the internal class is different from the general class.How does the compiler block virtual machines?

After compiling the internal class, two class files are generated:Outer. ClassAndOuter $ inner. Class. This indicates that the inner class is still compiled into an independent class (outer $ inner. Class), rather than a field of the outer class.When a virtual machine is running, inner is also treated as a regular class.

But the question is, that is, why can they access each other's private domains (the first two internal class features mentioned )? This is to ask the compiler to compile the two classes into something.

We used the reflect reflection mechanism to explore the situation of internal classes after compilation (the code for exploring the internal mechanism of the class is provided in the following attachment reflect. Java ).

(1) compile code 1 to generate the outer $ inner. Class file and use reflectutil. Reflect ("outer $ inner") to reflect the inner of the internal class. Three hidden components are found in the running result:

Decompilation code
    1. // Decompilation1
    2. Class outer $ inner
    3. {
    4. Outer $ inner (outer, outer $ inner); // package visible Constructor
    5. Private outer $ inner (outer); // The private constructor sets this $0Domain
    6. Final outer this $0; // External class instance domain this $0
    7. }

 

Now we can explain the features of the first internal class above:Why Can external classes create internal class objects? And can internal classes easily reference external class objects?

First, the compiler compiles the external and internal classes and places them in the same package. Add a visible constructor to the internal class. In this way, the inner in = new inner () in the VM running outer class actually calls the visible structure of the package: New outer $ inner (this, null ). Therefore, even private internal classes, the constructor can successfully obtain the constructor permission of private internal classes through the implicit package visibility constructor.

In addition, the outer $ inner class has a reference this $0 pointing to the external class Outer. With this reference, you can easily obtain visible members in the external class object. But how are private members in the outer class accessed? Now let's look at the secrets in the outer. Class file below.

(2) compile code 2 to generate the outer. Class file, and then use reflectutil. Reflect ("outer") to reflect the external class outer. An implicit component is found in the running result as follows:

Decompilation code
    1. // Decompilation2
    2. Class Outer
    3. {
    4. Static int access $0(Outer); // static method. The returned value is the data value of the private domain of the external class.
    5. }

Now we can explain the second feature:Why can an internal class reference the private domain of an external class?

The key cause is that the compiler adds the static method access $0 to the peripheral class. It passes the returned value as a parameter to its object domain data. In this way, the print statement in the inner class is as follows:

System. Out. println (data );

Actually, what is called during running is:

S ystem. Out. println (this $0. Access $0 (outer ));

To sum up the compiler's practices for internal classes in the class:

(1) create a package visible constructor secretly in the internal class, so that the external class has the permission to create.

(2) create a static method to access private variables in the external class.EnableThe internal class has access permissions.

In this way, the internal class defined in the class can be accessed by its external class regardless of private, public, or static.

2. static internal class-internal class defined between methods, static

Internal classes also have static differences. This is the static internal class. Let's take a look at the Code:

Java code
  1. PackageHR. test;
  2. // Code 3: Reference of static internal classes to external variables
  3. Public ClassOuter {
  4. Private Static IntI =0;
  5. // Create a static internal Class Object
  6. PublicInner in =NewInner ();
  7. // Static
  8. Private Static ClassInner {
  9. Public VoidPrint (){
  10. System. Out. println (I );// If I is not a static variable, compilation fails.
  11. }
  12. }
  13. }

The biggest difference between a static internal class and a private internal class is that the static internal class cannot reference non-static members of its peripheral class. Why? Let's take a look at what happened in the static internal class Outer $ inner?

Decompilation code
    1. // Decompilation3
    2. Class outer $ inner
    3. {
    4. Private outer $ inner ();
    5. Outer $ inner (HR. Test. Outer $ inner );
    6. }

Compared with the previous private internal class decompilation 1, we found that a reference to the peripheral Class Object final outer this $0 was missing; that is to say, the static internal class cannot get reference to its peripheral class object, naturally, you cannot access non-static members of the peripheral class.Therefore, the static internal class can only access the static members of its peripheral class. In addition, there is no difference between the static internal class and the non-static internal class.

3. Local internal class-internal class defined in the Method

The internal class of the method also has two features:

(1) The internal class in the method does not have an access modifier, that is, the internal class of the method is invisible to anything other than the method surrounding it.

(2) The internal class of the method can only access the local variables in the method, so it is also called the local internal class. And these local variables must be final-modified constants.

Java code
  1. ClassOutter {
  2. Public VoidOutmethod (){
  3. Final IntBeep =0;
  4. ClassInner {
  5. // Use beep
  6. }
  7. Inner in =NewInner ();
  8. }
  9. }

 

Why?

(1) We first reflected the outter class and found that there was no hidden method to return the private domain in the outter.

(2) reflection on the inner class found that the inner class has an additional backup hidden domain for the beep variable: Final int Val $ I;

In this way, we can explain this backup common volume field in the inner class. First, when the JVM runs to the inner object that needs to be created, all the outter classes have been run, this mechanism is very likely to release the local variable beep. Where can I find the beep variable for the inner class?

The compiler helped us solve this problem again. He created a beep backup in the inner class.That is to say, even if the beep in the ouuter is recycled, there is a backup in the inner, so you are not afraid to find it.

But the problem comes again. If the beep In the outter keeps changing. Isn't it necessary to change the backup beep variable all the time.To keep the local variables consistent with the backup domain in the local internal class.The compiler has to specify that these local fields must be constants and cannot be changed once the value is assigned.

Therefore, the reason why the domain of the local internal class application external method must be a constant domain.

Summary of internal class features

(1) Non-static internal classes defined between methods:

● The peripheral class and internal class can access their own private members.

● Static member variables cannot be defined in internal classes.


(2) static internal classes defined between methods:

● Only static members of external classes can be accessed.


(3) Local internal classes defined in methods:

● This internal class does not have any access control permissions

● The peripheral class cannot see the local internal class in the method, but the local internal class can access any member of the peripheral class.

● The method body can access local internal classes, but the access statement must be after the local internal class is defined.

● A local internal class can only access constants in the method body, that is, members modified with final.


(4) Anonymous internal classes defined in methods:

● no constructor. Instead, the constructor parameter is passed to the superclass constructor.

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.