7.2 内部类
实例066 普通内部类的简单应用
实例说明
在使用图形界面程序时,用户总是希望界面是丰富多彩的,这就要求程序员根据不同的情况为界面设置不同的颜色。本实例定义了3个按钮,用户通过单击不同的按钮,可以为面板设置不同的颜色。运行本实例,将显示如图7.9所示的效果,单击“红色”按钮,即可将背景设置为红色;单击“绿色”按钮,即可将背景设置为绿色;单击“蓝色”按钮,即可将背景设置为蓝色,如图7.10所示。
实现过程
(1)在Eclipse
中创建项目066,并在该项目中创建com.Mingrisoft
包。
(2)在com.Mingrisoft
包中编写类ButtonTest
,该类继承自JFrame
。在该窗体中添加3个按钮,分别用来为面板设置不同的颜色。
(3)在com.Mingrisoft
包中再编写类ColorAtion
,该类继承自ActionListener
接口。在该类的构造方法中,需要为其指定一种颜色,在actionPerformed
方法中将面板设置成指定的颜色。关键代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
| package com.mingrisoft;
import java.awt.Color; import java.awt.EventQueue; import java.awt.FlowLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.border.EmptyBorder;
public class ButtonTest extends JFrame { private final class BackgroundColorAction implements ActionListener { private Color backgroundColor; public BackgroundColorAction(Color color) { this.backgroundColor = color; } public void actionPerformed(ActionEvent e) { contentPane.setBackground(backgroundColor); } }
private static final long serialVersionUID = -7473358778079684939L; private JPanel contentPane;
public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { public void run() { try { ButtonTest frame = new ButtonTest(); frame.setVisible(true); } catch (Exception e) { e.printStackTrace(); } } }); }
public ButtonTest() { setTitle("普通内部类的简单应用"); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setBounds(100, 100, 450, 300); contentPane = new JPanel(); contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); setContentPane(contentPane); contentPane.setLayout(new FlowLayout(FlowLayout.CENTER, 5, 5));
JButton btnNewButton = new JButton("红色"); btnNewButton.addActionListener(new BackgroundColorAction(Color.red)); contentPane.add(btnNewButton);
JButton btnNewButton_1 = new JButton("绿色"); btnNewButton_1.addActionListener(new BackgroundColorAction(Color.green)); contentPane.add(btnNewButton_1);
JButton btnNewButton_2 = new JButton("蓝色"); btnNewButton_2.addActionListener(new BackgroundColorAction(Color.blue)); contentPane.add(btnNewButton_2); }
}
|
指点迷津:contentPane
是在外部类ButtonTest
中定义的域,但是在内部类中却可以直接使用。
技术要点:在类中,除了可以定义域、方法和块,还可以定义类,这种类称为内部类。声明一个最简单的内部类的语法如下:
1 2 3 4 5
| public class Outter{ class Inner{ } }
|
内部类可以使用外部类中定义的属性和方法,即使它们都是私有的。编译器在编译内部类时,将内部类命名为Outter$Inner
的形式,虚拟机并不知道有内部类。
实例067 局部内部类的简单应用
实例说明
日常生活中,闹钟的应用非常广泛。使用它可以更好地帮助人们安排时间。本实例将实现个非常简单的闹钟。运行本实例,控制台会不断输出当前的时间,并且每隔一秒钟会发出提示音。用户可以单击“确定”按钮来退出程序。
实现过程
(1)在Eclipse
中创建项目067,并在该项目中创建com.Mingrisoft
包
(2)在com.Mingrisoft
包中编写Java
类,名称为AlarmClock
。在该类中,首先定义两个属性,一个是delay
,表示延迟的时间;另一个是flag
,表示是否需要发出提示声音。然后在start()
方法中,使用Timer
类来安排动作发出事件。关键代码如下:
局部内部类 Swing定时器的使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| package com.mingrisoft; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.text.SimpleDateFormat; import java.util.Date; import javax.swing.Timer;
public class AlarmClock {
private int delay; private boolean flag;
public AlarmClock(int delay, boolean flag) { this.delay = delay; this.flag = flag; }
public void start() { class TimerListener implements ActionListener { @Override public void actionPerformed(ActionEvent e) { SimpleDateFormat format = new SimpleDateFormat("k:m:s"); String result = format.format(new Date()); System.out.println("当前的时间是:" + result); if (flag) { Toolkit.getDefaultToolkit().beep(); } } } Timer timer = new Timer(delay, new TimerListener()); timer.start(); } }
|
(3)编写类Test
进行测试,在该类的main()
方法中创建AlarmClock
对象,并调用其start
方法。使用对话框提示用户是否要退出程序。关键代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13
| package com.mingrisoft; import javax.swing.JOptionPane;
public class Test { public static void main(String[] args) { AlarmClock clock = new AlarmClock(1000, true); clock.start(); JOptionPane.showMessageDialog(null, "是否退出?"); System.exit(0); } }
|
技术要点
本实例的技术要点就是局部内部类。在Java
中可以将类定义在方法的内部,称为局部内部类。这种类不能使用public
和private
修饰,它的作用域被限定在声明这个类的方法中。局部内部类比其他内部类还有一个优点,就是可以访问方法参数。一个最简单的局部内部类代码如下:
1 2 3 4 5
| public void book(){ public class JavaProgrammingBook{
} }
|
脚下留神:被局部内部类使用的方法参数必须是final
的
Swing定时器的使用示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| package com.mingrisoft;
import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JTextField; import javax.swing.Timer;
public class CountdownClock { private JTextField textField; private class CountdownAction implements ActionListener { public void actionPerformed(ActionEvent e) { String text = textField.getText(); if (!"".equals(text)) { int num = Integer.parseInt(text); if (num-- > 0) { textField.setText(String.valueOf(num)); } if (num == 0) { System.out.println("0"); Toolkit.getDefaultToolkit().beep(); } } } }; private Timer timer = new Timer(1000, new CountdownAction()); public CountdownClock(JTextField textField) { this.textField = textField; } public void start() { timer.start(); } public void stop() { timer.stop(); } }
|
调用界面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
| package com.mingrisoft;
import java.awt.Color; import java.awt.EventQueue; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.GridLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JTextField; import javax.swing.UIManager; import javax.swing.border.EmptyBorder; import javax.swing.border.TitledBorder; import java.awt.FlowLayout; import javax.swing.SwingConstants; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent;
public class CountdownFrame extends JFrame { private static final long serialVersionUID = 2291192626975502319L; private JPanel contentPane; private JTextField textField;
public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { public void run() { try { CountdownFrame frame = new CountdownFrame(); frame.setVisible(true); } catch (Exception e) { e.printStackTrace(); } } }); }
public CountdownFrame() { setTitle("倒计时器"); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); contentPane = new JPanel(); contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); setContentPane(contentPane); GridBagLayout gbl_contentPane = new GridBagLayout(); gbl_contentPane.columnWidths = new int[]{424, 0}; gbl_contentPane.rowHeights = new int[]{50, 40, 0}; gbl_contentPane.columnWeights = new double[]{1.0, Double.MIN_VALUE}; gbl_contentPane.rowWeights = new double[]{0.0, 0.0, Double.MIN_VALUE}; contentPane.setLayout(gbl_contentPane);
JPanel panel0 = new JPanel(); panel0.setToolTipText(""); panel0.setBorder(new TitledBorder(UIManager.getBorder("TitledBorder.border"), "请输入需要倒数的时间(秒数)", TitledBorder.LEADING, TitledBorder.TOP, null, new Color(0, 0, 0))); GridBagConstraints gbc_panel0 = new GridBagConstraints(); gbc_panel0.fill = GridBagConstraints.BOTH; gbc_panel0.insets = new Insets(0, 0, 5, 0); gbc_panel0.gridx = 0; gbc_panel0.gridy = 0; contentPane.add(panel0, gbc_panel0); panel0.setLayout(new GridLayout(0, 1, 0, 0));
textField = new JTextField(); final CountdownClock textClock = new CountdownClock(textField); textField.addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_ENTER) { System.out.println("你按下了enter键"); textClock.start(); } } }); textField.setHorizontalAlignment(SwingConstants.LEFT); textField.setText("60"); textField.setToolTipText("在这里输入时间(单位:秒)"); panel0.add(textField); textField.setColumns(10);
JPanel panel1 = new JPanel(); GridBagConstraints gbc_panel1 = new GridBagConstraints(); gbc_panel1.gridx = 0; gbc_panel1.gridy = 1; contentPane.add(panel1, gbc_panel1);
JButton btnNewButton = new JButton("开始"); btnNewButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { textClock.start(); } }); panel1.setLayout(new FlowLayout(FlowLayout.CENTER, 5, 5)); panel1.add(btnNewButton);
JButton btnNewButton_1 = new JButton("暂停"); btnNewButton_1.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { textClock.stop(); } }); panel1.add(btnNewButton_1);
JButton btnNewButton_2 = new JButton("清零"); btnNewButton_2.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { textClock.stop(); textField.setText("0"); } }); panel1.add(btnNewButton_2);
this.pack(); }
}
|
实例068 匿名内部类的简单应用
实例说明
在査看数码相片时,通常会使用一款图片査看软件,该软件应该能够遍历文件夹下的所有图片并进行显示。本实例将编写一个非常简单的图片查看软件,它可以支持6张图片。通过单击不同的按钮就可以查看不同的图片。运行本实例,单击不同的按钮将显示不同的图片,例如,单击“图片4”按钮,将显示如图712所示的图片;单击“图片5”按钮,将显示如图7.13所示的图片。
实现过程
(1)在Eclipse
中创建项目068,并在该项目中创建com. mingrisoft
包
(2)在com.mingrisoft
包中编写类,名称为ImageViewer
,该类继承自JFrame
。在窗体中添加6个按钮和一个标签,单击不同的按钮可以在标签上显示不同的图片。关键代码如下:
项目结构
1 2 3 4 5 6 7 8 9 10 11 12
| G:\Desktop\书籍\Java\Java 实战\Java经典编程300例\Java经典编程300例\SL\07\068 └─src\ ├─com\ │ └─mingrisoft\ │ └─ImageViewer.java └─images\ ├─1.png ├─2.png ├─3.png ├─4.png ├─5.png └─6.png
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
| package com.mingrisoft;
import java.awt.BorderLayout; import java.awt.EventQueue; import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.SwingConstants; import javax.swing.border.EmptyBorder;
public class ImageViewer extends JFrame { private static final long serialVersionUID = 6317071842177275862L; private JPanel contentPane;
public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { public void run() { try { ImageViewer frame = new ImageViewer(); frame.setVisible(true); } catch (Exception e) { e.printStackTrace(); } } }); }
public ImageViewer() { setTitle("匿名内部类的简单应用"); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setBounds(100, 100, 450, 300); contentPane = new JPanel(); contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); contentPane.setLayout(new BorderLayout(0, 0)); setContentPane(contentPane);
final JLabel label = new JLabel(""); label.setHorizontalAlignment(SwingConstants.CENTER); label.setIcon(new ImageIcon(ImageViewer.class.getResource("/images/1.png"))); contentPane.add(label, BorderLayout.CENTER);
JPanel panel = new JPanel(); contentPane.add(panel, BorderLayout.NORTH);
JButton button1 = new JButton("图片1"); button1.setIcon(null); button1.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { label.setIcon(new ImageIcon(ImageViewer.class.getResource("/images/1.png"))); } }); panel.setLayout(new GridLayout(2, 3, 0, 0)); panel.add(button1);
JButton button2 = new JButton("图片2"); button2.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { label.setIcon(new ImageIcon(ImageViewer.class.getResource("/images/2.png"))); } }); panel.add(button2);
JButton button3 = new JButton("图片3"); button3.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { label.setIcon(new ImageIcon(ImageViewer.class.getResource("/images/3.png"))); } }); panel.add(button3);
JButton button4 = new JButton("图片4"); button4.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { label.setIcon(new ImageIcon(ImageViewer.class.getResource("/images/4.png"))); } });
panel.add(button4);
JButton button5 = new JButton("图片5"); button5.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { label.setIcon(new ImageIcon(ImageViewer.class.getResource("/images/5.png"))); } }); panel.add(button5);
JButton button6 = new JButton("图片6"); button6.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { label.setIcon(new ImageIcon(ImageViewer.class.getResource("/images/6.png")));
} }); panel.add(button6); }
}
|
技术要点
本实例的技术要点就是匿名内部类。当只需要创建类的一个对象时,可以使用匿名内部类。ActionListener
是Swing
中动作事件的监听器,如果创建该接口的匿名内部类,可以使用以下代码:
1 2 3 4 5 6
| ActionListener listener=new ActionListener() { public void actionPerformed(ActionEvent e) { ...... } };
|
实例069 静态内部类的简单应用
实例说明
当对元素进行排序时,需要明确各个元素如何比较大小。使用既定的比较方式,就可以求出一个数组中的最大值和最小值。本实例使用静态内部类来实现使用一次遍历求最大值和最小值。实例的运行效果如图714所示。
实现过程
(1)在Eclipse
中创建项目069,并在该项目中创建com.mingrisoft
包。
(2)在com.Mingrisoft
包中编写Java
类,名称为MaxMin
,在该类中,首先定义一个静态内部类Result
,然后在该类中定义两个浮点型属性,一个是max
,表示最大值;另一个是min
,表示最小值。再使用构造方法为其初始化,并提供getXXX()
方法来获得这两个值。最后定义个静态方法getResult()
,该方法的返回值是Result
类型,这样就可以既保存最大值,又保存最小值。关键代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| package com.mingrisoft;
public class MaxMin { public static class Result { private double max; private double min;
public Result(double max, double min) { this.max = max; this.min = min; }
public double getMax() { return max; }
public double getMin() { return min; } } public static Result getResult(double[] array) { double max = Double.MIN_VALUE; double min = Double.MAX_VALUE; for (double i : array) { if (i > max) { max = i; } if (i < min) { min = i; } } return new Result(max, min); } }
|
(3)在com.Mingrisoft
包中再编写类Test
进行测试,在该类的main()
方法中,使用随机数初始化了一个长度为5的数组,并求得该数组的最大值和最小值。关键代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| package com.mingrisoft;
import com.mingrisoft.MaxMin.Result;
public class Test { public static void main(String[] args) { double[] array = new double[5]; for (int i = 0; i < array.length; i++) { array[i] = 100 * Math.random(); } System.out.println("源数组:"); for (int i = 0; i < array.length; i++) { System.out.println(array[i]); } Result result = MaxMin.getResult(array); System.out.println("最大值:" + result.getMax()); System.out.println("最小值:" + result.getMin()); } }
|
运行效果
1 2 3 4 5 6 7 8
| 源数组: 33.76939597721237 62.481609746228216 11.735585952472894 54.27160232334431 94.32873841657997 最大值:94.32873841657997 最小值:11.735585952472894
|
技术要点
本实例的技术要点就是静态内部类。静态内部类是使用static
修饰的内部类,在静态内部类中,可以使用外部类定义的静态域,但是不能使用非静态域。这是静态内部类与非静态内部类的重要区别。定义一个最简单的静态内部类的代码如下:
1 2 3
| public void book(){ public static class Inner{} }
|
注意,不要将静态内部类声明成private
的,否则不能使用其中定义的方法