Java internal class

Source: Internet
Author: User
Tags date now

Java internal class

This article is a summary of the interfaces and internal classes in Chapter 6 of Java core technology volume 1.

Inner class in Java is a class defined in another class. So what is the use of internal classes? The reason for the existence of three internal classes is as follows:

The internal class method can access the data in the scope of the class definition, including private data. That is, if Class A defines Class B, Class B can refer to data in Class A or even private data, but class A cannot refer to private data in Class B; internal classes can be hidden from other classes in the same package. When defining a class in a package, this class can be accessed by other classes in the package even if no access permission keyword is added. However, if it is defined as an internal class, this is equivalent to hiding other classes in the package. When you want to define a callback function and do not want to write a large amount of code, it is easier to use an anonymous internal class;

In C ++, nested classes are similar to internal classes in Java. A nested class is included in the scope of the peripheral class.

Java has another internal class function, making the nested class of the internal analogy C ++ more useful. The internal class object has an implicit reference, which references the peripheral class object that instantiates the internal object. This pointer can be used to access all States of peripheral class objects.

1. Access Object status using internal classes

The syntax of the internal class is complex. Here we use a simple example to describe how to use the internal class. The following code constructs a TalkingClock class, which defines a TimePrinter class. When constructing a TalkingClock, two parameters are required: interval at the time interval and beep:

public class TalkingClock {private int interval;private boolean beep;public TalkingClock(int interval,boolean beep){...}public void start(){...}public class TimePrinter implements ActionListener{
//an inner classpublic void actionPerformed(ActionEvent event){
...}}}
Here, the TimePrinter class is located inside the TalkingClock class. However, this does not mean that each TalkingClock has a TimePrinter instance domain. In addition, the TimePrinter object is constructed by the method of the TalkingClock class.

The TimePrinter class is defined as follows:

public class TimePrinter implements ActionListener{public void actionPerformed(ActionEvent event){Date now=new Date();System.out.println("At the tone,the time is "+now);if(beep)Toolkit.getDefaultToolkit().beep();}}

 

Here, the TimePrinter class has only one method actionreceivmed, but this method uses the variable beep of the peripheral class TalkingClock class, and does not have the instance domain or variable beep. That is to say, the internal Department class can access its own data domains, or access the data domains of its peripheral classes.

How do internal classes use peripheral class variables? The internal class object always has an implicit reference, which points to the external class object that creates it:

This reference is invisible to the definition of the internal class. To illustrate this concept, we can call the reference of an external Class Object outer. Therefore, the actionreceivmed method is equivalent to the following:

 

public class TimePrinter implements ActionListener{public void actionPerformed(ActionEvent event){Date now=new Date();System.out.println("At the tone,the time is "+now);if(outer.beep)Toolkit.getDefaultToolkit().beep();}}
The reference of the external class is set in the constructor. The compiler modifies the constructors of all internal classes and adds a parameter referenced by an external class. Because TimePrinter does not define the constructor, the compiler generates a default constructor for this class. The Code is as follows:
public TimePrinter(TalkingClock clock){        outer=clock;}
However, outer is not a Java keyword.

 

After a TimePrinter object is created in the start method, the compiler will pass this reference to the current TalkingClock constructor:

 

ActionListener listener=new TimePrinter(this);

Note that the above Code is automatically added by the compiler. The complete definition of the TalkingClock class is as follows:

 

 

import java.awt.*;import java.awt.event.*;import java.util.Date;import javax.swing.Timer;public class TalkingClock {private int interval;private boolean beep;public TalkingClock(int interval,boolean beep){this.interval=interval;this.beep=beep;}public void start(){ActionListener listener=new TimePrinter();Timer t=new Timer(interval,listener);t.start();}public class TimePrinter implements ActionListener{public void actionPerformed(ActionEvent event){Date now=new Date();System.out.println("At the tone,the time is "+now);if(beep)Toolkit.getDefaultToolkit().beep();}}}
Run the code and the result is as follows:

 

2 special syntax rules for internal classes

As mentioned above, the internal class has an external class that implicitly references outer. In fact, the regular syntax for using external class references is more complex. The following expression:

OuterClasss. this

External class reference. For example, you can write the actionreceivmed method of the TimePrinter internal class as follows:

public void actionPerformed(ActionEvent event){        ...        if(TalkingClock.this.beep)Toolkit.getDefaultToolkit().beep();}
In turn, you can use the following syntax format to write the constructor of internal class objects more clearly:

 

 

outerObject.new InnerClass(construction parameters);
For example:

 

ActionListener listener = this. new TimePrinter ();

Here, the external class reference of the newly constructed TimePrinter object is set to this reference in the method for creating the internal class object. This is actually redundant.

In addition to the external class scope, you can also reference the internal class as follows:

OuterClass. InnerClass

3. How does the compiler handle internal classes?

An internal class is a compiler phenomenon and has nothing to do with virtual machines. The compiler translates internal classes into regular class files that use $ to separate external class names and internal class names. The virtual machine does not know.

In the example above, we can see the. class file in the compiled bin folder. For the above project, there are two. class files:

TalkingClock. class and TalkingClock $ TimePrinter. class

The compiler uses the internal class as a regular class file. So what's special about this class?

You can use javap to decompile the. class file to view the specific information of this class. Enter the javap-private TalkingClock $ TimePrinter command and the result is as follows:

As you can see, in the compiled file, there is our own method actionmongomed, in addition to a final variable this $0, that is, the implicit reference of the external class, this name is synthesized by the compiler and cannot be used in the Code Compiled by the compiler. There is also a constructor generated by the compiler. In this constructor, there is an external class parameter.

Since the compiler can automatically convert data, can it be implemented without the internal class itself?

First, define TimePrinter as a regular class. When constructing a TimePrinter object in TalkingClock outside the TalkingClock class, pass a this pointer. In TimePrinter, the passed TalkingClock pointer is used to access the beep instance in TalkingClock.

The problem arises. In the TalkingClock class, beep is private and external classes cannot be accessed.

That is to say, internal classes have access privileges for external departments. How does the compiler save this access privilege?

Use javap to decompile the TalkingClock class and check the result:

In addition to the instance domain and method defined by ourselves, a static method access $0 is added. This method has a parameter, which is the reference of this class. The return type of this method is exactly the beep type used by the internal class. That is to say, the internal class calls this method to obtain the private member variable of the external class. That is:

If (beep)

It is equivalent:

If (access $0 (outer ))

This may pose a risk. After all, everyone can access the private members of the external class through the access $0 method. However, this method is hidden in the compiled bytecode, and it is difficult to find the specific address of this method. Of course, you cannot use the illegal method name "access $0" in your code.

4. Local internal class

In the preceding example, the TimePrinter class is used only once in the start method of the TalkingClock class. In this case, you can define an internal class as a local internal class.

 

public void start(){class TimePrinter implements ActionListener{public void actionPerformed(ActionEvent event){Date now=new Date();System.out.println("At the tone,the time is "+now);if(beep)Toolkit.getDefaultToolkit().beep();}}ActionListener listener=new TimePrinter();Timer t=new Timer(interval,listener);t.start();}
The local internal class cannot be modified using the public or private access specifiers. Its scope is limited to the block that declares this local class.

The advantage of a local class is that it can be completely hidden from the external world, even if other methods in the TalkingClock class cannot be accessed.

The running result of this example is the same as that of the preceding example.

5. Access final variables by external Methods

Compared with other internal classes, local classes also have the advantage that they can not only access external classes that contain them, but also access local variables. However, these variables must be declared as final. The following code places interval and beep in the start method:

 

public void start(int interval,final boolean beep){class TimePrinter implements ActionListener{public void actionPerformed(ActionEvent event){Date now=new Date();System.out.println("At the tone,the time is "+now);if(beep)Toolkit.getDefaultToolkit().beep();}}ActionListener listener=new TimePrinter();Timer t=new Timer(interval,listener);t.start();}

Here, interval and beep are used as the start parameters, so that the two member variables do not need to be defined in the TalkingClock class.

 

However, since the TimePrinter class is inside start, you should be able to access this variable.

To clearly view internal problems, consider the control process:

(1) Call the start method;

(2) Call the constructor of the internal class TimePrinter to initialize the object variable listener;

(3) Pass the listener reference to the Timer constructor. The Timer starts timing and the start method ends. In this case, the beep parameter variable in the start method no longer exists;

(4) then, the actionreceivmed method executes if (beep );

But the beep variable is gone. How can I still know the beep VALUE IN THE actionreceivmed method? The possible cause is that the value is saved when the internal class TimePrinter constructs the listener. Use javap to check the definition of internal classes:

As you can see, in addition to its own definition, there is an extra final variable val $ beep, and the automatically generated constructor has a boolean parameter in addition to an external class reference parameter, this parameter starts with passing the beep variable. This confirms our speculation. In fact, when an object is created, beep will be passed to the constructor and stored in the val $ beep domain. The compiler must check access to local variables, create corresponding data domains for each variable, and copy local variables to the constructor to initialize these data domains as copies of local variables.

Declare the beep variable as final. After initialization, it cannot be modified. This ensures that the local variables are consistent with the copies in the local class.

But what if I need to modify the final value? For example, you need to update the counter in a closed scope. Count the number of times the compareTo method is called during the sorting process.

Final cannot be updated. However, you can use the following techniques to modify final variables:

Public static int count () {final int [] counter = new int [1]; Date [] dates = new Date [100]; for (int I = 0; I
 
  
An array with a length of 1 is defined here. Although it cannot be referenced by another array, the content in the array can be changed.
  

The result of the above Code is as follows:

99

6. Anonymous internal class

Take the use of local internal classes further. If you create only one object of this class, you do not need to name it. This type is called the anonymous internal class ). For example:

 

public void start(int interval,final boolean beep){ActionListener listener=new ActionListener(){public void actionPerformed(ActionEvent event){Date now=new Date();System.out.println("At the tone,the time is "+now);if(beep)Toolkit.getDefaultToolkit().beep();}};Timer t=new Timer(interval,listener);t.start();}
The syntax indicates that a new object of the class implementing the ActionListener interface is created, and the actionreceivmed method to be implemented is inside.

 

The common syntax format is:

 

new SuperType(construction parameters){        inner class methods and data}

SuperType can be an interface, so the internal class needs to implement this interface; it can also be a class, so the internal class needs to expand it.

 

If the code of an internal class is very small, you can use an anonymous internal class.

7 static internal class

If an internal class does not need to reference an external class object, an internal class can be hidden from the external class. Therefore, you can declare the internal class as static to cancel the generated reference.

The following is a typical example of using static internal classes. If you want to calculate the maximum and minimum values of an array, You need to traverse the array twice if you use two methods. If the maximum and minimum values are obtained in one traversal, two results are returned. Therefore, you can define a Pair class that contains two values:

 

class Pair{private double first;private double second;public Pair(double first,double second){this.first=first;this.second=second;}public double getFirst(){return first;}public double getSecond(){return second;}}
Then define a method minmax that can return Pair results. The complete code is as follows:

 

 

Public class ArrayAlg {public static class Pair {private double first; private double second; public Pair (double first, double second) {this. first = first; this. second = second;} public double getFirst () {return first;} public double getSecond () {return second ;}} public static Pair minmax (double [] values) {double min = Double. MIN_VALUE; double max = Double. MAX_VALUE; for (double x: values) {if (min> x) min = x; if (max <x) max = x; r Eturn = "" new = "" pre = ""> only internal classes can be declared as static. Objects of static internal classes are the same as all internal classes except for the reference privilege of the external class objects that generate them. In this example, it must be defined as static because the internal class is defined in the static method. <P> </x) max = x;>

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.