关闭

java(6)内部类基础

标签: java内部类
336人阅读 评论(0) 收藏 举报
分类:

【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)内部类可以访问外围类的私有数据, 而常规类则不行:可见, 由于内部类拥有访问特权, 所以与常规类比较起来功能更加强大;
这里写图片描述

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:492134次
    • 积分:7597
    • 等级:
    • 排名:第2813名
    • 原创:252篇
    • 转载:212篇
    • 译文:7篇
    • 评论:64条
    最新评论