Java 内部類種類及使用解析
内部類Inner Class
将相關的類組織在一起,進而降低了命名空間的混亂。
一個内部類可以定義在另一個類裡,可以定義在函數裡,甚至可以作為一個表達式的一部分。
Java中的内部類共分為四種:
靜态内部類static inner class (also called nested class)
成員内部類member inner class
局部内部類local inner class
匿名内部類anonymous inner class
靜态内部類Static Inner Class
最簡單的内部類形式。
類定義時加上static關鍵字。
不能和外部類有相同的名字。
被編譯成一個完全獨立的.class檔案,名稱為OuterClass$InnerClass.class的形式。
隻可以通路外部類的靜态成員和靜态方法,包括了私有的靜态成員和方法。
生成靜态内部類對象的方式為:
OuterClass.InnerClass inner = new OuterClass.InnerClass();
靜态内部類使用代碼:

package com.learnjava.innerclass;
class StaticInner
{
private static int a = 4;
// 靜态内部類
public static class Inner
{
public void test()
{
// 靜态内部類可以通路外部類的靜态成員
// 并且它隻能通路靜态的
System.out.println(a);
}
}
}
public class StaticInnerClassTest
{
public static void main(String[] args)
{
StaticInner.Inner inner = new StaticInner.Inner();
inner.test();
}
}
成員内部類Member Inner Class
成員内部類也是定義在另一個類中,但是定義時不用static修飾。
成員内部類和靜态内部類可以類比為非靜态的成員變量和靜态的成員變量。
成員内部類就像一個執行個體變量。
它可以通路它的外部類的所有成員變量和方法,不管是靜态的還是非靜态的都可以。
在外部類裡面建立成員内部類的執行個體:
this.new Innerclass();
在外部類之外建立内部類的執行個體:
(new Outerclass()).new Innerclass();
在内部類裡通路外部類的成員:
Outerclass.this.member
詳情見代碼例子:

package com.learnjava.innerclass;
class MemberInner
{
private int d = 1;
private int a = 2;
// 定義一個成員内部類
public class Inner2
{
private int a = 8;
public void doSomething()
{
// 直接通路外部類對象
System.out.println(d);
System.out.println(a);// 直接通路a,則通路的是内部類裡的a
// 如何通路到外部類裡的a呢?
System.out.println(MemberInner.this.a);
}
}
}
public class MemberInnerClassTest
{
public static void main(String[] args)
{
// 建立成員内部類的對象
// 需要先建立外部類的執行個體
MemberInner.Inner2 inner = new MemberInner().new Inner2();
inner.doSomething();
}
}
局部内部類Local Inner Class
局部内部類定義在方法中,比方法的範圍還小。是内部類中最少用到的一種類型。
像局部變量一樣,不能被public, protected, private和static修飾。
隻能通路方法中定義的final類型的局部變量。
局部内部類在方法中定義,是以隻能在方法中使用,即隻能在方法當中生成局部内部類的執行個體并且調用其方法。

package com.learnjava.innerclass;
class LocalInner
{
int a = 1;
public void doSomething()
{
int b = 2;
final int c = 3;
// 定義一個局部内部類
class Inner3
{
public void test()
{
System.out.println("Hello World");
System.out.println(a);
// 不可以通路非final的局部變量
// error: Cannot refer to a non-final variable b inside an inner
// class defined in a different method
// System.out.println(b);
// 可以通路final變量
System.out.println(c);
}
}
// 建立局部内部類的執行個體并調用方法
new Inner3().test();
}
}
public class LocalInnerClassTest
{
public static void main(String[] args)
{
// 建立外部類對象
LocalInner inner = new LocalInner();
// 調用外部類的方法
inner.doSomething();
}
}
匿名内部類Anonymous Inner Class
匿名内部類就是沒有名字的局部内部類,不使用關鍵字class, extends, implements, 沒有構造方法。
匿名内部類隐式地繼承了一個父類或者實作了一個接口。
匿名内部類使用得比較多,通常是作為一個方法參數。

package com.learnjava.innerclass;
import java.util.Date;
public class AnonymouseInnerClass
{
@SuppressWarnings("deprecation")
public String getDate(Date date)
{
return date.toLocaleString();
}
public static void main(String[] args)
{
AnonymouseInnerClass test = new AnonymouseInnerClass();
// 列印日期:
String str = test.getDate(new Date());
System.out.println(str);
System.out.println("----------------");
// 使用匿名内部類
String str2 = test.getDate(new Date()
{
});// 使用了花括号,但是不填入内容,執行結果和上面的完全一緻
// 生成了一個繼承了Date類的子類的對象
System.out.println(str2);
System.out.println("----------------");
// 使用匿名内部類,并且重寫父類中的方法
String str3 = test.getDate(new Date()
{
// 重寫父類中的方法
@Override
@Deprecated
public String toLocaleString()
{
return "Hello: " + super.toLocaleString();
}
});
System.out.println(str3);
}
}
生成的.class檔案中,匿名類會生成OuterClass$1.class檔案,數字根據是第幾個匿名類而類推。
Swing中使用内部類的例子如下:

package com.learnjava.innerclass;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JButton;
import javax.swing.JFrame;
public class SwingTest
{
public static void main(String[] args)
{
JFrame frame = new JFrame("JFrame");
JButton button = new JButton("JButton");
button.addActionListener(new ActionListener()
{
// new出來一個實作了ActionListener接口的類的執行個體
@Override
public void actionPerformed(ActionEvent arg0)
{
System.out.println("Hello World");
}
});
//加入按鈕
frame.getContentPane().add(button);
//設定關閉行為
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(200, 200);
frame.addWindowListener(new WindowAdapter()
{
//也可以使用繼承了擴充卡類的匿名内部類
@Override
public void windowClosing(WindowEvent e)
{
System.out.println("Closing");
System.exit(0);
}
});
frame.setVisible(true);
}
}
參考資料
張龍老師Java SE系列視訊教程。