CoreJava(第六章)05-内部类

1.内部类

顾名思义:内部类就是定义在另一个类中的类。

为什么需要使用内部类?

1)内部类里面的方法可以访问该类定义所在的作用域中的数据,包括私有的数据。

2)内部类可以对同一个包中的其它类隐藏起来。

3)当想要定义一个回调函数且不想编写大量代码时,使用匿名内部类比较便捷。

2.使用内部类访问对象状态

1)先创建一个TalkingClock对象。

2)构造一个语音时钟需要提供两个参数:发布通告的间隔和开关铃声的标志。

class TalkingClock{
	/**
	 * 实例域
	 */
	private int interval;	// 发布通告的间隔
	private boolean beep;	// 开关铃声的标志
	
	public TalkingClock(int interval, boolean beep) {
		super();
		this.interval = interval;
		this.beep = beep;
	}
}

下面这段代码中的TimePrinter类位于TalkingClock类的内部。并不意味着每个TalkingClock都有一个TimePrinter实例域。也就是上面这段代码说的TimePrinter对象是由TalkingClock类的方法构造。

public class TimePrinter implements ActionListener{

		public void actionPerformed(ActionEvent e) {
		}
}

下面这段代码中TimePrinter类并没有实例域或者名为beep的变量,反而beep引用了创建TimePrinterTalkingClock对象的域。

内部类既可以访问自身的数据域,也可以访问创建它的外围类对象的数据域。

if (beep) Toolkit.getDefaultToolkit().beep();	// 检查beep的标志

内部类的对象总有一个隐式引用,它指向了创建它的外部类对象。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dxM6Imzl-1579613264593)(C:\Users\sywangu\AppData\Roaming\Typora\typora-user-images\image-20200121152257771.png)]

1)上图中的这个引用在内部类的定义中是不可见的。(如下代码)

public void actionPerformed(ActionEvent e) {
			System.out.println("当前时间是:" + new Date());
			/**
			 * TimePrinter类没有实例域、也没有beep的变量,而是beep引用了创建TimePrinter的TalkingClock对象的域。
			 * 内部类既可以访问自身的数据域,也可以访问创建它的外围类对象的数据域。
			 */
			if (beep) Toolkit.getDefaultToolkit().beep();	// 检查beep的标志
			
		}

2)外围类的引用在构造器中设置。(如下代码)

public TalkingClock(int interval, boolean beep) {
		super();
		this.interval = interval;
		this.beep = beep;
	}

3)当在start方法中创建了TimePrinter对象后,编译期就会将this引用传递给当前的语音时钟的构造器:

ActionListener listener = new TimePrinter();

4)以上代码完整程序

package corejava_06;

import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Date;
import javax.swing.Timer;

import javax.swing.JOptionPane;

/**
 * 
 * @author sywangu
 *
 */
public class InnerClassTest {
	public static void main(String[] args) {
		TalkingClock clock = new TalkingClock(1000, true);
		clock.start();
		
		JOptionPane.showConfirmDialog(null, "退出?");
		System.exit(0);
	}
}
/**
 * 构造一个语音时钟时需要提供两个参数:发布通告的间隔和开关铃声的标志。
 * @author sywangu
 *
 */
class TalkingClock{
	/**
	 * 实例域
	 */
	private int interval;	// 发布通告的间隔
	private boolean beep;	// 开关铃声的标志
	
	public TalkingClock(int interval, boolean beep) {
		super();
		this.interval = interval;
		this.beep = beep;
	}
	
	public void start() {
		ActionListener listener = new TimePrinter();
		Timer t = new Timer(interval , listener);
		t.start();
	}

	/**
	 * TimePrinter对象是由TalkingClock类的方法构造
	 * @author sywangu
	 *
	 */
	public class TimePrinter implements ActionListener{

		public void actionPerformed(ActionEvent e) {
			System.out.println("当前时间是:" + new Date());
			/**
			 * TimePrinter类没有实例域、也没有beep的变量,而是beep引用了创建TimePrinter的TalkingClock对象的域。
			 * 内部类既可以访问自身的数据域,也可以访问创建它的外围类对象的数据域。
			 */
			if (beep) Toolkit.getDefaultToolkit().beep();	// 检查beep的标志
			
		}
	}
	
}

5)运行结果
在这里插入图片描述

2.内部类的特殊语法规则

3.内部类是否有用、必要和安全

编译器会把内部类翻译成用$分隔外部类名与内部类名的常规文件。

TalkingClock类内部的TimePrinter类转换成class文件是:TalkingClock$TimePrinter.class

编译器为了引用外围类,生成一个附加的实例域this$0

public class TalkingClock$TimePrinter
{
public TalkingClock$TimePrinter ( TalkingCtock ) ;
public void actionPerformed ( java.awt.event.ActionEvent ) ;
final TalkingClock this$0 ;
}

(1)将TimePrinter定义成一个常规类,并把它置于TalkingClock类的外部。

(2)在构造TimePrinter对象的时候,将创建该对象的this指针传递给它。

package corejava_06;

import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.Timer;


public class TalkingClock {

	private int interval;
	private boolean beep;
	
	public TalkingClock(int interval, boolean beep) {
		super();
		this.interval = interval;
		this.beep = beep;
	}
	
	public void start() {
		ActionListener listener = new TimePrinter(this);
		Timer t = new Timer(interval, listener);
		t.start();
	}
}

/*
 * 将TimePrinter定义成一个常规类,并把它置于TalkingClock类的外部
 */
class TimePrinter implements ActionListener {

	private TalkingClock outer;
	
	/*
	 * 在构造`TimePrinter`对象的时候,将创建该对象的this指针传递给它。
	 */
	@Override
	public void actionPerformed(ActionEvent e) {
		// (outer.beep)  // error
		// 内部类可以访问外部类的私有数据,但是这里面的TimePrinter类则不行
		if (outer.beep) Toolkit.getDefaultToolkit().beep();
	}

	public TimePrinter(TalkingClock clock) {
		outer = clock;
	}

}
发布了90 篇原创文章 · 获赞 284 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/qq_41293896/article/details/104065963