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)飛哥