您的位置:首页 > 编程语言 > Java开发

java(6)内部类基础

2015-11-18 23:10 465 查看

【0】README

0.1) 本文描述+源代码均 转自 core java volume 1, 旨在理解 java内部类 的基础知识;

【1】内部类相关

1.1)为什么要使用 内部类?(Reason)

R1)内部类可以访问该类定义所在的作用域中的数据, 包括私有数据;

R2)内部类可以对同一个包中的其他类隐藏起来;

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

1.2)嵌套类有两个好处(Merit):

M1)命名控制+访问控制;

M2)需要注意的是, Link类位于 LinkedList 类 的私有部分, 因此,Link对其他的代码均不可见;鉴于此情况,可以将Link的数据域设计为 public, 它仍然是安全的,因为这些数据域只能被 LinkedList类中的方法访问, 而不会暴露给其他的代码;

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

2.1)看个荔枝:构造一个语音时钟需要两个参数:发布通告的时间间隔 + 开关铃声的标志:



2.2)需要注意: 这里的 TimePrinter 位于 TalkingClock 的内部, 并不意味着 每个 TalkingClock 都有一个 TimePrinter 实例域;

2.3)看更加详细的 TimePrinter(值得注意的是,actionPerformed 方法在发出铃声前检查了 beep 标志):



这是因为, 内部类既可以访问自身的数据域,也可以访问创建它的外围类对象的数据域(干货);

2.4)为了能够运行这个程序, 内部类的对象有一个隐式引用, 它指向了 创建它的外部类对象(内部类对象拥有一个对外围类对象 的 引用):



2.5)外围类的引用在构造器中设置。编译器修改了所有的内部类的构造器, 添加了一个外围类引用的参数, 因为 TimePrinter 类没有定义构造器, 所以编译器为这个类生成了一个默认构造器;

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

ActionListener listener = new TimePrinter(this);   // parameter automatically added


Annotation) TimerPrinter 类声明为私有的, 这样一来, 只有 TalkingClock的方法才能够构造 TimePrinter对象, 只有内部类可以是私有类,而常规类只可以具有包可见性, 或公有可见性;

package com.corejava.chapter6_2;

import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.Timer;

/**
* This program demonstrates the use of inner classes.
* @version 1.10 2004-02-27
* @author Cay Horstmann
*/
public class InnerClassTest
{
public static void main(String[] args)
{
TalkingClock clock = new TalkingClock(1000, true);
clock.start();

// keep program running until user selects "Ok"
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 the interval between messages (in milliseconds)
* @param beep true if the clock should beep
*/
public TalkingClock(int interval, boolean beep)
{
this.interval = interval;
this.beep = beep;
}

/**
* Starts the clock.
*/
public void start()
{
ActionListener listener = new TimePrinter();
Timer t = new Timer(interval, listener);
t.start();
}

private class TimePrinter implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
Date now = new Date();
System.out.println("At the tone, the time is " + now);
if (beep) Toolkit.getDefaultToolkit().beep();
}
}
}




【3】内部类的特殊语法规则

3.1)使用外围类引用的正规语法还要复杂一些, 表达式 OuterClass.this 表示外围类的引用;如:

public void actionPerformed(ActionEvent event)
{
if(TalkingClock.this.beep) Tookit.getDefaultToolkit().beep();
}


反过来,可以采用下列语法格式更加明确地编写内部对象的构造器:(下面代码中的this是外部类调用start方法的时候,传了一个外部类本身的this引用,this.new == TalkingClock.new TimePrinter)

outerObject.new InnerClass(construction parameters)
如,  ActionListener listener = this.new TimePrinter();


上面的代码中: 最新构造的 TimePrinter 对象 的外围类引用被设置为创建内部类对象的方法中的this引用;这是一种最常见的 情况;

3.2)可以显式地命名将外围类引用设置为其他的对象:如, 如果TimerPrinter 是一个公有内部类,对于任意的语音时钟都可以构造一个 TimePrinter:

TalkingClock jabberer = new TalkingClock(1000, true);
TalkingClock.TimePrinter listener = jabberer.new TimerPrinter();


Attention)需要注意, 在外部类的作用域之外,可以这样引用内部类:

OuterClass.InnerClass


【4】内部类是否有用、必要和安全

4.1)内部类是一种编译器现象, 与虚拟机无关:编译器将会把内部类翻译为用 $ 分隔外部类名和内部类名的常规类文件, 而虚拟机则对此一无所知;

如, 在 TalkingClock 类内部的 TimePrinter 类将被翻译成类文件 TalkingClock\$TimePrinter.class;

4.2)可以看到: 编译器为了引用外围类,生成了一个附加的实例域 this$0;

4.3)内部类可以访问外围类的私有数据, 而常规类则不行:可见, 由于内部类拥有访问特权, 所以与常规类比较起来功能更加强大;

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java 内部类