- 内部类是定义在另一个类中的类,使用内部类有以下原因:
- 内部类可以访问该类定义所在的数据,包括私有数据;
- 内部类可以对同一个包中的其他类隐藏起来;
- 匿名内部类可以可以定义回调函数并且节省大量代码。
- 内部类对象有一个隐式引用(该引用在内部类中不可见),总是指向创建它的外部类对象。
外围类的引用在内部类的构造器中设置,编译器修改了所有内部类的构造器,都添加了一个外部类的引用。
只有内部类可以是私有的,外部类只可能是受保护的或者共有的。
package innerClass;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Date;
/**
* @author feng
* @create 2021-04-03 10:45
*/
public class InnerClassTest {
public static void main(String[] args) {
TalkingClock clock = new TalkingClock(5000, true);
clock.start();
JOptionPane.showMessageDialog(null, "quit program?");
System.exit(0);
}
}
/**
* a clock that prints the time in regular intervals
*/
class TalkingClock{
private int interval;
private boolean beep;
/**
* constructs a talking clock
* @param interval
* @param beep
*/
public TalkingClock(int interval,boolean beep){
this.interval = interval;
this.beep = beep;
}
/**
* starts the clock
*/
public void start(){
ActionListener listener = new TimePrinter();
Timer timer = new Timer(5000, listener);
timer.start();
}
/**
* inner class
*/
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();
}
}
}
以上代码由于TimePrinter没有定义构造器,所以编译器会自动为内部类生成一个构造器。
public TimePrinter(TalkingClock clock){
outer = clock;
}
在start方法中创建TimePrinter对象后。编译器会自动为当前内部类构造器添加参数this。e.g.ActionListener listener = new TimePrinter(this);
3. 内部类的特殊语法规则:
- 内部类中声明的所有静态域必须是final。
- 内部类不能有static方法,如果有static方法,只能方法外部类的静态域和方法。
- 表达式
OuterClass.this
表示外围类引用。 - 可以用下列语法更加明确的编写内部类构造器:
outerObject.new InnerClass(construction parameters)
,例如:ActionListener listener = this.new TimePrinter();
。 - 在外围类的作用域之外,可以这样应用内部类:
OuterClass.InnerClass
:
e.g.TalkingClock jb = new TalkingClock(50000,true); TalkingClock.TimePrinter listener = jb.new TimePrinter();
- 内部类是一种编译器现象,与虚拟机无关。编译器会把内部类编译成外部类名$内部类名的常规文件,虚拟机对此一无所知。
- 局部内部类不能用public或者private访问说明符进行声明,他的作用域被限定在声明它的代码块中,外部类的其他方法也不能访问,可以对外部世界完全隐藏起来。
public void start(){
class TimePrinter implements ActionListener{
public void actionPerformed(ActionEvent evnet){
System.out.println("at the tone,the time is:" + new Date());
if(beep)
ToolKit.getDefaultToolkit().beep();
}
}
ActionListener listener = new TimePrinter();
Timer timer = new Timer(5000, listener);
timer.start();
}
- 局部内部类不仅能访问外部类,还能访问局部变量,不过这些局部变量必须是final的。编译器必须检测对局部变量的访问,为每一个变量建立响应的数据域,并将局部变量拷贝到构造器中,以便将这些数据域初始化为局部变量的副本。
- 匿名内部类通常的语法格式为:
其中SuperType可以是接口,也可以是类,由于匿名内部类没有类名。因此没有构造器,它的构造器参数直接传给超类构造器,但是在内部类实现接口的时候,不能有任何的构造器。new SuperType(constructor parameters){ innerclass method and data }
new InterfaceType(){ methods and data }
package innerClass;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Date;
/**
* @author feng
* @create 2021-04-03 12:31
*/
public class AnonymousInnerClassTest {
public static void main(String[] args) {
TalkingClock clock = new TalkingClock();
clock.start(5000,true);
JOptionPane.showMessageDialog(null, "quit program?");
System.exit(0);
}
}
class TalkingClock{
public void start(int iterval, boolean beep) {
ActionListener listener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("at the tone,the time is:" + new Date());
if (beep)
Toolkit.getDefaultToolkit().beep();
}
};
Timer timer = new Timer(iterval, listener);
timer.start();
}
}
- 静态内部类
- 有时候使用内部类只是为了把一个类隐藏在另一个类中,并不会引用外部类的对象,这时候就可以将该类定义为一个静态内部类,以便取消产生的引用。
- 在内部类不需要访问外部类对象的时候,应该使用静态内部类,有时又将静态内部类称为嵌套类。
- 与常规内部类不同,静态内部类可以有静态域和方法。
- 声明在接口中的内部类自动称为static和public的。
package innerClass;
import java.util.Arrays;
/**
* 这个类检测静态内部类的应用
* @author feng
* @create 2021-04-03 13:02
*/
public class StaticInnerClass {
public static void main(String[] args) {
double[] doubles = new double[20];
for (int i = 0; i < 20; i++) {
doubles[i] = Math.random() * 100;
}
System.out.println(Arrays.toString(doubles));
ArrayAlg.Pair pair = ArrayAlg.minmax(doubles);
System.out.println("min=" + pair.getFirst());
System.out.println("max=" + pair.getSecond());
}
}
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;
}
}
/**
* 获取随机数组的最大值和最小值
* @param doubles
* @return
*/
public static Pair minmax(double[] doubles) {
double min = Double.POSITIVE_INFINITY;
double max = Double.NEGATIVE_INFINITY;
for (double d : doubles){
if (min > d)
min = d;
if (max < d)
max = d;
}
return new Pair(min, max);
}
}