<CoreJava> 6.4 内部类

 内部类:定义在一个类中的类。
为什么要用内部类:
1)内部类可以访问其外围类的实例域,包括私有数据。
2)内部类可以对同包中的其他类隐藏。
3)定义一个回调函数,使用匿名内部类要便捷。

6.4.1 使用内部类访问对象的状态
实例:一个TimePrinter常规类,他需要通过TalkingClock类的共有方法访问beep标志。
注释:TimePrinter类被声明为私有的,这样只有TalkingClock的方法才能生成TimePrinter对象。内部类可以是私有类,常规类只能是包可见性或公有可见性。
例6-4源代码:
  1. package com.corejava.innerclass;  
  2.   
  3. import java.awt.*;  
  4. import java.awt.event.*;  
  5. import java.util.*;  
  6. import javax.swing.*;  
  7. import javax.swing.Timer;  
  8. /** 
  9.  *  
  10.  * @author vincent 
  11.  *  
  12.  */  
  13. public class InnerClassTest {  
  14.   
  15.     public static void main(String[] args) {  
  16.         TalkingClock clock = new TalkingClock(1000true);  
  17.         clock.start();  
  18.           
  19.         JOptionPane.showMessageDialog(null"Quit program?");  
  20.         System.exit(0);  
  21.     }  
  22. }  
  23.   
  24. class TalkingClock {  
  25.       
  26.     private int interval;  
  27.     private boolean beep;  
  28.   
  29.     public TalkingClock(int interval, boolean beep) {  
  30.         this.interval = interval;  
  31.         this.beep = beep;  
  32.     }  
  33.       
  34.     public void start() {  
  35.         ActionListener listener = new TimePrinter();  
  36.         Timer t = new Timer(interval, listener);  
  37.         t.start();  
  38.     }  
  39.       
  40.     public class TimePrinter implements ActionListener {  
  41.   
  42.         @Override  
  43.         public void actionPerformed(ActionEvent e) {  
  44.             // TODO Auto-generated method stub  
  45.             Date now = new Date();  
  46.             System.out.println("At the tone, the time is " + now);  
  47.             if(beep)  
  48.                 Toolkit.getDefaultToolkit().beep();  
  49.         }  
  50.           
  51.     }  
  52. }  

6.4.4局部内部类
使用背景:创建一个类的对象只需使用一次时,推荐使用局部内部类。例如上述代码中TimerPrinter这个类只在start方法中创建了对象并只使用了一次,这时可将TimerPrinter创建为局部内部类:
  1. public void start() {  
  2.     class TimerPrinter implements ActionListener {  
  3.         public void actionPerformed(ActionEvent event) {  
  4.             Date now = new Date();  
  5.             System.out.println("At the tone, the time is " + now);  
  6.             if(beep)  
  7.                 Toolkit.getDefaultToolkit().beep();  
  8.         }  
  9.     }  
  10.       
  11.     ActionListener listener = new TimerPrinter();  
  12.     Timer t = new Timer(interval, listener);  
  13.     t.start();  
  14. }  
注意:局部内部类不能用public或private声明,它的作用域被限定在声明这个局部类的块中;
局部类的好处是对外完全隐藏,即使TalkingClock类中的其他代码也不能访问它,除了start方法外,没有任何方法知道TimerPrinter类的存在。
局部类还有一个优点:除了能访问包含它的外部类,还能访问局部变量,不过这些局部变量必须被声明为final。

6.4.5由外部方法访问final变量
典型示例:将TalkingClock构造器的参数interval和beep移至start方法中。
  1. public void start(int interval, final boolean beep) {  
  2.     class TimerPrinter implements ActionListener {  
  3.         public void actionPerformed(ActionEvent event) {  
  4.             Date now = new Date();  
  5.             System.out.println("At the tone, the time is " + now);  
  6.             if(beep)  
  7.                 Toolkit.getDefaultToolkit().beep();  
  8.         }  
  9.     }  
  10.       
  11.     ActionListener listener = new TimerPrinter();  
  12.     Timer t = new Timer(interval, listener);  
  13.     t.start();  
  14. }  

6.4.6匿名内部类

1、将局部内部类深入,若只创建这个类的一个对象,就不用命名了。这种类就是匿名内部类。

小程序:

public void start(int interval, final boolean beep) {

ActiongListener listener = new ActionListener() {

public void actionPerformed(ActionEvent event) {

Date now = new Date();

System.out.println("At the tone, time is " + now);

if(beep)

Toolkit.getDefultToolkit().beep();

}

};

Timer t = new Timer(interval, listener);

t.start();

}

代码解析:创建了一个实现ActiongListener接口的类的新对象,这个新对象需要实现actionPerformed所定义的方法。

2、构造器的名字必须和类名相同,但是匿名类没有类名,所以匿名类没有构造器。取而代之的是将构造器的参数传递给超类(父类)构造器。尤其是内部类实现接口是不能有任何构造参数,而且还要提供一组括号,例如:

new InterfaceType() {

    methods and data;

}

3、构造一个类的新对象共和构造一个匿名类的区别:

Person queen = new Person("Mary");    //a Person object

Person count = new Person() {....};   //an object of an inner class extending Person

如果构造参数的闭源括号跟一个开花括号,表示正在定义的就是匿名内部类 


例6-5源代码:将这个程序与之前的6-4相比较会发现匿名类的解决方案比较简单、实际和易于理解

  1. package com.core.anonymousinnerclass;  
  2.   
  3. import java.awt.Toolkit;  
  4. import java.awt.event.ActionEvent;  
  5. import java.awt.event.ActionListener;  
  6. import java.util.Date;  
  7. import javax.swing.JOptionPane;  
  8. import javax.swing.Timer;  
  9.   
  10. /** 
  11.  *  
  12.  * @author vincent 
  13.  * 
  14.  */  
  15. public class AnonymousInnerClass {  
  16.   
  17.     public static void main(String[] args) {  
  18.         TalkingClock clock = new TalkingClock();  
  19.         clock.start(1000true);  
  20.           
  21.         //keep progra running until user selects "OK"  
  22.         JOptionPane.showMessageDialog(null"Quit program?");  
  23.         System.exit(0);  
  24.     }  
  25. }  
  26.   
  27. class TalkingClock {  
  28.     public void start(int interval, final boolean beep) {  
  29.         ActionListener listener = new ActionListener() {  
  30.   
  31.             @Override  
  32.             public void actionPerformed(ActionEvent e) {  
  33.                 // TODO Auto-generated method stub  
  34.                 Date now = new Date();  
  35.                 System.out.println("At the tone, time is: " + now);  
  36.                 if(beep)  
  37.                     Toolkit.getDefaultToolkit().beep();  
  38.             }  
  39.   
  40.         };  
  41.         Timer t = new Timer(interval, listener);  
  42.         t.start();  
  43.     }  
  44. }  

6.4.7静态内部类
使用背景:只需要将一个类隐藏在另一个类的内部,并不需要内部类引用外围类对象时。
只有内部类可以声明为static,静态类除了不能生产外围类对象的引用外,与其他内部类一样。
例6-6
  1. package com.core.staticinnerclass;  
  2.   
  3. /** 
  4.  *  
  5.  * @author vincent 
  6.  * 
  7.  */  
  8. public class StaticInnerClass {  
  9.   
  10.     public static void main(String[] args) {  
  11.         double[] d = new double[20];  
  12.         for (int i = 0; i < d.length; i++)  
  13.             d[i] = 100 * Math.random();  
  14.               
  15.         ArrayAlg.Pair p = ArrayAlg.minmax(d);   //不需要用new生成对象,静态方法可以直接引用  
  16.           
  17.         System.out.println("min = " + p.getFirst());  
  18.         System.out.println("max = " + p.getSecond());  
  19.     }  
  20.               
  21. }  
  22.       
  23.     class ArrayAlg {  
  24.   
  25.         //A pair of floating-point numbers  
  26.         public static class Pair {  
  27.   
  28.             private double first;  
  29.             private double second;  
  30.   
  31.             //Constructs a pair from two floating-point numbers  
  32.             public Pair(double f, double s) {  
  33.                 first = f;  
  34.                 second = s;  
  35.             }  
  36.               
  37.             //Returns the first numbers of the pair  
  38.             public double getFirst() {  
  39.                 return first;  
  40.             }  
  41.               
  42.             //Return the second numbers of the pair  
  43.             public double getSecond() {  
  44.                 return second;  
  45.             }  
  46.         }  
  47.           
  48.         //minmax方法返回 Pair这个静态内部类  
  49.         public static Pair minmax(double[] values) {  
  50.   
  51.             double min = Double.MAX_VALUE;  
  52.             double max = Double.MIN_VALUE;  
  53.               
  54.             for (double v : values) {  
  55.                 if (min > v)  
  56.                     min = v;  
  57.                 if (max < v)  
  58.                     max = v;  
  59.             }  
  60.             return new Pair(min, max);  
  61.         }  
  62.   
  63.     }  
posted @ 2013-02-28 18:59  vincent_hv  阅读(193)  评论(0编辑  收藏  举报