內部類就是定義在另一個類中的類,使用內部類的理由主要有以下三點:
1)內部類方法可以訪問該類定義在作用域中的數據,包括私有數據。
2)內部類可以對同一個包中的其他類隱藏起來。
3)當想要定義一個回調函數且不想編寫大量代碼時,使用匿名內部類比較便捷。
內部類根據定義的位置不同,可以分爲四種,第一種就是普通的內部類,第二種是局部內部類,第三種是匿名內部類,第四種是靜態內部類。
這裏只需強調一點即可,就是爲了運行使用了其外部實例域的內部類,內部類對象中總有一個隱式引用,它指向了創建它的外部類對象,因此其內部類可以使用其外部類的實例域。
當然,既然有隱式引用,當然可以顯式的表達出來了。
對於內部類引用外部類中數據,可以使用以下語法:外部類名.this.數據名
例如下面例子中的:
if(beep)可以顯式的寫爲if(TalkingClock.this.beep)
創建一個內部類對象的時候也可以顯式的說明,可以使用以下語法:內部類名 對象名=this.new 內部類名(參數);
例如下面例子中的:
ActionListener listener=new TimePrinter();可以顯式的寫爲ActionListener listener=this.new TimePrinter();
下面是一個完整的例子:
代碼:
package InnerClasses;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Date;
import javax.swing.JOptionPane;
import javax.swing.Timer;
public class InnerClassTest {
public static void main(String[] args) {
TalkingClock clock = new TalkingClock(1000,true);
clock.start();
JOptionPane.showMessageDialog(null,"關閉??");
System.exit(0);
}
}
class TalkingClock{
private int interval;
private boolean beep;
public TalkingClock(int interval,boolean beep) {
this.interval=interval;
this.beep=beep;
}
public void start() {
ActionListener listener=new TimePrinter();
Timer t=new Timer(interval,listener);
t.start();
}
private class TimePrinter implements ActionListener{
@Override
public void actionPerformed(ActionEvent arg0) {
System.out.println("現在時間是:"+new Date());
if(beep) {
Toolkit.getDefaultToolkit().beep();
}
}
}
}
運行結果:
對於第二種內部類--局部內部類,其實是定義在類方法中的內部類,這種類不能使用訪問修飾符,而且這種類的作用域被限制在聲明這個局部類的塊中。同一般的內部類相比,局部內部類還有一個優勢就是可以訪問局部變量。
例如上面的代碼可以修改爲:
代碼:
package InnerClasses;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Date;
import javax.swing.JOptionPane;
import javax.swing.Timer;
public class InnerClassTest {
public static void main(String[] args) {
TalkingClock clock = new TalkingClock(1000,true);
clock.start();
JOptionPane.showMessageDialog(null,"關閉??");
System.exit(0);
}
}
class TalkingClock{
private int interval;
private boolean beep;
public TalkingClock(int interval,boolean beep) {
this.interval=interval;
this.beep=beep;
}
public void start() {
class TimePrinter implements ActionListener{
@Override
public void actionPerformed(ActionEvent arg0) {
System.out.println("現在時間是:"+new Date());
if(beep) {
Toolkit.getDefaultToolkit().beep();
}
}
}
ActionListener listener=new TimePrinter();
Timer t=new Timer(interval,listener);
t.start();
}
}
輸出結果和上一例子一樣。
第三種內部類--匿名內部類:
這種內部類更加直接,沒有類名。
具體語法爲:
類名 對象名=new 類名(構造參數){
內部類方法和數據
}
類名也可以是接口名,如果是接口名,則就像下面這樣子了:
接口名 對象名=new 接口名(){
方法和數據
}
下面是一個例子:
package InnerClasses;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Date;
import javax.swing.JOptionPane;
import javax.swing.Timer;
public class AnonyInnerClassTest {
public static void main(String[] args) {
TalkingClock2 clock =new TalkingClock2();
clock.start(1000, true);
JOptionPane.showMessageDialog(null, "退出??");
System.exit(0);
}
}
class TalkingClock2{
public void start(int interval,boolean beep) {
ActionListener listener=new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
System.out.println("現在的時間是:"+new Date());
if(beep) {
Toolkit.getDefaultToolkit().beep();
}
}
};
Timer t=new Timer(interval,listener);
t.start();
}
}
運行結果和前兩個例子一樣。
第四種內部類--靜態內部類
靜態內部類的目的很簡單,就是爲了把一個類隱藏在另一個類的內部。這時,可以將內部類聲明爲static。
靜態內部類中不可以引用外部類的非靜態變量和方法,而在靜態內部類中可以有靜態域和靜態方法。
下面是一個例子:用於計算一個double型數組的最大值和最小值。
代碼:
package InnerClasses;
public class StaticInnerClass {
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{
public static class Pair{
private double first;
private double second;
public Pair(double f,double s) {
first=f;
second=s;
}
public double getFirst() {
return first;
}
public double getSecond() {
return second;
}
}
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);
}
}
運行結果: