读书笔记——Java中的内部类

读书笔记——Java中的内部类

(看完Java核心技术卷一第六章关于内部类一节,特做记录)

 

内部类(inner class)是定义在另一个类中的类,为什么要使用内部类呢?其主要原因有以下三点:

  1.内部类方法可以访问该类定义所在的作用域中的数据,包括私有数据。

  2.内部类可以对同一个包中的其他类隐藏起来。

  3.当想要定义一个回调函数且不想编写大量代码时,使用匿名内部类比较便捷。

普通的内部类:

一个简单的内部类, 代码如下:

package com.chen;

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

import java.util.Date;
//import java.swing.Timer;

/**
 * @author 淡
 * @create 2020-03-02 0:18
 */
public class InterClassTest {
    public static void main(String[] args) {
        TalkingClock clock = new TalkingClock(1000, true);
        clock.start();
//注释代码一:
//        ActionListener listener = new TalkingClock.TimePrinter();
//        Timer t = new Timer(1000, listener);
//        t.start();

// 注释代码二:
//        TalkingClock jabberer = new TalkingClock(100, true);
//        TalkingClock.TimePrinter listener = jabberer.new TimePrinter();

        JOptionPane.showConfirmDialog(null, "quit program?");
        System.exit(0);

    }
}


class TalkingClock{
    private int interval;
    private boolean beep;


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

    //TimePrinter 可以声明为私有类(private),也可以声明为公有类(public)
    // 当声明为public时,可以通过 main中的注释代码二访问
    public class TimePrinter implements ActionListener{

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

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

}

如果有一个TimePrinter类是一个常规类,它就需要通过TalkingClock类的公有方法访问beep标志,而使用内部类可以给予改进,即不用提供用于访问其他类的访问器 

特殊的语法规则

可以在外部类的作用域之外,这样引用内部类:OuterClass.InnerClass

如上述代码中,若内部类声明为:public(private时则不可以),可以通过如下代码,在main中构建一个TimePrinter对象

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

局部内部类:

从上文代码中,可以了解到,TimePrinter这个类名字只使用了一次(在start方法中创建这个类型的对象中使用过一次),此时可以在start方法中定义局部类,代码如下:

 public void start(){

        class TimePrinter implements ActionListener{

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

        ActionListener listener = this.new TimePrinter();
        Timer t = new Timer(interval, listener);
        t.start();
    }

优势:将TimePrinter类完全隐藏起来。

除了start方法外,没有任何方法知道TimePrinter类的存在,即使是TalkingClock类中的其他代码也不能访问它

注意:1、此时TimePrinter类前面不能有public、private修饰,否则报错;

           2、start方法中创建多个TimePrinter对象,注明以此与匿名内部类做区分。

匿名内部类:

假如只创建这个类的一个对象,甚至连名字都不用命名,这种没有名字的类,称为匿名内部类(annoymous inner class)

start方法代码,可改为如下所示:

   public void start(){
        ActionListener listener = new ActionListener()
        {
            public void actionPerformed(ActionEvent e) {
                System.out.println(" At the tone, the time is " + new Date());
                if (beep)
                    Toolkit.getDefaultToolkit().beep();
            }
        };
        Timer t = new Timer(interval, listener);
        t.start();
    }

含义是:创建了一个实现ActionListener接口的类的新对象,需要实现的方法actionPerformed定义在括号{}内

注意:由于构造器的名字必须和类名相同,而匿名类没有名字,所以匿名类不能有构造器,尤其是在内部类中实现接口时,不能有任何构造参数。

如果构造参数的闭圆括号跟一个开花括号,正在定义的就是匿名内部类,如下代码:

Person cout = new Person("Dracula")
{
    匿名内部类的内容;
};

静态内部类:

  1. 有时候,使用内部类只是为了把一个类隐藏在另外一个类的内部,并不需要内部类引用外部类对象。所以可以把内部类声明为static,以便取消产生的引用
  2. 静态内部类的对象除了没有对生成它的外围类对象的引用特权外,与其他的所有内部类完全一样(但静态内部类可以有静态域和方法,详见下例)
  3. 在内部类不需要访问外围类对象时(即:都是外围类调用它,它不用调用外围类的东西),应该使用静态内部类

注意:当内部类对象是由静态方法中构造出来时,必须使用静态内部类(若该类声明无static,则编译器会报错),如下例代码所示(注:懒得写了,直接拿书上源码来用了):

/**
 * This program demonstrates the use of static inner classes.
 * @version 1.02 2015-05-12
 * @author Cay Horstmann
 */
public class StaticInnerClassTest
{
   public static void main(String[] args)
   {
      double[] d = new double[20];
      for (int i = 0; i < d.length; i++)
         d[i] = 100 * Math.random();
      ArrayAlg.Pair p = ArrayAlg.minmax(d);
      System.out.println("min = " + p.getFirst());
      System.out.println("max = " + p.getSecond());
   }
}

class ArrayAlg
{
   /**
    * A pair of floating-point numbers
    */
   public static class Pair
   {
      private double first;
      private double second;

      /**
       * Constructs a pair from two floating-point numbers
       * @param f the first number
       * @param s the second number
       */
      public Pair(double f, double s)
      {
         first = f;
         second = s;
      }

      /**
       * Returns the first number of the pair
       * @return the first number
       */
      public double getFirst()
      {
         return first;
      }

      /**
       * Returns the second number of the pair
       * @return the second number
       */
      public double getSecond()
      {
         return second;
      }
   }

   /**
    * Computes both the minimum and the maximum of an array
    * @param values an array of floating-point numbers
    * @return a pair whose first element is the minimum and whose second element
    * is the maximum
    */
   public static Pair minmax(double[] values)
   {
      double min = Double.POSITIVE_INFINITY;
      double max = Double.NEGATIVE_INFINITY;
      for (double v : values)
      {
         if (min > v) min = v;
         if (max < v) max = v;
      }
      return new Pair(min, max);
   }
}

此时,Pair类不需要访问外围类对象(即:不需要引用任何其他的对象),且Pair对象是由外部类的静态方法public static Pair minmax(double[] values)构造,故此Pair应该使用static,声明为内部静态类

 

书中有一句“声明在接口中的内部类自动成为static和public类”,不太理解!!!

你可能感兴趣的:(Java)