讀書筆記——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類”,不太理解!!!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章