Core Java笔记 5.内部类

本章重点:

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

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

为何使用内部类

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

访问外围类数据

示例:

package corejava.inner;

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

/**
 * Created by guolong.fan on 15/4/26.
 */
public class InnerClassTest {

    public static void main(String[] args) {
        TalkingClock clock = new TalkingClock(1000, true);
        clock.start();

        JOptionPane.showMessageDialog(null, "Quit program?");
        System.exit(0);
    }
}

class TalkingClock {

    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();
    }

    private int interval;
    private boolean beep;

    public class TimePrinter implements ActionListener {

        @Override
        public void actionPerformed(ActionEvent actionEvent) {
            System.out.println("At the tone, the time is " + new Date());
            if (beep) Toolkit.getDefaultToolkit().beep();
        }
    }
}

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

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

  • 内部类的命名. outclass$innerclass(eg. TalkingClock$TimePrinter)
  • 内部类生成外部类实例的引用(final)+构造器.
public class corejava.inner.TalkingClock$TimePrinter extends java.lang.Object implements java.awt.event.ActionListener{
    final corejava.inner.TalkingClock this$0;
    public corejava.inner.TalkingClock$TimePrinter(corejava.inner.TalkingClock);
    public void actionPerformed(java.awt.event.ActionEvent);
}
  • 针对内部类访问了的private fields, 外围类生成 access$ 代码(package权限的getter).
class corejava.inner.TalkingClock extends java.lang.Object{
    private int interval;
    private boolean beep;
    public corejava.inner.TalkingClock(int, boolean);
    public void start();
    static boolean access$000(corejava.inner.TalkingClock);
}

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

class TalkingClock {

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

    public void start() {
        ActionListener listener = new TimePrinter(this);
        Timer timer = new Timer(interval, listener);
        timer.start();
    }

    static boolean access$000(corejava.inner.TalkingClock);
    
    private int interval;
    private boolean beep;

    public class TimePrinter implements ActionListener {
        public TimePrinter(TalkingClock clock) {
            outer = clock;
        }

        @Override
        public void actionPerformed(ActionEvent actionEvent) {
            System.out.println("At the tone, the time is " + new Date());
            if (access$000()) Toolkit.getDefaultToolkit().beep();
        }
        ...
        private TalkingClock outer;
    }
}

内部类的语法规则

  1. 外围类的引用. 即上面的 outer 实质是 OuterClass.this. beep可以写成TalkingClock.this.beep.
  2. 生成内部类对象. outObject.new InnerClass(construction parameters).
内部类:
ActionListener listener = this.new TimePrinter();

其他程序中:
TalkingClock jabberer = new TalkingClock(1000, true);
TalkingClock.TimePrinter listener = jabberer.new TimePrinter();

局部内部类

直接定义在方法中.

public class InnerClassTest {

    public static void main(String[] args) {
        TalkingClock clock = new TalkingClock(1000, true);
        clock.start();

        JOptionPane.showMessageDialog(null, "Quit program?");
        System.exit(0);
    }
}

class TalkingClock {

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

    public void start() {
        public class TimePrinter implements ActionListener {

            @Override
            public void actionPerformed(ActionEvent actionEvent) {
                System.out.println("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();
    }

    private int interval;
    private boolean beep;
}


匿名内部类

package corejava.inner;

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

/**
 * Created by guolong.fan on 15/4/26.
 */
public class InnerClassTest {

    public static void main(String[] args) {
        TalkingClock clock = new TalkingClock(1000, true);
        clock.start();

        JOptionPane.showMessageDialog(null, "Quit program?");
        System.exit(0);
    }
}

class TalkingClock {

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

    public void start() {
        ActionListener listener = new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent actionEvent) {
                System.out.println("At the tone, the time is " + new Date());
                if (beep) Toolkit.getDefaultToolkit().beep();
            }
        };

        Timer timer = new Timer(interval, listener);
        timer.start();
    }

    private int interval;
    private boolean beep;
}
posted @ 2015-04-30 16:27  nil2inf  阅读(196)  评论(0编辑  收藏  举报