1. 程式人生 > >Java靜態內部類的作用

Java靜態內部類的作用

      在一個類中建立另外一個類,叫做成員內部類。這個成員內部類可以靜態的(利用static關鍵字修飾),也可以是非靜態的。由於靜態的內部類在定義、使用的時候會有種種的限制。所以在實際工作中用到的並不多。 
在開發過程中,內部類中使用的最多的還是非靜態地成員內部類。不過在特定的情況下,靜態內部類也能夠發揮其獨特的作用。 
一、靜態內部類的使用目的。 

     在定義內部類的時候,可以在其前面加上一個許可權修飾符static。此時這個內部類就變為了靜態內部類。不過由於種種的原因,如使用上的限制等等因素(具體的使用限制,筆者在下面的內容中會詳細闡述),在實際工作中用的並不是很多。但是並不是說其沒有價值。在某些特殊的情況下,少了這個靜態內部類還真是不行。

如在進行程式碼程式測試的時候,如果在每一個Java原始檔中都設定一個主方法(主方法是某個應用程式的入口,必須具有),那麼會出現很多額外的程式碼。而且最主要的時這段主程式的程式碼對於Java檔案來說,只是一個形式,其本身並不需要這種主方法。但是少了這個主方法又是萬萬不行的。在這種情況下,就可以將主方法寫入到靜態內部類中,從而不用為每個Java原始檔都設定一個類似的主方法。這對於程式碼測試是非常有用的。在一些中大型的應用程式開發中,則是一個常用的技術手段。為此,這個靜態內部類雖然不怎麼常用,但是程式開發人員還必須要掌握它。也許在某個關鍵的時刻,其還可以發揮巨大的作用也說不定。 

下面的例子所示:

public class Student {
	//.......程式碼
	
	
}
public class Person{  
     //姓名  
     private String name;  
     //家庭  
     private Home home;  
     //建構函式設定屬性值  
     public Person(String _name){  
          name = _name;  
     }  
     /* home、name的getter/setter方法省略 */  
 public void setHome(Home home){
	 this.home = home;
 }
 
 public Home getHome(){
	 return home;
 }
 
 
 
     public static class Home{  
          //家庭地址  
          private String address;  
          //家庭電話  
          private String tel;  
 
          public Home(String _address,String _tel){  
            address = _address;  
            tel = _tel;  
          }  
          /* address、tel的getter/setter方法省略 */ 
          
          public static void main(String[] args) {  
      	    Student student = new Student();
      	}
     }  
      
} 
二、靜態內部類的使用限制。 
將某個內部類定義為靜態類,跟將其他類定義為靜態類的方法基本相同,引用規則也基本一致。不過其細節方面仍然有很大的不同。具體來說,主要有如下幾個地方要引起各位程式開發人員的注意。 
一是靜態成員(包括靜態變數與靜態成員)的定義。一般情況下,如果一個內部類不是被定義成靜態內部類,那麼在定義成員變數或者成員方法的時候,是不能夠被定義成靜態成員變數與靜態成員方法的。也就是說,在非靜態內部類中不可以宣告靜態成員。如現在在一個student類中定義了一個內部類age,如果沒有將這個類利用static關鍵字修飾,即沒有定義為靜態類,那麼在這個內部類中如果要利用static關鍵字來修飾某個成員方法或者成員變數是不允許的。在編譯的時候就通不過。故程式開發人員需要注意,只有將某個內部類修飾為靜態類,然後才能夠在這個類中定義靜態的成員變數與成員方法。這是靜態內部類都有的一個特性。也正是因為這個原因,有時候少了這個靜態的內部類,很多工作就無法完成。或者說要繞一個大圈才能夠實現某個使用者的需求。這也是靜態的內部類之所以要存在的一個重要原因。 
二是在成員的引用上,有比較大的限制。一般的非靜態內部類,可以隨意的訪問外部類中的成員變數與成員方法。即使這些成員方法被修飾為private(私有的成員變數或者方法),其非靜態內部類都可以隨意的訪問。則是非靜態內部類的特權。因為在其他類中是無法訪問被定義為私有的成員變數或則方法。但是如果一個內部類被定義為靜態的,那麼在銀用外部類的成員方法或則成員變數的時候,就會有諸多的限制。如不能夠從靜態內部類的物件中訪問外部類的非靜態成員(包括成員變數與成員方法)。這是什麼意思呢?如果在外部類中定義了兩個變數,一個是非靜態的變數,一個是靜態的變數。那麼在靜態內部類中,無論在成員方法內部還是在其他地方,都只能夠引用外部類中的靜態的變數,而不能夠訪問非靜態的變數。在靜態內部類中,可以定義靜態的方法(也只有在靜態的內部類中可以定義靜態的方法),在靜態方法中引用外部類的成員。但是無論在內部類的什麼地方引用,有一個共同點,即都只能夠引用外部類中的靜態成員方法或者成員變數。對於那些非靜態的成員變數與成員方法,在靜態內部類中是無法訪問的。這就是靜態內部類的最大使用限制。在普通的非靜態內部類中是沒有這個限制的。也正是這個原因,決定了靜態內部類只應用在一些特定的場合。其應用範圍遠遠沒有像非靜態的內部類那樣廣泛。 
三是在建立靜態內部類時不需要將靜態內部類的例項繫結在外部類的例項上。 
      通常情況下,在一個類中建立成員內部類的時候,有一個強制性的規定,即內部類的例項一定要繫結在外部類的例項中。也就是說,在建立內部類之前要先在外部類中要利用new關鍵字來建立這個內部類的物件。如此的話如果從外部類中初始化一個內部類物件,那麼內部類物件就會繫結在外部類物件上。也就是說,普通非靜態內部類的物件是依附在外部類物件之中的。但是,如果成員開發人員建立的時靜態內部類,那麼這就又另當別論了。通常情況下,程式設計師在定義靜態內部類的時候,是不需要定義繫結在外部類的例項上的。也就是說,要在一個外部類中定義一個靜態的內部類,不需要利用關鍵字new來建立內部類的例項。即在建立靜態類內部物件時,不需要其外部類的物件。具體為什麼會這樣,一般程式開發人員不需要了解這麼深入,只需要記住有這個規則即可。在定義靜態內部類的時候,千萬不要犯畫蛇添足的錯誤。 
從以上的分析中可以看出,靜態內部類與非靜態的內部類還是有很大的不同的。一般程式開發人員可以這麼理解,非晶態的內部類物件隱式地在外部類中儲存了一個引用,指向建立它的外部類物件。 不管怎麼理解,程式開發人員都需要牢記靜態內部類與非靜態內部類的差異。如是否可以建立靜態的成員方法與成員變數(靜態內部類可以建立靜態的成員而非靜態的內部類不可以)、對於訪問外部類的成員的限制(靜態內部類只可以訪問外部類中的靜態成員變數與成員方法而非靜態的內部類即可以訪問靜態的也可以訪問非靜態的外部類成員方法與成員變數)。這兩個差異是靜態內部類與非靜態外部類最大的差異,也是靜態內部類之所以存在的原因。瞭解了這個差異之後,程式開發人員還需要知道,在什麼情況下該使用靜態內部類。如在程式測試的時候,為了避免在各個Java原始檔中書寫主方法的程式碼,可以將主方法寫入到靜態內部類中,以減少程式碼的書寫量,讓程式碼更加的簡潔。  
總之,靜態內部類在Java語言中是一個很特殊的類,跟普通的靜態類以及非靜態的內部類都有很大的差異。作為程式開發人員,必須要知道他們之間的差異,並在實際工作中在合適的地方採用合適的類。不過總的來說,靜態內部類的使用頻率並不是很高。但是在有一些場合,如果沒有這個內部靜態類的話,可能會起到事倍功半的反面效果.
package com.devin;

public class MyMain{
    private static String name = "woobo";
    private String num = "X001";
 
    // 靜態內部類可以用public,protected,private修飾
    static class Person {
        // 靜態內部類中可以定義靜態或者非靜態的成員
        private String address = "China";

        private static String x = "as";
        public String mail = "[email protected]";// 內部類公有成員

        public void display() {
            // System.out.println(num);//不能直接訪問外部類的非靜態成員

            // 靜態內部類不能訪問外部類的非靜態成員(包括非靜態變數和非靜態方法)
            System.out.println(name);// 只能直接訪問外部類的靜態成員

            // 靜態內部類只能訪問外部類的靜態成員(包括靜態變數和靜態方法)
            System.out.println("Inner " + address);// 訪問本內部類成員。
        }
    }

    public void printInfo() {
        Person person = new Person();

        // 外部類訪問內部類的非靜態成員:例項化內部類即可
        person.display();

        // System.out.println(mail);//不可訪問
        // System.out.println(address);//不可訪問
        System.out.println(person.address);// 可以訪問內部類的私有成員

        System.out.println(Person.x);// 外部類訪問內部類的靜態成員:內部類.靜態成員
        System.out.println(person.mail);// 可以訪問內部類的公有成員
    }

    public static void main(String[] args) {
        MyMain staticTest = new MyMain();
        staticTest.printInfo();
    }
}

1. 巢狀類的物件,並不需要其外圍類的物件。 即它可以不依賴於外部類例項被例項化。

2. 不能從巢狀類的物件中訪問非靜態的外圍類物件。 這是由Java語法中"靜態方法不能直接訪問非靜態成員"所限定

3. 外部類訪問內部類的的成員有些特別, 不能直接訪問, 但可以通過內部類例項來訪問, 這是因為靜態巢狀內的所有成員和方法預設為靜態的了.同時注意, 內部靜態類Person只在類StaticTest 範圍內可見, 若在其它類中引用或初始化, 均是錯誤的.
4 . 靜態內部類可以有靜態成員,而非靜態內部類則不能有靜態成員。 
5. 靜態內部類的非靜態成員可以訪問外部類的靜態變數,而不可訪問外部類的非靜態變數;

6 . 非靜態內部類的非靜態成員可以訪問外部類的非靜態變數。

    生成一個靜態內部類不需要外部類成員:這是靜態內部類和成員內部類的區別。靜態內部類的物件可以直接生成:Outer.Inner in = new Outer.Inner();而不需要通過生成外部類物件來生成。這樣實際上使靜態內部類成為了一個頂級類(正常情況下,你不能在介面內部放置任何程式碼,但巢狀類可以作為介面的一部分,因為它是static 的。只是將巢狀類置於介面的名稱空間內,這並不違反介面的規則)

Java裡面static一般用來修飾成員變數或函式。但有一種特殊用法是用static修飾內部類,普通類是不允許宣告為靜態的,只有內部類才可以。被static修飾的內部類可以直接作為一個普通類來使用,而不需例項一個外部類(見如下程式碼):

public class OuterClass {
	public static class InnerClass{
		InnerClass(){
			System.out.println("============= 我是一個內部類'InnerClass' =============");
		}
	}
}

public class TestStaticClass {
	public static void main(String[] args) {
		// 不需要new一個OutClass
		new OuterClass.InnerClass();
	}
}

如果沒有用static修飾InterClass,則只能按如下方式呼叫:
package inner_class;

public class OuterClass {
	public class InnerClass{
		InnerClass(){
			System.out.println("============= 我是一個內部類'InnerClass' =============");
		}
	}
}

public class TestStaticClass {
	public static void main(String[] args) {
		// OutClass需要先生成一個例項
		OuterClass oc = new OuterClass();
		oc.new InnerClass();
	}
}