1. 程式人生 > >Java內部類(inner Class)和巢狀類(static inner Class)也就是靜態內部類的區別

Java內部類(inner Class)和巢狀類(static inner Class)也就是靜態內部類的區別

內部類和靜態類有著本質的區別,有點類似普通成員變數和靜態成員變數的區別
.
內部類可以看成是外部類的普通成員變數,這個成員變數可以使用外部類的屬性(靜態和非靜態),可以呼叫外部類的方法(靜態和非靜態),而且內部類還持有外部類物件作為其自身的一個屬性,這個屬性的名稱叫 this$0,可以使用反射獲取外部類物件。內部類物件在其他類中不能使用建構函式直接new得到,因為內部類物件類似外部類的成員變數,外部類不存在時,內部屬性自然不能生成。內部類持有外部類物件的最好例項就是容器類的Iterator物件,通過容器類的iterator()方法得到Iterator物件,然後通過Iterator物件就能遍歷容器,就是因為Iterator物件持有外部物件也就是容器物件的例項,大部分容器均有一個內部類實現了Iterator介面,實現自己的遍歷邏輯。
.
巢狀類可以看成是外部類的靜態成員,只能使用外部類的靜態屬性和靜態方法。巢狀類是獨立於外部類存在的,也就是其他類可以通過呼叫巢狀類的建構函式來獲取巢狀類例項。巢狀類不持有外部類物件例項,巢狀類可以看成是另外一個獨立的類。很多情況是巢狀類僅僅在外部類裡使用,使用巢狀類對外部類的幾個屬性或者一些函式做一個封裝,便於外部類的邏輯實現 , 所以其修飾符很多時候定義為private static class。
.
內部類和巢狀類的類名均是:外部類名稱+$

+自身類名稱,比如com.bob.test.concrete.clazz.TopLevelClass$NestedClass,com.bob.test.concrete.clazz.TopLevelClass$InnerClass,包名和外部類一致。

可以通過外部類的Class.getDeclaredClasses()方法獲取所有定義的內部類和巢狀類。

程式碼示例:

public class TopLevelClass {

    private int id;

    public int getId() {
        return id;
    }

    public
void setId(int id) { this.id = id; } public InnerClass getInnerClass(){ return new InnerClass(); } public NestedClass getNestedClass(){ return new NestedClass(); } public static void print(){ System.out.println("呼叫靜態方法"); } /** * 內部類 */
public class InnerClass { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } public String toString(){ //內部類可以使用外部類的屬性和方法 return id + name; } } /** * 巢狀類,靜態內部類 */ public static class NestedClass { private int age; public int getAge() { return age; } public void setAge(int age) { this.age = age; } public void print(){ //巢狀類智慧使用外部類的靜態成員及方法 TopLevelClass.print(); } } }

程式碼測試:

public class InnerClassTest {

    @Test
    public void getInnerClass(){
        //InnerClass is = new InnerClass(); 會報錯
        InnerClass is = new TopLevelClass().getInnerClass();
    }

    @Test
    public void getNestedClass(){
        NestedClass ns = new NestedClass();
        ns = new TopLevelClass().getNestedClass();
    }

    @Test
    public void testInnerClassName() {
        //獲取所有的內部類及巢狀類
        Class<?>[] classes = TopLevelClass.class.getDeclaredClasses();
        for (Class<?> clazz : classes) {
            //內部類和巢狀類都屬於成員類
            System.out.println(clazz.isMemberClass());
            System.out.println(
                "Class.Name = " + clazz.getName() + ", Class.SimpleName = " + clazz.getSimpleName() + ", Class.Package = " + clazz.getPackage().getName());
        }
        System.out.println(TopLevelClass.class.isMemberClass());
    }

    @Test
    public void getOutterClassInstance() throws NoSuchFieldException, IllegalAccessException {
        TopLevelClass tps = new TopLevelClass();
        InnerClass is = tps.getInnerClass();
        Field filed = is.getClass().getDeclaredField("this$0");
        //獲取內部類物件持有的外部類例項
        TopLevelClass innerTps = (TopLevelClass)filed.get(is);
        //返回true,他們是同一個物件
        System.out.println(tps == innerTps);
    }

}