標籤:內部類 物件導向 java 對象 匿名內部類
一、前言
內部類也稱寄生類,就是把一個類放在類裡面(即內部類的上一級程式單元是類)定義,將其作為外部類的成員。內部類主要用幾種定義形式:靜態(static)內部類,非靜態內部類,匿名內部類(也就是沒有名字的寄生類)。內部類的好處就是內部類可以直接外部類的(包括私人)成員,反之不能。下面我們通過一些執行個體來詳細講解一下Java中內部類的使用及幾種定義形式的相互調用。
二、執行個體說明
(1)匿名內部類:當程式建立匿名內部類時,會立即建立匿名內部類(實作類別)的執行個體。
interface IBreathe {void breathe();}/** * 匿名內部類的使用,定義形式如下: * * new 介面() | 父類構造器<參數>){ * // 類體部分... * }; * * @author [*昨日重現*] [email protected] * @since version 1.0 * @datetime 2015年4月29日 下午10:17:40 */public class Anonymous {// 這裡相當於建立了介面IBreathe的匿名實作類別,並建立了匿名內部類的執行個體// 將實作類別的執行個體賦值給介面變數 ,屬於向上轉型IBreathe breathe = new IBreathe() {// 必須實現介面裡的所有抽象方法@Overridepublic void breathe() {System.out.println("呼吸新鮮空氣...");}};public static void main(String[] args) {Anonymous anonymous = new Anonymous();anonymous.breathe.breathe();}}
注意以下幾點:
1)只要父類是抽象類別或者是一個介面,那麼其子類中的方法都可以使用匿名內部類來實現;反過來也就是說使用匿名內部類有個前提:它必須顯示地繼承一個父類或實現一個介面。
2)匿名內部類必須實現介面或抽象類別中所有的抽象方法。
3)匿名內部類適合建立只需一次使用的類。
4)匿名內部類不能有構造器而且程式以後無法再訪問它,因為它沒有類名。
(2)靜態內部類:它屬於外部類(宿主類)的靜態成員,所以它不能訪問外部類的非靜態成員(屬性、方法)。
/** * 外部類(宿主類)中包含靜態內部類作為外部類的一個靜態成員 * * @author [*昨日重現*] [email protected] * @since version 1.0 * @datetime 2015年4月29日 下午11:00:51 */public class Out {private static String name = "張三";private String sex = "男";static class In {private static String name = "李四";public void info() {// 靜態內部類不能訪問外部類的非靜態成員,所以下面這句會編譯不通過// System.out.println("外部類的sex = " + sex);System.out.println("in的info方法被調用,name:" + name);}}public static void main(String[] args) {// 列印結果(編譯器遵循就近原則):in的info方法被調用,name:李四// 這裡只需要把外部類當成靜態內部類的包就行了// 所以In前加不加Out.都是一樣的new In().info();new Out.In().info();}}
如果要在外部類的外面訪問靜態內部類的成員:Out.In in = new Out.In(); in.info();當然,靜態內部類也可以派生子類:class InSub extends Out.In {},編寫和調用方式與普通類一樣,這裡不再贅述。下面看看重點來看看非靜態內部類定義和使用。
(3)非靜態內部類:在建立非靜態內部類的執行個體前,必須先建立外部類執行個體,也就是說非靜態內部類必須寄生在外部類的執行個體(Outer.this)裡面。所以在建立非靜態內部類的執行個體前,必須先建立外部類執行個體。
/** * 非靜態內部類的使用 * * @author [*昨日重現*] [email protected] * @since version 1.0 * @datetime 2015年4月29日 下午11:26:06 */public class Outer {int number = 10;// 定義非靜態內部類class Inner {int number = 100;public void info() {int number = 1000;System.out.println("Inner內部類的info()方法被調用~");System.out.println("number變數的值為:" + number);// 方法的局部變數,所以為1000System.out.println("number變數的值為:" + this.number);// 指向寄生類成員,所以為100System.out.println("number變數的值為:" + Outer.this.number);// 指向宿主類成員,所以為10}}/** * 通過外部類的方法來訪問寄生類的成員(屬性、方法) */public void info() {System.out.println("Outer外部類的info()方法被調用~");Inner inner = new Inner();inner.info();System.out.println(inner.number);}public static void main(String[] args) {new Outer().info();}}如果在外部類的外面使用內部類,那麼在建立非靜態內部類的執行個體前,必須先建立外部類執行個體。
Outer outer = new Outer();
Outer.Inner in = outer.new Inner();
等價於==》Outer.Inner in2 = new Outer().new Inner();
當然非靜態內部類也可以派生子類,如下:
//非靜態內部類派生子類class InnerSub extends Outer.Inner {public InnerSub() {// 由於Outer.Inner是非靜態內部類,因此必須使用"宿主對象"來調用它的構造器new Outer().super();}}
三、總結
1)有static修飾的內部類屬於外部類本身,沒有static修飾的內部類屬於類執行個體 。
2)記住方法是誰的,就用誰來調用。
3)沒有static修飾的內部類,【必須寄生在“外部類”的執行個體裡】;反之則寄生在外部類本身裡。
4)靜態內部類是寄生在類本身裡面的,所以就不需要程式員理會宿主。-把外部類當成靜態內部類的包就行了。
5)非靜態內部類派生子類:由於子類的構造器必須調用父類構造器一次,因此必須在子類構造器中使用宿主對象來調用它的構造器。
四、結束語
關於Java中的內部類的定義和使用基本內容就這些,後面會陸續更新包括:Regex、Java效能最佳化、學習JVM等等,敬請關注。
Java學習系列(二十三)Java物件導向之內部類詳解