讀書筆記——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")
{
匿名內部類的內容;
};
靜態內部類:
- 有時候,使用內部類只是爲了把一個類隱藏在另外一個類的內部,並不需要內部類引用外部類對象。所以可以把內部類聲明爲static,以便取消產生的引用
- 靜態內部類的對象除了沒有對生成它的外圍類對象的引用特權外,與其他的所有內部類完全一樣(但靜態內部類可以有靜態域和方法,詳見下例)
- 在內部類不需要訪問外圍類對象時(即:都是外圍類調用它,它不用調用外圍類的東西),應該使用靜態內部類
注意:當內部類對象是由靜態方法中構造出來時,必須使用靜態內部類(若該類聲明無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類”,不太理解!!!