directory
- Local inner class
- Anonymous inner class
An inner class is a class defined in another class.
- Inner class methods can access data in the scope in which the class is defined, including private data.
- Inner classes can be hidden from other classes in the same package
- When you want to define a callback function and don’t want to write a lot of code, it’s convenient to use anonymous inner classes.
Here is a simple example:
A clock needs two parameters: the interval between announcements and a flag to turn on or off the bell.
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 timer = new Timer(interval, listener);
timer.start();
}
public class TimePrinter implements ActionListener{
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("At the tone, the time is " + new Date());
if (beep) {
Toolkit.getDefaultToolkit().beep();
}
}
}
public static void main(String[] args) {
TalkingClock clock = new TalkingClock(1000, true);
clock.start();
//keep program running until user selects "OK"
JOptionPane.showMessageDialog(null, "Quit program?"); System.exit(0); }}Copy the code
The main purpose of this code is to show that the internal class TimePrinter can directly access the external class TalkingClock private member beep.
The syntax and usage are easy to learn, but how does an inner class directly access a private member variable of another class? We know that Java private member variables are accessible only by the instance of the class itself.
When you first learn Java syntax, you remember and understand the inner class as a property of the class, so it’s natural to have access to private variables. This understanding, it turns out, was wrong.
Inner classes are a compiler phenomenon, independent of virtual machines. The compiler will translate the inner class into a regular class file with $separating the outer class name from the inner class name, and the virtual machine will have no idea.
The above inner class is compiled to TalkingClock$TimePrinter:
javap -private TalkingClock$TimePrinter.class
Compiled from "TalkingClock.java"
public class com.test.java.clazz.innerclass.TalkingClock$TimePrinter implements java.awt.event.ActionListener {
final com.test.java.clazz.innerclass.TalkingClock this$0;
public com.test.java.clazz.innerclass.TalkingClock$TimePrinter(com.test.java.clazz.innerclass.TalkingClock);
public void actionPerformed(java.awt.event.ActionEvent);
}Copy the code
Can be found, the compiler to add a new method for static static Boolean access $000 (com) test. Java clazz. Innerclass. TalkingClock); Obviously, we can call this method with the class name to get the private variable, which is equivalent to adding the getter method to expose the private variable.
Look at the actionPerformed method of the mutated inner class:
public void actionPerformed(ActionEvent e) {
System.out.println("At the tone, the time is " + new Date());
if (TalkingClock.accessThe $000(this.this$0)) { Toolkit.getDefaultToolkit().beep(); }}Copy the code
In summary, the inner class provides access to the class by modifying the code through the compiler. If a hacker calls the external class’s access$000 under the same package name, it can access private variables, which is a bit of a danger.
Local inner class
If you look closely at the sample code, TimePrinter is only called in the start method. We can reduce this class to a local inner class, declaring an inner class inside the method.
Local inner classes can access local variables
We will modify the demo above:
public void start(int interval, Boolean beep) {
class TimePrinter implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("Every "+interval+", At the tone, the time is " + new Date());
if (beep) {
Toolkit.getDefaultToolkit().beep();
}
}
}
ActionListener listener = new TimePrinter();
Timer timer = new Timer(interval, listener);
timer.start();
}Copy the code
A local class cannot be specified with either public or private access specifiers; its role is limited to the block in which it is declared.
In the demo above, the local inner class TimePrinter accesses local variables interval and beep. Similarly, these two variables are still converted into the member variables of the inner class to achieve the transfer of values.
Anonymous inner class
public class AnonymousInnerClassTest {
@Data
static class Animal {
private String name;
public void sayHi(){
System.out.println("Hi " + name);
}
}
public static void main(String[] args) {
Animal animal = new Animal(){
@Override
public void sayHi() {
System.out.println("Wang"); }}; animal.sayHi(); }}Copy the code
The above simple simulation of an Animal anonymous class. The compiled result is:
'AnonymousInnerClassTest$1.class' 'AnonymousInnerClassTest$Animal.class' AnonymousInnerClassTest.classCopy the code
The compiler generates three compiler classes.
AnonymousInnerClassTest
public class AnonymousInnerClassTest {
public AnonymousInnerClassTest() { } public static void main(String[] args) { com.test.java.clazz.innerclass.AnonymousInnerClassTest.Animal animal = new 1(); animal.sayHi(); }}Copy the code
AnonymousInnerClassTest$1
import com.test.java.clazz.innerclass.AnonymousInnerClassTest.Animal;
final class AnonymousInnerClassTestThe $1 extends Animal {
AnonymousInnerClassTestThe $1() {
}
public void sayHi() {
System.out.println("Wang"); }}Copy the code
AnonymousInnerClassTestAnimal ‘ ‘ ‘classAnonymousInnerClassTestAnimal’ ‘ ‘classAnonymousInnerClassTestAnimal {private String name;
public void sayHi() {
System.out.println("Hi " + this.name);
}
public AnonymousInnerClassTest$Animal() {
}
//getter setter equals toStringCopy the code
The compiler to generate a packet access the inner class AnonymousInnerClassTestAnimal, for its anonymous subclasses, and generate the final AnonymousInnerClassTestAnimal, for its anonymous subclass, Final AnonymousInnerClassTest1 is also generated, or AnonymousInnerClassTest$2 if there is a second anonymous class.