天天看點

Java嵌套類(Nested Classes)總結

在java語言規範裡面,嵌套類(nested classes)定義是:

a nested class is any class whose declaration occurs within the body of another class or interface. a top level class is a class that is not a nested class. 

說的簡單一點,就是定義在類裡面的類。一般把定義内部類的外圍類成為包裝類(enclosing class)或者外部類

根據nested class定義的地方,可以分為member nested class,local nested class , anonymous nested class

member nested class(成員嵌套類) :成員嵌套類 作為 enclosing class 的成員定義的,成員嵌套類有enclosing class屬性

local nested class (局部嵌套類): 局部嵌套類定義在 enclosing class 的方法裡面,局部嵌套類有enclosing class 屬性和enclosing method 屬性

anonymous nested class(匿名嵌套類):匿名嵌套類沒有顯示的定義一個類,直接通過new 的方法建立類的執行個體。一般回調模式情況下使用的比較多

member nested class 可以使用public,private,protected通路控制符,也可以用static,final關鍵字

local nested class 可以使用final關鍵字

anonymous nested class 不使用任何關鍵字和通路控制符

見下面的代碼

<code>public</code> <code>class</code> <code>enclosingclass {</code>

<code>    </code><code>public</code> <code>static</code> <code>final</code> <code>class</code> <code>nestedmemberclass {</code>

<code>    </code><code>}</code>

<code>    </code><code>public</code> <code>void</code> <code>nestedlocalclass() {</code>

<code>        </code><code>final</code> <code>class</code> <code>nestedlocalclass {</code>

<code>        </code><code>}</code>

<code>    </code><code>public</code> <code>void</code> <code>nestedanonymousclass() {</code>

<code>        </code><code>new</code> <code>runnable() {</code>

<code>            </code><code>@override</code>

<code>            </code><code>public</code> <code>void</code> <code>run() {</code>

<code>            </code><code>}</code>

<code>        </code><code>};</code>

<code>}</code>

 如果你想學習java可以來這個群,首先是二二零,中間是一四二,最後是九零六,裡面有大量的學習資料可以下載下傳

在大多數情況下,一般把nested classes 分為兩種:

static nested classes(靜态嵌套類): 就是用static修飾的成員嵌套類

innerclass:靜态嵌套類之外所有的嵌套類的總稱,也就是沒有用static定義的nested classes,inner classes 不能定義為static,不能有static方法和static初始化語句塊。在jls(java語言規範)裡面是這麼定義的:

an inner class is a nested class that is not explicitly or implicitly declared static. inner classes may not declare static initializers (§8.7) or member inter- faces 

其中inner class又可以分為三種:

1 inner member classes :沒有用static 修飾的成員内部類

2 local inner classes : 定義在方法裡面的内部類,方法可以是static的也可以是非static的,也可以是構造器方法。

3 anonymous inner classes :定義在方法裡面匿名類,方法可以是static的也可以是非static的

static nested classes 以及 inner classes 有一些限制規則,下面介紹一下這些規則。

static nested classes通路規則

用static修飾的nested classes,隻能通路外部類的非static變量。對于public 的 static nested classes 可以用 new 外部類.内部類()的方式直接建立。而預設的static nested classes 可以在同一包名下,用 new 外部類.内部類()的方式建立。其實和外部類的方式差不多。靜态成員類可以使用通路控制符,可以使用static修飾,可以是abstract抽象類

<code>public</code> <code>class</code> <code>staticnestedclass {</code>

<code>    </code><code>// 私有局部</code>

<code>    </code><code>private</code> <code>int</code> <code>i =</code><code>0</code><code>;</code>

<code>    </code><code>// 靜态</code>

<code>    </code><code>public</code> <code>static</code> <code>int</code> <code>j =</code><code>0</code><code>;</code>

<code>    </code><code>// 不變值</code>

<code>    </code><code>private</code> <code>final</code> <code>int</code> <code>k =</code><code>0</code><code>;</code>

<code>    </code><code>// static final</code>

<code>    </code><code>private</code> <code>static</code> <code>final</code> <code>int</code> <code>m =</code><code>0</code><code>;</code>

<code>    </code><code>// 靜态嵌套内,這裡不是innerclass,可以直接new出來</code>

<code>    </code><code>public</code> <code>static</code> <code>class</code> <code>publicnestedclass {</code>

<code>        </code><code>private</code> <code>void</code> <code>test1() {</code>

<code>            </code><code>// system.out.println(i); 非innerclass不能通路enclosing類的非static屬性</code>

<code>            </code><code>system.out.println(j);</code>

<code>            </code><code>system.out.println(m);</code>

<code>            </code><code>// system.out.println(k); 非innerclass不能通路enclosing類的非static屬性</code>

<code>        </code><code>// 可以定義static方法</code>

<code>        </code><code>private</code> <code>static</code> <code>void</code> <code>test2() {</code>

<code>    </code><code>// 靜态嵌套内,這裡不是innerclass,由于是私有的,不可以直接new出來</code>

<code>    </code><code>private</code> <code>static</code> <code>class</code> <code>privatenestedclass {</code>

  

下面的例子示範了static nested class的建立

<code>public</code> <code>class</code> <code>testclass {</code>

<code>    </code><code>public</code> <code>static</code> <code>void</code> <code>main(string[] args) {</code>

<code>        </code> 

<code>        </code><code>//任何地方都可以建立</code>

<code>        </code><code>staticnestedclass.publicnestedclass publicnestedclass =</code><code>new</code> <code>staticnestedclass.publicnestedclass();</code>

<code>        </code><code>//可以在同一package下建立</code>

<code>        </code><code>staticnestedclass.defaultnestedclass defaultnestedclass =</code><code>new</code> <code>staticnestedclass.defaultnestedclass();</code>

<code>        </code><code>//編譯錯誤,無法通路内部内</code>

<code>        </code><code>//staticnestedclass.privatenestedclass privatenestedclass = new staticnestedclass.privatenestedclass();</code>

inner class通路規則

inner member classes(内部成員類) 可以通路外部類的所有執行個體屬性,靜态屬性。因為内部成員類持有一個外部對象的引用,内部類的執行個體可以對外部類的執行個體屬性進行修改。如果是public的 inner  member classes,可以通過 外部類執行個體.new 内部類()的方式進行建立,當調用内部類的構造器的時候,會把目前建立的内部類對象執行個體中持有的外部對象引用指派為目前建立内部類的外部類執行個體。内部成員類可以是使用通路控制符,可以定義為final,也可以是抽象類。

<code>public</code> <code>class</code> <code>memberinnerclass {</code>

<code>    </code><code>public</code> <code>int</code> <code>i =</code><code>0</code><code>;</code>

<code>    </code><code>private</code> <code>static</code> <code>int</code> <code>j =</code><code>0</code><code>;</code>

<code>    </code><code>public</code> <code>class</code> <code>publicmemberinnerclass {</code>

<code>        </code><code>// enclosing class的屬性都可以通路</code>

<code>        </code><code>public</code> <code>void</code> <code>test() {</code>

<code>            </code><code>system.out.println(i);</code>

<code>            </code><code>system.out.println(k);</code>

<code>        </code><code>public</code> <code>memberinnerclass getoutterclass() {</code>

<code>            </code><code>return</code> <code>memberinnerclass.</code><code>this</code><code>;</code>

<code>        </code><code>// 這裡會報錯,不允許定義static方法</code>

<code>        </code><code>// private static final void test();</code>

<code>    </code><code>// 私有的innerclass 外部不能通路</code>

<code>    </code><code>private</code> <code>class</code> <code>privatememberinnerclass {</code>

<code>    </code><code>// 公開局部類,外部可以通路和建立,但是隻能通過outterclass執行個體建立</code>

<code>    </code><code>class</code> <code>defaultmemberinnerclass {</code>

下面例子示範了内部成員類的建立

<code>        </code><code>// 任何地方都可以建立</code>

<code>        </code><code>memberinnerclass t =</code><code>new</code> <code>memberinnerclass();</code>

<code>        </code><code>// 可以建立,pmic裡面儲存對t的引用</code>

<code>        </code><code>memberinnerclass.publicmemberinnerclass pmic = t.</code><code>new</code> <code>publicmemberinnerclass();</code>

<code>        </code><code>// 可以在同一package下建立,dmic儲存對t的引用</code>

<code>        </code><code>memberinnerclass.defaultmemberinnerclass dmic = t.</code><code>new</code> <code>defaultmemberinnerclass();</code>

<code>        </code><code>// 編譯錯誤,無法通路内部内</code>

<code>        </code><code>// memberinnerclass.privatememberinnerclass pmic = t.new</code>

<code>        </code><code>// privatememberinnerclass();</code>

<code>        </code><code>// 下面驗證一下outterclass是同一個對象</code>

<code>        </code><code>system.out.println(pmic.getoutterclass() == t);</code>

<code>        </code><code>system.out.println(dmic.getoutterclass() == t);</code>

 運作程式,列印結果:

<code>true</code>

2 local inner classes(局部類)

局部類 定義在類方法裡面。這個方法既可以是靜态方法,也可以是執行個體方法,也可以是構造器方法或者靜态初始化語句塊。

局部類可以定義在一個static上下文裡面 和 非static上下文裡面。局部類不能有通路控制符(private,public,protected修飾),可以是抽象的,也可以定義為final

定義在static上下文(static 字段初始化,static初始化塊,static方法)裡面的local inner classes 可以通路類的靜态屬性,如果定義在靜态方法裡面的局部類,還可以方法裡面定義的final變量。在static上下文定義的局部類,沒有指向父類執行個體變量的引用,因為static方法不屬于類的執行個體,屬于類本身。而且局部類不能在外部進行建立,隻能在方法調用的時候進行建立

<code>public</code> <code>class</code> <code>localinnerclass {</code>

<code>    </code><code>public</code> <code>static</code> <code>void</code> <code>test() {</code>

<code>        </code><code>final</code> <code>int</code> <code>a =</code><code>0</code><code>;</code>

<code>        </code><code>int</code> <code>b =</code><code>0</code><code>;</code>

<code>        </code><code>// local inner class不能夠有通路控制符 比如public private</code>

<code>        </code><code>abstract</code> <code>class</code> <code>localstaticinnerclass {</code>

<code>            </code><code>// local inner class不能定義靜态屬性</code>

<code>            </code><code>// private static int c;</code>

<code>            </code><code>private</code> <code>int</code> <code>d =</code><code>0</code><code>;</code>

<code>            </code><code>public</code> <code>localstaticinnerclass() {</code>

<code>                </code><code>// 可以通路方法裡面定義的final 變量</code>

<code>                </code><code>system.out.println(a);</code>

<code>                </code><code>// 不能通路b 因為b不是final</code>

<code>                </code><code>// system.out.println(b);      </code>

<code>                </code><code>// 定義在static上下文裡面的local inner class 不能通路外部類的非static字段</code>

<code>                </code><code>// system.out.println(i);</code>

<code>                </code><code>// system.out.println(k);</code>

<code>                </code><code>system.out.println(j);</code>

<code>                </code><code>system.out.println(m);</code>

<code>            </code><code>// local inner class不能定義靜态方法</code>

<code>            </code><code>// public static void test(){}</code>

<code>    </code><code>public</code> <code>void</code> <code>test2() {</code>

<code>        </code><code>final</code> <code>class</code> <code>localnonstaticinnerclass{  </code>

<code>            </code><code>public</code> <code>localnonstaticinnerclass() {</code>

<code>                </code><code>//定義在非static上下文的local inner class 可以通路外部類的所有屬性</code>

<code>                </code><code>system.out.println(i);</code>

<code>                </code><code>system.out.println(k);</code>

 

 3 anonymous inner classes (匿名類)也是定義在方法裡面,匿名類和局部類通路規則一樣,隻不過内部類顯式的定義了一個類,然後通過new的方式建立這個局部類執行個體,而匿名類直接new一個類執行個體,沒有定義這個類。匿名類最常見的方式就是回調模式的使用,通過預設實作一個接口建立一個匿名類然後,然後new這個匿名類的執行個體。

<code>public</code> <code>class</code> <code>anonymousinnerclass {</code>

<code>    </code><code>//通路規則和局部類一樣</code>

<code>    </code><code>public</code> <code>void</code> <code>test() {</code>

<code>        </code><code>//匿名類實作</code>

<code>        </code><code>new</code> <code>thread(</code><code>new</code> <code>runnable() {</code>

<code>        </code><code>}).start();</code>

<code>        </code><code>//非匿名類實作</code>

<code>        </code><code>class</code> <code>noneanonymousclass</code><code>implements</code> <code>runnable{</code>

<code>        </code><code>}  </code>

<code>        </code><code>noneanonymousclass t =</code><code>new</code> <code>noneanonymousclass();</code>

<code>        </code><code>new</code> <code>thread(t).start();</code>

嵌套類是可以有層次的,也就是說嵌套類裡面還是定義類,成為嵌套類中的嵌套類。虛拟機如何保證嵌套類正确的嵌套層層次?

對于merber class,内部嵌套類的可以表示為 a$b 其中a為外部類,b為内部成員類 ,如果b裡面又有成員為c的嵌套類,那麼c就可以表示為a$b$c,如果a定義了兩個同名member class,那麼編譯器就會報錯。如果b裡面又包含了為名b的nested class,則編譯器會報錯.

對于local inner class,局部類可以表示為a$1b的方式,其中a為外部類,b為第一個局部類 如果在不同的方法裡面定義了同名的局部類b,編譯器是可以編譯通過的,那麼定義的第二個局部類b可以表示為a$2b,如果在同一個方法裡面同定義兩個相同的局部類b,那麼編譯錯是要報錯的。如果b裡面又定義了同名的成員類,則可以表示為a$1b$b。

對于anonymous inner classes,匿名類可以表示為a$1的方式,代表程式裡面有一個匿名類。如果有n個,可以表示為a$n的方式(n為自然數).

看看下面的例子

<code>public</code> <code>class</code> <code>nestedclasslevel {</code>

<code>    </code><code>class</code> <code>a {</code>

<code>        </code><code>// 編譯器會報錯,a裡面不能在定義名為a的nested classes</code>

<code>        </code><code>// class a{}</code>

<code>            </code><code>class</code> <code>b {</code>

<code>    </code><code>//可以在繼續定義b</code>

<code>    </code><code>class</code> <code>b {</code>

<code>        </code><code>public</code> <code>void</code> <code>test(){</code>

<code>            </code><code>//可以無限定義匿名類</code>

<code>            </code><code>new</code> <code>runnable() {</code>

<code>                </code><code>public</code> <code>void</code> <code>run() {</code>

<code>                    </code><code>//可以無限定義匿名類</code>

<code>                    </code><code>new</code> <code>runnable() {           </code>

<code>                        </code><code>public</code> <code>void</code> <code>run() {        </code>

<code>                        </code><code>}</code>

<code>                    </code><code>};</code>

<code>                </code><code>}</code>

<code>            </code><code>};</code>

<code>    </code><code>// 隻能定義一個b</code>

<code>    </code><code>// class b{}</code>

<code>        </code><code>// 可以定義a</code>

<code>        </code><code>class</code> <code>a {</code>

<code>            </code><code>public</code> <code>void</code> <code>test() {</code>

<code>                </code><code>//可以有同名的局部類b和成員類b</code>

<code>                </code><code>class</code> <code>b {</code>

<code>                    </code><code>public</code> <code>void</code> <code>test() {</code>

<code>                        </code> 

<code>                    </code><code>}</code>

<code>                </code><code>//局部類a裡面不能在定義a</code>

<code>                </code><code>//class a{}</code>

<code>        </code><code>//可以有同名的局部類b和成員類b</code>

<code>        </code><code>class</code> <code>b {</code>

對于定義在非static上下文裡面的nested類層次,比如a$b$1c ,則最内層的嵌套類c有一個指向b執行個體的引用,b有一個指向a執行個體的引用,最終最内層的嵌套類可以通路a中的屬性可以方法,一般把b成為a的直接嵌套類。但是a不可以通路b或者c中屬性或者方法。

由于interface預設是定義為一個 public static的特殊類,是以interface可以直接作為 static member class。可以通過a.b的方式進行通路。

在java提供的基本類庫裡面,大量使用nested classes。比如我們知道的map類。其中 map類裡面有一個定義了entry類abstract inner class。是以我們在周遊map的時候,一般使用

for (map.entry entry:map.entryset()){

}

總結:nested類是java裡面比較複雜的一個概念,必須詳細了解jvm中對于嵌套類的實作以及java編譯器對嵌套類的處理才可以深入了解嵌套類細節。