[关闭]
@gnudennis 2015-04-26T23:28:38.000000Z 字数 4269 阅读 2417

Core Java笔记 5.内部类

CoreJava


本章重点:

  • 为何使用内部类
  • 访问外围类数据
  • 内部类的语法规则
  • 局部内部类
  • 匿名内部类

内部类(inner class)是定义在另一个类中的类。

为何使用内部类

  1. 内部类方法可以访问外围类的数据,包括私有的数据.
  2. 内部类可以对同一个包种的其他类隐藏起来.
  3. 使用anonymous内部类定义回调函数类.

访问外围类数据

示例:

  1. package corejava.inner;
  2. import javax.swing.*;
  3. import java.awt.*;
  4. import java.awt.event.ActionEvent;
  5. import java.awt.event.ActionListener;
  6. import java.util.Date;
  7. /**
  8. * Created by guolong.fan on 15/4/26.
  9. */
  10. public class InnerClassTest {
  11. public static void main(String[] args) {
  12. TalkingClock clock = new TalkingClock(1000, true);
  13. clock.start();
  14. JOptionPane.showMessageDialog(null, "Quit program?");
  15. System.exit(0);
  16. }
  17. }
  18. class TalkingClock {
  19. public TalkingClock(int interval, boolean beep) {
  20. this.interval = interval;
  21. this.beep = beep;
  22. }
  23. public void start() {
  24. ActionListener listener = new TimePrinter();
  25. Timer timer = new Timer(interval, listener);
  26. timer.start();
  27. }
  28. private int interval;
  29. private boolean beep;
  30. public class TimePrinter implements ActionListener {
  31. @Override
  32. public void actionPerformed(ActionEvent actionEvent) {
  33. System.out.println("At the tone, the time is " + new Date());
  34. if (beep) Toolkit.getDefaultToolkit().beep();
  35. }
  36. }
  37. }

if (beep)... 访问了外围类的私有属性.

内部类是一种编译器现象,与虚拟机无关. 使用 javap 分析编译器如何生成代码的?

javap -private TalkingClock$TimePrinter.class

  • 内部类的命名. outclass$innerclass(eg. TalkingClock$TimePrinter)
  • 内部类生成外部类实例的引用(final)+构造器.
  1. public class corejava.inner.TalkingClock$TimePrinter extends java.lang.Object implements java.awt.event.ActionListener{
  2. final corejava.inner.TalkingClock this$0;
  3. public corejava.inner.TalkingClock$TimePrinter(corejava.inner.TalkingClock);
  4. public void actionPerformed(java.awt.event.ActionEvent);
  5. }
  6. <div class="md-section-divider"></div>
  • 针对内部类访问了的private fields, 外围类生成 access$ 代码(package权限的getter).
  1. class corejava.inner.TalkingClock extends java.lang.Object{
  2. private int interval;
  3. private boolean beep;
  4. public corejava.inner.TalkingClock(int, boolean);
  5. public void start();
  6. static boolean access$000(corejava.inner.TalkingClock);
  7. }
  8. <div class="md-section-divider"></div>

最终,编译器生成如下代码.

  1. class TalkingClock {
  2. public TalkingClock(int interval, boolean beep) {
  3. this.interval = interval;
  4. this.beep = beep;
  5. }
  6. public void start() {
  7. ActionListener listener = new TimePrinter(this);
  8. Timer timer = new Timer(interval, listener);
  9. timer.start();
  10. }
  11. static boolean access$000(corejava.inner.TalkingClock);
  12. private int interval;
  13. private boolean beep;
  14. public class TimePrinter implements ActionListener {
  15. public TimePrinter(TalkingClock clock) {
  16. outer = clock;
  17. }
  18. @Override
  19. public void actionPerformed(ActionEvent actionEvent) {
  20. System.out.println("At the tone, the time is " + new Date());
  21. if (access$000()) Toolkit.getDefaultToolkit().beep();
  22. }
  23. ...
  24. private TalkingClock outer;
  25. }
  26. }
  27. <div class="md-section-divider"></div>

内部类的语法规则

  1. 外围类的引用. 即上面的 outer 实质是 OuterClass.this. beep可以写成TalkingClock.this.beep.
  2. 生成内部类对象. outObject.new InnerClass(construction parameters).
  1. 内部类:
  2. ActionListener listener = this.new TimePrinter();
  3. 其他程序中:
  4. TalkingClock jabberer = new TalkingClock(1000, true);
  5. TalkingClock.TimePrinter listener = jabberer.new TimePrinter();
  6. <div class="md-section-divider"></div>

局部内部类

直接定义在方法中.

  1. public class InnerClassTest {
  2. public static void main(String[] args) {
  3. TalkingClock clock = new TalkingClock(1000, true);
  4. clock.start();
  5. JOptionPane.showMessageDialog(null, "Quit program?");
  6. System.exit(0);
  7. }
  8. }
  9. class TalkingClock {
  10. public TalkingClock(int interval, boolean beep) {
  11. this.interval = interval;
  12. this.beep = beep;
  13. }
  14. public void start() {
  15. public class TimePrinter implements ActionListener {
  16. @Override
  17. public void actionPerformed(ActionEvent actionEvent) {
  18. System.out.println("At the tone, the time is " + new Date());
  19. if (beep) Toolkit.getDefaultToolkit().beep();
  20. }
  21. }
  22. ActionListener listener = new TimePrinter();
  23. Timer timer = new Timer(interval, listener);
  24. timer.start();
  25. }
  26. private int interval;
  27. private boolean beep;
  28. }
  29. <div class="md-section-divider"></div>

匿名内部类

  1. package corejava.inner;
  2. import javax.swing.*;
  3. import java.awt.*;
  4. import java.awt.event.ActionEvent;
  5. import java.awt.event.ActionListener;
  6. import java.util.Date;
  7. /**
  8. * Created by guolong.fan on 15/4/26.
  9. */
  10. public class InnerClassTest {
  11. public static void main(String[] args) {
  12. TalkingClock clock = new TalkingClock(1000, true);
  13. clock.start();
  14. JOptionPane.showMessageDialog(null, "Quit program?");
  15. System.exit(0);
  16. }
  17. }
  18. class TalkingClock {
  19. public TalkingClock(int interval, boolean beep) {
  20. this.interval = interval;
  21. this.beep = beep;
  22. }
  23. public void start() {
  24. ActionListener listener = new ActionListener() {
  25. @Override
  26. public void actionPerformed(ActionEvent actionEvent) {
  27. System.out.println("At the tone, the time is " + new Date());
  28. if (beep) Toolkit.getDefaultToolkit().beep();
  29. }
  30. };
  31. Timer timer = new Timer(interval, listener);
  32. timer.start();
  33. }
  34. private int interval;
  35. private boolean beep;
  36. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注