java學習筆記9--內部類總結


java學習筆記系列:

java學習筆記8--接口總結

java學習筆記7--抽象類與抽象方法

java學習筆記6--類的繼承、Object類

java學習筆記5--類的方法 

java學習筆記4--對象的初始化與回收

java學習筆記3--類與對象的基礎 

java學習筆記2--數據類型、數組

java學習筆記1--開發環境平台總結

本文地址:http://www.cnblogs.com/archimedes/p/java-study-note9.html,轉載請注明源地址。

java內部類分為: 非靜態內部類、靜態內部類、局部內部類、匿名內部類

內部類的共性:

(1)內部類仍然是一個獨立的類,在編譯之后內部類會被編譯成獨立的.class文件,但是前面冠以外部類的類名和$符號 。

(2)內部類不能用普通的方式訪問。內部類是外部類的一個成員,因此內部類可以自由地訪問外部類的成員變量,無論是否是private的 。

(3)內部類聲明成靜態的,就不能隨便的訪問外部類的成員變量了,此時內部類只能訪問外部類的靜態成員變量 。

java 中的內部類和接口加在一起,可以的解決常被 C++ 程序員抱怨 java 中存在的一個問題:沒有多繼承。實際上,C++ 的多繼承設計起來很復雜,而 java 通過內部類加上接口,可以很好的實現多繼承的效果

非靜態內部類

當一個類作為另一個類的非靜態成員,則這個類就是一個非靜態內部類。

創建非靜態內部類是很容易的,只需要定義一個類讓該類作為其他類的非靜態成員。該非靜態內部類和成員變量或者成員方法沒有區別,同樣可以在非靜態內部類前面加可以修飾成員的修飾符。創建非靜態內部類的基本語法如下所示:

class OutClass {
    class InClass {
        //內部類成員
    }
    //外部類成員
}

在內部類的程序中,是經常會進行外部類和內部類之間訪問的。在外部類中訪問內部類是很容易的,只要把內部類看成一個類,然后創建該類的對象,使用對象來調用內部類中的成員就可以了。

在外部類中訪問內部類的程序--舉個例子:

class OutClass {
    class InClass {    //創建非靜態內部類
        int i = 5;    //內部類成員
    }
    public void fun() {    //外部類成員
        InClass in = new InClass();    //創建一個內部類對象
        int i = in.i;        //訪問內部類成員
        System.out.println("InClass's var is: " + i);
    }
}
public class javatest {  
    public static void main(String args[ ]) { 
         OutClass out = new OutClass();
         out.fun();
   }
}

運行結果:

InClass's var is: 5

分析:在main方法中,首先創建一個外部類對象,然后訪問外部類的成員方法。在外部類的成員方法中,創建了一個內部類對象,然后使用內部類對象調用內部類的成員變量,從而得到結果。編譯該程序將產生三個class文件,分別是主類、外部類和內部類。內部類產生的class文件的名稱為OutClass$InClass.class,在該名稱中可以區分該內部類到底是哪一個類的內部類。

不但可以在外部類中訪問內部類,還可以在外部類外訪問內部類。在外部類外訪問內部類的基本語法如下所示。

OutClass.InClass oi=new OutClass().new InClass();

使用該方法就能夠創建一個內部類對象,使用該內部類對象就可以訪問內部類的成員。該方法是不容易理解的,可以分為下面的兩條語句:

Wai w=new Wai();

Wai.Nei wn=w.new Nei();

這樣就很容易理解了。首先是創建一個外部類的對象,然后讓該外部類對象調用創建一個內部類對象。 

在外部類外訪問內部類的程序--舉個例子:

class OutClass {
    class InClass {    //創建非靜態內部類
        int i = 5;    //內部類成員
        int j = 6;
    }
}
public class javatest {  
    public static void main(String args[ ]) { 
        OutClass.InClass oi1 = new OutClass().new InClass();
        OutClass ocClass = new OutClass();
        OutClass.InClass oi2 = ocClass.new InClass();
        System.out.println("InClass's var i is: " + oi1.i);
        System.out.println("InClass's var j is: " + oi1.j);  
   }
}

在示例代碼中使用了兩種方法來從外部類外訪問內部類。在外部類外訪問內部類時,是不能夠直接創建內部類對象的,因為內部類只是外部類的一個成員。所以要想創建內部類對象,首先要創建外部類對象,然后以外部類對象為標識來創建內部類對象。 

在內部類中訪問外部類

在內部類中訪問外部類,就像所有的同一個類中成員互相訪問一樣,這樣是沒有限制的,包括將成員聲明為private私有的。

舉個例子:

class OutClass {
    int i = 8;    //外部類成員變量
    class InClass {    //創建非靜態內部類
        public void fun() {
            System.out.println("OutClass's var is: " + i);
        }
    }
}
public class javatest {  
    public static void main(String args[ ]) { 
        OutClass oc = new OutClass();    //創建外部類對象
        OutClass.InClass oi = oc.new InClass();    //創建內部類對象
        oi.fun();    //調用內部類中的成員
   }
}

在示例代碼中,在內部類中定義了一個fun來訪問外部類中的成員變量i。可以看到從內部類中訪問外部類是非常容易的,不需要添加任何內容,就像成員方法間調用一樣。如果外部類中也有一個成員變量i,得到的是內部類成員變量的值。下面通過示例代碼解決這個問題:

class OutClass {
    int i = 8;    //外部類成員變量
    class InClass {    //創建非靜態內部類
        int i = 9;
        OutClass oc = new OutClass();
        public void fun() {    //內部類成員
            System.out.println("InClass's var is: " + i);
            System.out.println("OutClass's var is: " + oc.i);
        }
    }
}
public class javatest {  
    public static void main(String args[ ]) { 
        OutClass oc = new OutClass();    //創建外部類對象
        OutClass.InClass ic = oc.new InClass();    //創建內部類對象
        ic.fun();    //調用內部類中的成員
   }
}

在本程序中先定義了一個外部類的成員變量,接着定義了一個內部類的成員變量,這兩個成員變量的名稱是相同的。而在內部直接訪問時,將訪問的是內部類的成員變量。要想訪問外部類成員變量,就需要首先創建一個外部類對象,然后使用該對象調用外部類成員變量。 

局部內部類

局部內部類的作用范圍是和局部變量的作用范圍相同的,只在局部中起作用,所以對局部內部類進行訪問時,只能在該局部內部類的作用范圍內。

舉個例子:

class OutClass {
    public void fun() {    
        class InClass {    //定義一個局部內部類
            int i = 5;    //局部內部類的成員變量
        }
        InClass ic = new InClass();
        System.out.println("InClass's var is: " + ic.i);
    }
}
public class javatest {  
    public static void main(String args[ ]) { 
        OutClass oc = new OutClass();
        oc.fun();
   }
}

在本程序中定義了一個局部內部類,並進行了對該局部內部類的訪問。對該內部類進行訪問必須在該內部類所在的方法中通過創建內部類對象來進行訪問。這是因為這里的內部類是作為局部成員的形式出現的,只能在它所在的方法中進行調用。 

局部內部類中訪問外部類成員變量

在局部內部類中訪問外部類成員變量是很容易實現的,並不需要進行過多操作。在局部內部類中可以直接調用外部類的成員變量。

舉個例子:

class OutClass {
    int i = 9;    //定義一個外部類的成員變量
    public void fun() {    
        class InClass {    //定義一個局部內部類
            public void Infun() {
                System.out.println("OutClass's var is: " + i);    //訪問外部類中的成員變量
            }
        }
        InClass ic = new InClass();    //創建內部類對象
        ic.Infun();    //調用內部類中的成員方法
    }
}
public class javatest {  
    public static void main(String args[ ]) { 
        OutClass oc = new OutClass();    //創建外部類對象
        oc.fun();    //調用內部類中的成員
   }
}

在示例代碼中定義了一個局部內部類,在該局部內部類中定義了一個方法來訪問外部類的成員變量。

在局部內部類中訪問外部類的局部變量

和訪問外部類的成員變量不同,在局部內部類中訪問外部類中和局部內部類在同一局部的局部變量是不能夠直接訪問的。

舉個例子(下面是一段錯誤的代碼):

class OutClass {
    public void OutFun() {
        int i = 9;
        class InClass {
            public void InFun() {
                System.out.println("OutClass's var is: " + i);//訪問外部類的成員變量
            }
        }
        InClass ic = new InClass();    //創建內部類對象
        ic.InFun();    //調用內部類中的成員方法
    }
}
public class javatest {  
    public static void main(String args[ ]) { 
        OutClass oc = new OutClass();    //創建外部類對象
        oc.OutFun();    //調用內部類中的成員
   }
}

運行產生異常:

Exception in thread "main" java.lang.Error: Unresolved compilation problem:
Cannot refer to a non-final variable i inside an inner class defined in a different method

運行該程序是會發生錯誤的,錯誤信息為“從內部類中訪問局部變量i;需要被聲明為最終類型”。在局部內部類中訪問外部類的局部變量是不能夠訪問普通的局部變量的,必須將該局部變量聲明為final。

靜態方法中的局部內部類

局部內部類定義在非靜態方法和靜態方法中是不同的,在前面例子都是將局部內部類定義在非靜態方法中,下面就來學習靜態方法中定義局部內部類的情況。在靜態方法中定義的局部內部類要想訪問外部類中的成員,該成員必須是靜態成員。

class OutClass {
    static int i = 4;
    public static void OutFun() {    //外部類成員
        class InClass {
            public void InFun() {
                System.out.println("OutClass's local var is: " + i);
            }
        }
        InClass ic = new InClass();
        ic.InFun();
    }
}
public class javatest {  
    public static void main(String args[ ]) { 
        OutClass.OutFun();
   }
}

靜態內部類

前面已經學習了非靜態內部類,接下來就來學習什么是靜態內部類。靜態內部類就是在外部類中扮演一個靜態成員的角色。創建靜態內部類的形式和創建非靜態內部類的形式很相似的,只是需要將該內部類使用static修飾成靜態的形式。使用static修飾類,這在正常類中是不可能的。定義靜態內部類的語法如下所示:
class OutClass {
    static class InClass {
        //內部類成員
    }
    //外部類成員
}

在外部類中訪問靜態內部類

在外部類中訪問靜態內部類和在外部類中訪問非靜態內部類一樣的,只需要從成員間訪問的角度就可以考慮到這一點。舉個例子:

class OutClass {
    static class InClass {    //創建靜態內部類
        int i = 5;    //內部類成員
    }
    public void OutFun() {    //外部類成員
        InClass ic = new InClass();    //創建一個內部類對象
        int ii = ic.i;    //訪問內部類成員
        System.out.println("static InClass's var is: " + ii);
    }
}
public class javatest {  
    public static void main(String args[ ]) { 
        OutClass oc = new OutClass();    //創建外部類對象
        oc.OutFun();    //調用內部類中的成員
   }
}

在外部類中訪問靜態內部類和訪問非靜態內部類是相同的,但是在外部類中訪問靜態內部類和非靜態內部類就不再相同。因為靜態內部類是外部類的靜態成員,靜態成員是不需要外部類對象而存在的,所以在外部類外,對靜態內部類進行訪問時是不需要創建外部類對象的。

注意:因為靜態內部類是外部類的靜態成員,靜態成員是不需要外部類對象而存在的,所以在外部類外,對靜態內部類進行訪問時是不需要創建外部類對象的。

匿名內部類

在所有的內部類中最難的就應該是匿名內部類。匿名內部類從名字上看就知道是沒有類名的內部類。正因為沒有名字,所以匿名內部類只能使用一次,它通常用來簡化代碼編寫,

使用匿名內部類還有個前提條件:必須繼承一個父類或實現一個接口

創建匿名內部類

在創建匿名內部類中將使用到繼承父類或者實現接口的知識,匿名內部類是沒有名字的,所以在創建匿名內部類時同時創建匿名內部類的對象。創建匿名內部類的語法格式如下:

new InFather() {
    //匿名內部類
};

在創建匿名內部類的語法中,InFather是匿名內部類繼承的父類的類名,使用new同時創建了匿名內部類的對象。在匿名內部類中可以重寫父類中的方法,也可以定義自己的方法。

實例1:不使用匿名內部類來實現抽象方法

abstract class Person {
    public abstract void eat();
}
 
class Child extends Person {
    public void eat() {
        System.out.println("eat something");
    }
}
public class test {
    public static void main(String[] args) {
        Person p = new Child();
        p.eat();
    }
}

運行結果:

eat something

可以看到,我們用Child繼承了Person類,然后實現了Child的一個實例,將其向上轉型為Person類的引用。但是,如果此處的Child類只使用一次,那么將其編寫為獨立的一個類會很麻煩。這個時候就引入了匿名內部類

實例2:匿名內部類的基本實現

abstract class Person {
    public abstract void eat();
}
public class test {
    public static void main(String[] args) {
        Person p = new Person() {
            public void eat() {
                System.out.println("eat something");
            }
        };
        p.eat();
    }
}

運行結果:

eat something

可以看到,我們直接將抽象類Person中的方法在大括號中實現了,這樣便可以省略一個類的書寫,並且匿名內部類還能用於接口上

實例3:在接口上使用匿名內部類

interface Person {
    public void eat();
}
public class test {
    public static void main(String[] args) {
        Person p = new Person() {
            public void eat() {
                System.out.println("eat something");
            }
        };
        p.eat();
    }
}

運行結果:

eat something

由上面的例子可以看出,只要一個類是抽象的或是一個接口,那么其子類中的方法都可以使用匿名內部類來實現。最常用的情況就是在多線程的實現上,因為要實現多線程必須繼承Thread類或是繼承Runnable接口

實例4:Thread類的匿名內部類實現

public class test {
    public static void main(String[] args) {
        Thread t = new Thread() {
            public void run() {
                for (int i = 1; i <= 5; i++) {
                    System.out.print(i + " ");
                }
            }
        };
        t.start();
    }
}

運行結果:

1 2 3 4 5

實例5:Runnable接口的匿名內部類實現

public class test {
    public static void main(String[] args) {
        Runnable r = new Runnable() {
            public void run() {
                for (int i = 1; i <= 5; i++) {
                    System.out.print(i + " ");
                }
            }
        };
        Thread t = new Thread(r);
        t.start();
    }
}

運行結果:

1 2 3 4 5

參考資料:

1、http://www.cnblogs.com/nerxious/archive/2013/01/25/2876489.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM