Java基礎(chǔ)之內(nèi)部類

內(nèi)部類的簡介

內(nèi)部類是定義在另一個類中的類。
內(nèi)部類的使用場景

    內(nèi)部類方法可以訪問該類定義所在的作用域中的數(shù)據(jù),包括私有數(shù)據(jù)。
    內(nèi)部類可以對同一個包中的其他類隱藏起來。
    當(dāng)想要定義一個回調(diào)函數(shù)且不想大量編寫代碼是時,使用匿名內(nèi)部類比較便捷

下面我們看一個簡單程序

package com.jay.innerClass;

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

/**
 * Created by xiang.wei on 2018/1/26
 * 描述:構(gòu)造一個語音時鐘
 * @author xiang.wei
 */
public class InnerClassTest {
    public static void main(String[] args) {
        TalkingClock talkingClock = new TalkingClock(1000, true);
        talkingClock.start();
        JOptionPane.showMessageDialog(null,"Quit program?");
    }
}

class TalkingClock {
    /**
     * 發(fā)布通告的時間間隔
     */
    private int interval;
    /**
     * 開關(guān)鈴聲的標(biāo)志
     */
    private boolean beep;

    public TalkingClock(int interval, boolean beep) {
        this.interval = interval;
        this.beep = beep;
    }
    public void start() {
        ActionListener listener = new TimePrinter();
        Timer timer = new Timer(interval, listener);
        timer.start();

    }

    public class TimePrinter implements ActionListener {

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



在說明2中,我們看到了內(nèi)部類直接引用了外部類的been變量。這里他是如何能引用的呢?
我們將外圍類對象的引用稱為outer。(outer不是Java的關(guān)鍵字)
外圍類的引用在構(gòu)造器中設(shè)置。編譯器修改了所有內(nèi)部類的構(gòu)造器。添加了一個外部類引用的參數(shù)。
如上例中,編譯器為這個類生成了一個默認(rèn)的構(gòu)造器。其代碼如下:

  public TimerPrint(TalkingClock clock){
    outer=clock
  }

當(dāng)在start 方法中創(chuàng)建了TimerPrinter對象后,編譯器就會將this引用傳遞給當(dāng)前的語音時鐘的構(gòu)造器
ActionListener listener = new TimerPrinter(this)
內(nèi)部類的特殊語法規(guī)則

    內(nèi)部類中聲明的所有靜態(tài)域都必須是final,原因很簡單。我們希望一個靜態(tài)域只有一個實(shí)例,不過對于每個外部對象,
    會分別有一個單獨(dú)的內(nèi)部類實(shí)例。如果這個域不是final,它可能就不是唯一的。
    內(nèi)部類中不能有static方法。Java語言規(guī)范對這個限制沒有做任何解釋。也可以允許有靜態(tài)方法,但只能訪問外部類的靜態(tài)域
    和方法。

局部內(nèi)部類

局部內(nèi)部類就是在方法內(nèi)部定義的一個內(nèi)部類。對外部世界是完全隱藏起來的。即使是外部類類本身的其他的方法也不能訪問
如下例所示:

 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 = new TimePrinter();
    javax.swing.Timer timer = new javax.swing.Timer(interval, listener);
    timer.start();
}


該方法的控制流程是
1. 調(diào)用start方法
2. 調(diào)用內(nèi)部類TimePrinter的構(gòu)造器,以便初始化對象listener
3. 將listener引用傳遞給Timer構(gòu)造器,定時器開始計時,start方法結(jié)束,此時start
方法的beep參數(shù)變量不復(fù)存在。
4. 然后,actionPerformed 方法執(zhí)行if(beep)…

假設(shè)想更新在一個封閉作用域內(nèi)的計數(shù)器。這里想要統(tǒng)計一下在排序過程中調(diào)用
compareTo 方法的次數(shù)

 public void start2() {
        int counter = 0;
        Date[] dates = new Date[100];
        for (int i = 0; i < dates.length; i++) {
            dates[i] = new Date(){
                public int compareTo(Date other) {
                    counter++;  //ERROR
                    return super.compareTo(other);
                }
            };
            Arrays.sort(dates);
            System.out.println(counter+"comparisons");
        }
    }


可以替代的方案是:

 public void start2() {
        int[] counter = new int[1];
        Date[] dates = new Date[100];
        for (int i = 0; i < dates.length; i++) {
            dates[i] = new Date(){
                @Override
                public int compareTo(Date other) {
                    counter[0]++;  //ERROR
                    return super.compareTo(other);
                }
            };
            Arrays.sort(dates);
            System.out.println(counter+"comparisons");
        }
    }


匿名內(nèi)部類

只創(chuàng)建了一個類的一個對象。
由于構(gòu)造器的名字必須與類名相同,而匿名內(nèi)部類沒有類名。所以,匿名類不能有構(gòu)造器。取而代之的是,將構(gòu)造器參數(shù)
傳遞給超類構(gòu)造器。尤其是在內(nèi)部類實(shí)現(xiàn)接口的時候,不能有任何構(gòu)造參數(shù)。




作者:碼農(nóng)飛哥
微信公眾號:碼農(nóng)飛哥