靜態內部類的使用

本講內容:內部類

Java語言允許在類中再定義類,這種在其它類內部定義的類就叫內部類。內部類又分爲:常規內部類、局部內部類、匿名內部類和靜態嵌套類四種。我們內部類的知識在Android手機開發中經常用到。

一、常規內部類

所謂常規內部類,或者說內部類,指的就是除去後面三種之外的內部類(這算什麼解釋。。。)

先寫一個最簡單的內部類的例子,大家感覺一下:

1 public classOuter {
2     publicclass Inner{
3     }
4 }

編譯一下,我們看到目錄中出現了兩個class文件,其中有一個文件名叫做Outer$Inner.class,帶了一個$符號,這個特點讓我們很容易的認出來這是內部類編譯後的class文件。

K6DP_~XUH}@$_Y$ZEYMFE@T

再寫一個稍微複雜一點的內部類:

01 public classOuter {   
02  
03     privateint x=1;
04  
05     publicOuter(){
06         System.out.println("Outer initial");
07     }
08  
09     publicclass Inner{
10  
11         publicInner(){
12             System.out.println("Inner initial");
13         }
14  
15         privateint x=2;
16  
17         public void add(){
18             intx=3;
19             System.out.println(x);
20             System.out.println(this.x);
21             System.out.println(Outer.this.x);
22         }
23  
24     }
25  
26     publicstatic void main(String[] args){
27         Inner inner =new Outer().newInner();
28         inner.add();
29     }
30 }

我們編譯以後,運行一下看看:

 image

在上面的例子裏我們可以清晰的看到:

  1. 內部類就像一個實例成員一樣存在於外部類中。
  2. 內部類可以訪問外部類的所有成員就想訪問自己的成員一樣沒有限制。
  3. 內部類中的this指的是內部類的實例對象本身,如果要用外部類的實例對象就可以用類名.this的方式獲得。
  4. 內部類對象中不能有靜態成員,原因很簡單,內部類的實例對象是外部類實例對象的一個成員。

下面我們再小結一下內部類的創建方法:

  1. 在外部類的內部,可以用 Inner inner = new Inner(); 方法直接創建
  2. 在外部類外部,必須先創建外部類實例,然後再創建內部類實例,除了上面 Inner inner = new Outer().new Inner()的寫法以外,還有 Outer outer = new Outer(); Inner inner = outer.new Inner();的寫法

 

二、局部內部類

我們也可以把類定義在方法內部,這時候我們稱這個類叫局部內部類。

我們再看一個例子:

01 public classOuter {
02  
03     intx =1;
04     publicvoid doSomething(){
05         finalint y=2;
06         classInner{
07             intx =3;
08             voidprint(){
09                 intx=4;
10                 System.out.println(x);
11                 System.out.println(this.x);
12                 System.out.println(Outer.this.x);
13                 System.out.println(y);
14             }
15         }
16         Inner inner =new Inner();
17         inner.print();
18     }
19  
20     publicstatic void main(String[] args){
21         Outer outer =new Outer();
22         outer.doSomething();
23     }
24 }

運行程序,查看結果:

image

我們通過上面這裏例子也可以看到下面幾點:

  1. 局部內部類的地位和方法內的局部變量的位置類似,因此不能修飾局部變量的修飾符也不能修飾局部內部類,譬如public、private、protected、static、transient等
  2. 局部內部類只能在聲明的方法內是可見的,因此定義局部內部類之後,想用的話就要在方法內直接實例化,記住這裏順序不能反了,一定是要先聲明後使用,否則編譯器會說找不到。
  3. 局部內部類不能訪問定義它的方法內的局部變量,除非這個變量被定義爲final 。

是不是有點不好理解?關於爲什麼用final修飾以後就可以用了,我打算專門在番外篇裏專門寫一篇博客給你講清楚,先記住吧。

三、匿名內部類

當我們把內部類的定義和聲明寫到一起時,就不用給這個類起個類名而是直接使用了,這種形式的內部類根本就沒有類名,因此我們叫它匿名內部類。

我們再看一個有趣的例子:

01 public classDog {
02  
03     publicinterface Pet {
04  
05         publicvoid beFriendly();
06         publicvoid play();
07  
08     }
09  
10     publicstatic void main(String[] args){
11  
12         Pet dog =new Pet(){
13             @Override
14             publicvoid beFriendly() {
15                 System.out.println("蹭蹭你^_^");
16             }
17             @Override
18             publicvoid play() {
19                 System.out.println("把飛盤叼給你,逼你把飛盤丟出去,然後它再撿回來讓你繼續扔,連續500次^_^");
20             }
21         };
22  
23         dog.beFriendly();
24         dog.play();
25  
26     }
27 }

編譯和運行程序,查看結果:

image

竟然編譯和運行都很正常,我們知道抽象類和接口肯定無法實例化的,因此剛纔的例子肯定有點意思:

  1. 第一匿名內部類可以是個接口,這個沒什麼好奇怪的哈。
  2. 第12行到第21行是一個語句,就是定義了一個對象,因此21行大括號後面有個分號。
  3. 匿名內部類用 new Pet(){ … } 的方式把聲明類的過程和創建類的實例的過程合二爲一。
  4. 匿名內部類可以是某個類的繼承子類也可以是某個接口的實現類。

好吧我們再看一個例子,方法參數內的匿名內部類

01 public classDog {
02  
03     staticabstract class Ball {
04         abstractString getName();
05     }
06  
07     voidplay(Ball b){
08         System.out.println(b.getName());
09     }
10  
11     publicstatic void main(String[] args){
12         Dog dog =new Dog();
13  
14         dog.play(newBall(){
15             @Override
16             String getName() {
17                 return"qiu qiu";
18             }});
19     }
20 }

編譯和運行以後的截圖我就不給你了,返回值就是“qiu qiu”。

從第14行到第18行是一句話,就是執行一個play方法,而這個方法的參數就由一個匿名內部類的實例來提供。

四、靜態嵌套類

爲了讓你感覺舒服一些,我們也把最簡單的內部類放在最後講。

當一個內部類前面用static修飾時,我們稱之爲靜態嵌套類或者說靜態內部類。

上面的例子裏其實我們已經看到過靜態嵌套類了,下面我們再舉一個例子:

01 public classOuter {
02  
03     staticint x =1;
04  
05     staticclass Nest {
06  
07         voidprint(){
08             System.out.println("Nest "+x);
09         }
10     }
11  
12     publicstatic void main(String[] args){
13         Outer.Nest nest =new Outer.Nest();
14         nest.print();
15     }
16 }

因爲靜態嵌套類和其他靜態方法一樣只能訪問其它靜態的成員,而不能訪問實例成員。因此靜態嵌套類和外部類(封裝類)之間的聯繫就很少了,他們之間可能也就是命名空間上的一些關聯。上面例子中你需要注意的就是靜態嵌套類的聲明方法 new Outer.Nest() 連續寫了兩個類名,以至於我們都懷疑前面的Outer是個包名了,好在包名一般都小寫的,要不還真分不清……

再強調一遍,內部類在Android中應用的非常多,理解和使用好顯得蠻重要。好了,本講就到這裏。


如何應用Java的靜態內部類

http://java.chinaitlab.com/oop/787330.html

在上一小節我們討論了內部類,即在一個類中包含有另外一個或者多個類(見本書12.3.3小節)。與內部類相似,靜態內部類指在一個類的內部包含有另外一個或者多個靜態類。例如:
 
public class OuterClass {
    ...
    static class StaticInnerClass1 {            //內部靜態類
        //只可以訪問OuterClass的靜態成員
        ...
    }                                           //StaticInnerClass結束
    ...                            
    static class StaticInnerClassN {            //更多靜態內部類
       //只可以訪問OuterClass的靜態成員
       ...
    }                                           //StaticInnerClassN結束
}  //OuterClass結束
 
       與一般內部類不同,在靜態代碼中不能夠使用this操作,所以在靜態內部類中只可以訪問外部類的靜態變量和靜態方法。使用靜態內部類的目的和使用內部類相同。如果一個內部類不依賴於其外部類的實例變量,或與實例變量無關,則選擇應用靜態內部類。
如下例子演示怎樣使用靜態內部類:
 
///完整程序存在本書配套資源目錄Ch12名爲StaticInnerClassTest.java
public class StaticInnerClassTest {
    public static void main( String args[] ) {
        OuterClass2 outer = new OuterClass2();
        OuterClass2.StaticInnerClass.innerMethod();   
                                                //調用靜態內部類的靜態方法
        OuterClass2.outerMethod();
        //創建靜態內部類對象
        OuterClass2.StaticInnerClass staticInner = new OuterClass2.StaticInnerClass();
        int num = staticInner.innerMethod2();   //調用靜態內部類實例方法
    }
}
class OuterClass2 {                             //外部類
    private double x = 0.0;                     //內部靜態類不可以訪問外部類實                                              例變量
    static private int n = 10;                  //外部類靜態變量
    static void outerMethod() {                 //外部類靜態方法
        System.out.println("from OuterClass...");
    }
    void outerMethod2() {
        System.out.println("from OuterClass’ instance method2()...");
    }
    static class StaticInnerClass {             //靜態內部類
        static private int m = 5;               //靜態內部類靜態變量
        static void innerMethod() {             //靜態內部類靜態方法
            int sum;
            n = 20;                             //只可以訪問外部類靜態變量
            sum = n + m;
            System.out.println("from InnerClass sum = " + sum);
            outerMethod();                      //只可以調用外部類靜態方法
       }
        int innerMethod2() {
            n = 100;
            outerMethod();
            System.out.println("from InnerMethod2() n = " + n);
            return n;
        }
   }       //靜態內部類結束
}           //外部類結束
 
如同不用創建對象就可調用靜態方法一樣,上例靜態內部類中的靜態方法利用:
 
OuterClass2.StaticInnerClass.innerMethod(); //靜態內部類調用其靜態方法
 
來調用。注意,可以在靜態內部類的方法中,直接訪問外部類的靜態變量n和調用靜態方法outerMethod()。但不允許訪問外部類的實例變量x以及實例方法outerMethod2()。
       靜態內部類中也可以提供實例方法,如:
 
    static class StaticInnerClass {
        int innerMethod2() {
            n = 100;                        //只可訪問外部類靜態變量
            outerMethod();                  //只可調用外部類靜態方法
            System.out.println("from InnerMethod2() n = " + n);
            return n;
        }
    }       //靜態內部類結束
 
       靜態內部類的實例方法中亦只允許訪問外部類的靜態成員。
可以使用下列語法格式創建一個靜態內部類對象並且調用其實例方法,以及靜態方法:
 
OuterClass2.StaticInnerClass staticInner = new OuterClass2.StaticInner Class();                                 //創建靜態內部類對象
int num = staticInner.innerMethod2();       //調用實例方法
staticInner.innerMethod();                  //調用其靜態方法
 

java 靜態內部類的使用

http://blog.csdn.net/xys_777/article/details/6755836

  1. package Chapter10;  
  2. public class StaticInternal {  
  3.     private static String name = "\"聶慶亮\"";  
  4.     public static void setStatic(String n) {        // 外部類的非靜態方法  
  5.         System.out.println("[現在訪問的是外部類的靜態方法!]");  
  6.         name = n;  
  7.     }  
  8.     static class InnerClass_2 {            // 靜態內部類開始  
  9.         String address, mail;        // 聲明String類型變量  
  10.         long phoneNum;        // 聲明long類型變量  
  11.         int qq;                // 聲明int類型變量  
  12.         static void getStatic() {    // 靜態內部類的靜態方法  
  13.             System.out.println("[訪問外部類的靜態變量] name = " + name);  
  14.             setStatic("尹繼平");     // 訪問外部類的靜態方法  
  15.         }  
  16.         // 靜態內部類的非靜態方法  
  17.         public void setString(String address, String mail) {  
  18.             System.out.println("1.靜態內部類的帶String型參數的非靜態主法");  
  19.             this.address = address;  
  20.             this.mail = mail;  
  21.         }  
  22.         public void setInt(long phoneNum, int qq) {  
  23.             System.out.println("2.靜態內部類的帶int型參數的非靜態主法!");  
  24.             this.phoneNum = phoneNum;  
  25.             this.qq = qq;  
  26.         }  
  27.     }                            // 靜態內部類結束  
  28.     public void setValue() {             // 外部類訪問靜態內部類的靜態成員:內部類.靜態成員  
  29.         InnerClass_2.getStatic();         // 訪問靜態內部類的靜態方法  
  30.         InnerClass_2 inner = new InnerClass_2();                 // 實例化對象  
  31.         inner.setString("北京昌平區沙河鎮""[email protected]");     // 訪問靜態內部類的非靜態方法  
  32.         inner.setInt(89653310313557706);  
  33.         System.out.println("\n外部類訪問靜態內部類的結果如下:");  
  34.         System.out.println("姓名:" + this.name);  
  35.         System.out.println("住址:" + inner.address);  
  36.         System.out.println("聯繫電話" + inner.phoneNum);  
  37.         System.out.println("E-mail:" + inner.mail);  
  38.         System.out.println("QQ號碼:" + inner.qq);  
  39.     }  
  40.     public static void main(String[] args) {                        // java程序主入口處  
  41.         StaticInternal sin = new StaticInternal();  
  42.         sin.setValue();                                         // 調用方法  
  43.     }  
  44. }  


Java內部類與靜態內部類

http://hi.baidu.com/zhumulangma/item/bcd478c140427b2cef466532

定義在一個類內部的類叫內部類,包含內部類的類稱爲外部類。內部類可以聲明public、protected、private等訪問限制,可以聲明爲abstract的供其他內部類或外部類繼承與擴展,或者聲明爲static、final的,也可以實現特定的接口。外部類按常規的類訪問方式使用內部類,唯一的差別是外部類可以訪問內部類的所有方法與屬性,包括私有方法與屬性

(1)創建實例

OutClass.InnerClass obj = outClassInstance.new InnerClass(); //注意是外部類實例.new,內部類

AAA.StaticInner in = new AAA.StaticInner();//注意是外部類本身,靜態內部類

(2)內部類中的this

內部類中的this與其他類一樣是指的本身。創建內部類對象時,它會與創造它的外圍對象有了某種聯繫,於是能訪問外圍類的所有成員,不需任何特殊條件,可理解爲內部類鏈接到外部類。 用外部類創建內部類對象時,此內部類對象會祕密的捕獲一個指向外部類的引用,於是,可以通過這個引用來訪問外圍類的成員。

(3)外部類訪問內部類

內部類類似外部類的屬性,因此訪問內部類對象時總是需要一個創建好的外部類對象。內部類對象通過‘外部類名.this.xxx’的形式訪問外部類的屬性與方法。如:
System.out.println("Print in inner Outer.index=" + pouter.this.index);
System.out.println("Print in inner Inner.index=" + this.index);

(4)內部類向上轉型

內部類也可以和普通類一樣擁有向上轉型的特性。將內部類向上轉型爲基類型,尤其是接口時,內部類就有了用武之地。如果內部類是private的,只可以被它的外部類問,從而完全隱藏實現的細節。

(5)方法內的類

方法內創建的類(注意方法中也能定義類),不能加訪問修飾符。另外,方法內部的類也不是在調用方法時纔會創建的,它們一樣也被事先編譯了。

(6)靜態內部類

定義靜態內部類:在定義內部類的時候,可以在其前面加上一個權限修飾符static。此時這個內部類就變爲了靜態內部類。

通常稱爲嵌套類,當內部類是static時,意味着:

[1]要創建嵌套類的對象,並不需要其外圍類的對象;

[2]不能從嵌套類的對象中訪問非靜態的外圍類對象(不能夠從靜態內部類的對象中訪問外部類的非靜態成員);

嵌套類與普通的內部類還有一個區別:普通內部類的字段的字段與方法,只能放在類的外部層次上,所以普通的內部類不能有static數據和static字段,也不能包含嵌套類。但是在嵌套類裏可以包含所有這些東西。也就是說,在非靜態內部類中不可以聲明靜態成員,只有將某個內部類修飾爲靜態類,然後才能夠在這個類中定義靜態的成員變量與成員方法。

另外,在創建靜態內部類時不需要將靜態內部類的實例綁定在外部類的實例上。普通非靜態內部類的對象是依附在外部類對象之中的,要在一個外部類中定義一個靜態的內部類,不需要利用關鍵字new來創建內部類的實例。靜態類和方法只屬於類本身,並不屬於該類的對象,更不屬於其他外部類的對象。

(7)內部類標識符

每個類會產生一個.class文件,文件名即爲類名。同樣,內部類也會產生這麼一個.class文件,但是它的名稱卻不是內部類的類名,而是有着嚴格的限制:外圍類的名字,加上$,再加上內部類名字。

(8)爲何要用內部類?

1. 內部類一般只爲其外部類使用;

2. 內部類提供了某種進入外部類的窗戶;

3. 也是最吸引人的原因,每個內部類都能獨立地繼承一個接口,而無論外部類是否已經繼承了某個接口。因此,內部類使多重繼承的解決方案變得更加完整。

發佈了22 篇原創文章 · 獲贊 0 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章