java嵌套類(Nested Classes)總結

attention:

1.本文轉載自 http://www.cnblogs.com/aigongsi/archive/2012/04/24/2467183.html  

2.文章最後有原blog信息


-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

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 不使用任何關鍵字和訪問控制符

見下面的代碼

public class EnclosingClass {
 
    public static final class NestedMemberClass {
 
    }
 
    public void nestedLocalClass() {
 
        final class NestedLocalClass {
 
        }
    }
 
    public void nestedAnonymousClass() {
 
        new Runnable() {
 
            @Override
            public void run() {
            }
        };
    }
}


 

在大多數情況下,一般把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抽象類

 

public class StaticNestedClass {
 
    // 私有局部
    private int i = 0;
 
    // 靜態
    public static int j = 0;
 
    // 不變值
    private final int k = 0;
 
    // static final
    private static final int m = 0;
 
    // 靜態嵌套內,這裏不是innerclass,可以直接new出來
    public static class PublicNestedClass {
 
        private void test1() {
            // System.out.println(i); 非innerClass不能訪問enclosing類的非static屬性
            System.out.println(j);
            System.out.println(m);
            // System.out.println(k); 非innerClass不能訪問enclosing類的非static屬性
        }
 
        // 可以定義static方法
        private static void test2() {
 
        }
    }
 
    // 靜態嵌套內,這裏不是innerclass,由於是私有的,不可以直接new出來
    private static class PrivateNestedClass {
 
    }
}


  

下面的例子演示了static Nested class的創建

public class TestClass {
 
    public static void main(String[] args) {
         
        //任何地方都可以創建
        StaticNestedClass.PublicNestedClass publicNestedClass = new StaticNestedClass.PublicNestedClass();
         
        //可以在同一package下創建
        StaticNestedClass.DefaultNestedClass defaultNestedClass = new StaticNestedClass.DefaultNestedClass();
        //編譯錯誤,無法訪問內部內
        //StaticNestedClass.PrivateNestedClass privateNestedClass = new StaticNestedClass.PrivateNestedClass();
    }
}


  

  • Inner Class訪問規則

inner member classes(內部成員類) 可以訪問外部類的所有實例屬性,靜態屬性。因爲內部成員類持有一個外部對象的引用,內部類的實例可以對外部類的實例屬性進行修改。如果是public的 inner  member classes,可以通過 外部類實例.new 內部類()的方式進行創建,當調用內部類的構造器的時候,會把當前創建的內部類對象實例中持有的外部對象引用賦值爲當前創建內部類的外部類實例。內部成員類可以是使用訪問控制符,可以定義爲final,也可以是抽象類。

 

  

public class MemberInnerClass {
 
    // 私有局部
    public int i = 0;
 
    // 靜態
    private static int j = 0;
 
    // 不變值
    private final int k = 0;
 
    // static final
    private static final int m = 0;
 
    public class PublicMemberInnerClass {
        // enclosing Class的屬性都可以訪問
        public void test() {
            System.out.println(i);
            System.out.println(j);
            System.out.println(m);
            System.out.println(k);
        }
 
        public MemberInnerClass getOutterClass() {
            return MemberInnerClass.this;
        }
        // 這裏會報錯,不允許定義static方法
        // private static final void test();
    }
 
    // 私有的innerclass 外部不能訪問
    private class PrivateMemberInnerClass {
    }
 
    // 公開局部類,外部可以訪問和創建,但是隻能通過OutterClass實例創建
 
    class DefaultMemberInnerClass {
        public MemberInnerClass getOutterClass() {
            return MemberInnerClass.this;
        }
    }
 
}


  

下面例子演示了內部成員類的創建

public class TestClass {
 
    public static void main(String[] args) {
 
        // 任何地方都可以創建
        MemberInnerClass t = new MemberInnerClass();
 
        // 可以創建,pmic裏面保存對t的引用
        MemberInnerClass.PublicMemberInnerClass pmic = t.new PublicMemberInnerClass();
 
        // 可以在同一package下創建,dmic保存對t的引用
        MemberInnerClass.DefaultMemberInnerClass dmic = t.new DefaultMemberInnerClass();
 
        // 編譯錯誤,無法訪問內部內
        // MemberInnerClass.PrivateMemberInnerClass pmic = t.new
        // PrivateMemberInnerClass();
 
        // 下面驗證一下outterClass是同一個對象
        System.out.println(pmic.getOutterClass() == t);
        System.out.println(dmic.getOutterClass() == t);
 
    }
}


 運行程序,打印結果:

true
true

  

2 local inner classes(局部類)

局部類 定義在類方法裏面。這個方法既可以是靜態方法,也可以是實例方法,也可以是構造器方法或者靜態初始化語句塊。

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

定義在static上下文(static 字段初始化,static初始化塊,static方法)裏面的local inner classes 可以訪問類的靜態屬性,如果定義在靜態方法裏面的局部類,還可以方法裏面定義的final變量。在static上下文定義的局部類,沒有指向父類實例變量的引用,因爲static方法不屬於類的實例,屬於類本身。而且局部類不能在外部進行創建,只能在方法調用的時候進行創建

 

public class LocalInnerClass {
 
    // 私有局部
    private int i = 0;
 
    // 靜態
    public static int j = 0;
 
    // 不變值
    private final int k = 0;
 
    // static final
    private static final int m = 0;
 
    public static void test() {
        final int a = 0;
        int b = 0;
        // local inner class不能夠有訪問控制符 比如public private
        abstract class LocalStaticInnerClass {
            // local inner class不能定義靜態屬性
            // private static int c;
            private int d = 0;
            public LocalStaticInnerClass() {
                // 可以訪問方法裏面定義的final 變量
                System.out.println(a);
                // 不能訪問b 因爲b不是final
                // System.out.println(b);      
                // 定義在static上下文裏面的local inner class 不能訪問外部類的非static字段
                // System.out.println(i);
                // System.out.println(k);
                System.out.println(j);
                System.out.println(m);
            }
            // local inner class不能定義靜態方法
            // public static void test(){}
        }
    }
 
    public void test2() {
        final int a = 0;
        int b = 0;
        final class LocalNonStaticInnerClass{  
            public LocalNonStaticInnerClass() {
                //定義在非static上下文的local inner class 可以訪問外部類的所有屬性
                System.out.println(i);
                System.out.println(k);
                System.out.println(j);
                System.out.println(m);
            }
        }
    }
 
}


 

 3 anonymous inner classes (匿名類)也是定義在方法裏面,匿名類和局部類訪問規則一樣,只不過內部類顯式的定義了一個類,然後通過new的方式創建這個局部類實例,而匿名類直接new一個類實例,沒有定義這個類。匿名類最常見的方式就是回調模式的使用,通過默認實現一個接口創建一個匿名類然後,然後new這個匿名類的實例。

public class AnonymousInnerClass {
    //訪問規則和局部類一樣
    public void test() {
         
        //匿名類實現
        new Thread(new Runnable() {
 
            @Override
            public void run() {
 
            }
        }).start();
         
        //非匿名類實現
        class NoneAnonymousClass implements Runnable{
            public void run() {
 
            }
        }  
        NoneAnonymousClass t = new NoneAnonymousClass();
        new Thread(t).start();
    }
}


嵌套類的層次

嵌套類是可以有層次的,也就是說嵌套類裏面還是定義類,成爲嵌套類中的嵌套類。虛擬機如何保證嵌套類正確的嵌套層層次?

對於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爲自然數).

看看下面的例子

public class NestedClassLevel {
 
    class A {
        // 編譯器會報錯,A裏面不能在定義名爲A的nested classes
        // class A{}
        public void test() {
            class B {
            }
        }
    }
 
    //可以在繼續定義B
    class B {
        public void test(){
            //可以無限定義匿名類
            new Runnable() {
                public void run() {
                    //可以無限定義匿名類
                    new Runnable() {           
                        public void run() {        
                        }
                    };
                }
            };
        }
    }
 
    // 只能定義一個B
    // class B{}
 
    public void test() {
        // 可以定義A
        class A {
            public void test() {
                //可以有同名的局部類B和成員類B
                class B {
                    public void test() {
                         
                    }
                }
                //局部類A裏面不能在定義A
                //class A{}
            }
        }
        //可以有同名的局部類B和成員類B
        class B {
 
        }
    }
 
}


 

對於定義在非static上下文裏面的nested類層次,比如A$B$1C ,則最內層的嵌套類C有一個指向B實例的引用,B有一個指向A實例的引用,最終最內層的嵌套類可以訪問A中的屬性可以方法,一般把B成爲A的直接嵌套類。但是A不可以訪問B或者C中屬性或者方法。

nested interface

由於interface默認是定義爲一個 public static的特殊類,所以interface可以直接作爲 static member class。可以通過A.B的方式進行訪問。

 

nested class的應用

在java提供的基本類庫裏面,大量使用nested classes。比如我們知道的map類。其中 Map類裏面有一個定義了Entry類abstract inner class。所以我們在遍歷map的時候,一般使用

for (Map.Entry entry:map.entrySet()){

}

 

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

 

 

 

 

 

 

 -----以下爲原文blog信息--------

GodIsCoder
博客園blog地址:http://www.cnblogs.com/aigongsi/
獨立Blog: God Is Coder
個人網站: iphone發碼網
本人版權歸作者和博客園所有,歡迎轉載,轉載請註明出處

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章