閱讀256 返回首頁    go 阿裏雲 go 技術社區[雲棲]


Java4Android之靜態相關

在這一節,我希望把跟Java Static相關的知識點全部涉及到,至少看完本帖的時候,你對Java 靜態的了解能夠讓你在茶餘飯後能夠與其他程序員聊上一會。
Java中的靜態主要分為:靜態成員變量,靜態成員函數,靜態代碼段,靜態類。我們一個個娓娓道來。
本文的組織如下,首先,我們說明靜態和非靜態的區別;然後我們具體一個個的去講上述靜態相關知識點。


1,靜態對象與非靜態對象的區別


靜態和非靜態的區別對比見下表

比較項目 靜態 非靜態
擁有屬性  是類共同擁有的   是類各對象獨立擁有的
內存分配 內存空間上是固定的 空間在各個附屬類裏麵分配 
分配順序 先分配靜態對象的空間   繼而再對非靜態對象分配空間,也就是初始化順序
是先靜態再非靜態.

靜態對象的好處:

1)靜態對象的數據在全局是唯一的,一改都改。如果你想要處理的東西是整個程序中唯一的,弄成靜態是個好方法。 非靜態的東西你修改以後隻是修改了他自己的數據,但是不會影響其他同類對象的數據;
2)引用方便。直接用 類名.靜態方法名  或者  類名.靜態變量名就可引用並且直接可以修改其屬性值,不用get和set方法;
3)保持數據的唯一性。此數據全局都是唯一的,修改他的任何一處地方,在程序所有使用到的地方都將會體現到這些數據的修改。有效減少多餘的浪費;
4)static final用來修飾成員變量和成員方法,可簡單理解為“全局常量”。對於變量,表示一旦給值就不可修改;對於方法,表示不可覆蓋;
5)靜態,它並不是一個好的麵向對象思想,如果你發現自己的靜態使用過多,說明設計出了問題。


2 , 靜態成員變量

通常情況下,類成員必須通過它的類的對象訪問,但是可以創建這樣一個成員,它能夠被它自己使用,而不必引用特定的實例。在成員的聲明前麵加上關鍵字static就能創建這樣的成員。如果一個成員被聲明為static,它就能夠在它的類的任何對象創建之前被訪問,而不必引用任何對象(跟類是否有static修飾無關)。

3,靜態成員方法
static 成員的最常見的 例子是main( ) 。因為在程序開始執行時必須調用main() ,所以它被聲明為static。 聲明為static的變量實質上就是全局變量。聲明為static的方法有以下幾條限製:  ·
1)它們僅能調用其他的static 方法
2)它們隻能訪問static數據
3)它們不能以任何方式引用this 或super(this涉及到對象,super 與繼承有關)

4,靜態代碼塊
一般情況下,如果有些代碼必須在項目啟動的時候就執行的時候,需要使用靜態代碼塊,這種代碼是主動執行的;需要在項目啟動的時候就初始化,在不創建對象的情況下,其他程序來調用的時候,需要使用靜態方法,這種代碼是被動執行的. 靜態方法在類加載的時候 就已經加載 可以用類名直接調用比如main方法就必須是靜態的 這是程序入口兩者的區別就是:靜態代碼塊是自動執行的;靜態方法是被調用的時候才執行的.


一個類可以使用不包含在任何方法體中的靜態代碼塊,當類被載入時,靜態代碼塊被執行,且隻被執行一次,靜態塊常用來執行類屬性的初始化。例如:
static
{
}

類裝載順序:


在Java中,類裝載器把一個類裝入Java虛擬機中,要經過三個步驟來完成:裝載、鏈接和初始化,其中鏈接又可以分成校驗、準備和解析三步,除了解析外,其它步驟是嚴格按照順序完成的,各個步驟的主要工作如下:


裝載:查找和導入類或接口的二進製數據;
鏈接:執行下麵的校驗、準備和解析步驟,其中解析步驟是可以選擇的;
校驗:檢查導入類或接口的二進製數據的正確性;
準備:給類的靜態變量分配並初始化存儲空間;
解析:將符號引用轉成直接引用;
初始化:激活類的靜態變量的初始化Java代碼和靜態Java代碼塊。
初始化類中屬性是靜態代碼塊的常用用途,但隻能使用一次。

示例代碼:

class Parent{ 
static String name = "hello"; 
{ 
System.out.println("parent block"); 
} 
static { 
System.out.println("parent static block"); 
} 
public Parent(){ 
System.out.println("parent constructor"); 
} 
} 

class Child extends Parent{ 
static String childName = "hello"; 
{ 
System.out.println("child block"); 
} 
static { 
System.out.println("child static block"); 
} 
public Child(){ 
System.out.println("child constructor"); 
} 
} 

public class StaticIniBlockOrderTest { 

public static void main(String[] args) { 
new Child();//語句(*) 
} 
}

輸出結果:

parent static block
child static block
parent block
parent constructor
child block
child constructor

當執行new Child()時,它首先去看父類裏麵有沒有靜態代碼塊,如果有,它先去執行父類裏麵靜態代碼塊裏麵的內容,當父類的靜態代碼塊裏麵的內容執行完畢之後,接著去執行子類(自己這個類)裏麵的靜態代碼塊,當子類的靜態代碼塊執行完畢之後,它接著又去看父類有沒有非靜態代碼塊,如果有就執行父類的非靜態代碼塊,父類的非靜態代碼塊執行完畢,接著執行父類的構造方法;父類的構造方法執行完畢之後,它接著去看子類有沒有非靜態代碼塊,如果有就執行子類的非靜態代碼塊。子類的非靜態代碼塊執行完畢再去執行子類的構造方法,這個就是一個對象的初始化順序。


5,靜態類


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

1)靜態類使用的目的

在定義內部類的時候,可以在其前麵加上一個權限修飾符static。此時這個內部類就變為了靜態內部類。不過由於種種的原因,如使用上的限製等等因素(具體的使用限製,筆者在下麵的內容中會詳細闡述),在實際工作中用的並不是很多。但是並不是說其沒有價值。在某些特殊的情況下,少了這個靜態內部類還真是不行。如在進行代碼程序測試的時候,如果在每一個Java源文件中都設置一個主方法(主方法是某個應用程序的入口,必須具有),那麼會出現很多額外的代碼。而且最主要的時這段主程序的代碼對於Java文件來說,隻是一個形式,其本身並不需要這種主方法。但是少了這個主方法又是萬萬不行的。在這種情況下,就可以將主方法寫入到靜態內部類中,從而不用為每個Java源文件都設置一個類似的主方法。這對於代碼測試是非常有用的。在一些中大型的應用程序開發中,則是一個常用的技術手段。為此,這個靜態內部類雖然不怎麼常用,但是程序開發人員還必須要掌握它。也許在某個關鍵的時刻,其還可以發揮巨大的作用也說不定。

public class MainInStaticClass {
 
 static class Main{
static void main() {
//將主方法寫到靜態內部類中,從而不必為每個源文件都這種一個類似的主方法
new MainInStaticClass().print();
}
}
 
public static void main(String[] args){
new MainInStaticClass().print();
}
 
public void print(){
System.out.println("main in static inner class");
}
}
 
 
public class TestMain {
 
 
public static void main(String[] args) {
// TODO Auto-generated method stub
// new MainInStaticClass().print();
MainInStaticClass.Main.main();
new MainInStaticClass.Main();
}
 
}


2)靜態內部類使用的限製

將某個內部類定義為靜態類,跟將其他類定義為靜態類的方法基本相同,引用規則也基本一致。不過其細節方麵仍然有很大的不同。具體來說,主要有如下幾個地方要引起各位程序開發人員的注意。


  一是靜態成員(包括靜態變量與靜態成員)的定義。一般情況下,如果一個內部類不是被定義成靜態內部類,那麼在定義成員變量或者成員方法的時候,是不能夠被定義成靜態成員變量與靜態成員方法的。也就是說,在非靜態內部類中不可以聲明靜態成員。如現在在一個student類中定義了一個內部類age,如果沒有將這個類利用static關鍵字修飾,即沒有定義為靜態類,那麼在這個內部類中如果要利用static關鍵字來修飾某個成員方法或者成員變量是不允許的。在編譯的時候就通不過。故程序開發人員需要注意,隻有將某個內部類修飾為靜態類,然後才能夠在這個類中定義靜態的成員變量與成員方法。這是靜態內部類都有的一個特性。也正是因為這個原因,有時候少了這個靜態的內部類,很多工作就無法完成。或者說要繞一個大圈才能夠實現某個用戶的需求。這也是靜態的內部類之所以要存在的一個重要原因。


後注:經過大家的指正,現聲明:非靜態內部類也可以定義靜態成員但需要同時有final關鍵詞修飾,靜態方法鑒於無法用final修飾,仍必須是在靜態內部類 或者非內部類中定義。


  二是在成員的引用上,有比較大的限製。一般的非靜態內部類,可以隨意的訪問外部類中的成員變量與成員方法。即使這些成員方法被修飾為private(私有的成員變量或者方法),其非靜態內部類都可以隨意的訪問。則是非靜態內部類的特權。因為在其他類中是無法訪問被定義為私有的成員變量或則方法。但是如果一個內部類被定義為靜態的,那麼在銀用外部類的成員方法或則成員變量的時候,就會有諸多的限製。如不能夠從靜態內部類的對象中訪問外部類的非靜態成員(包括成員變量與成員方法)。這是什麼意思呢?如果在外部類中定義了兩個變量,一個是非靜態的變量,一個是靜態的變量。那麼在靜態內部類中,無論在成員方法內部還是在其他地方,都隻能夠引用外部類中的靜態的變量,而不能夠訪問非靜態的變量。在靜態內部類中,可以定義靜態的方法(也隻有在靜態的內部類中可以定義靜態的方法),在靜態方法中引用外部類的成員。但是無論在內部類的什麼地方引用,有一個共同點,即都隻能夠引用外部類中的靜態成員方法或者成員變量。對於那些非靜態的成員變量與成員方法,在靜態內部類中是無法訪問的。這就是靜態內部類的最大使用限製。在普通的非靜態內部類中是沒有這個限製的。也正是這個原因,決定了靜態內部類隻應用在一些特定的場合。其應用範圍遠遠沒有像非靜態的內部類那樣廣泛。


 三是在創建靜態內部類時不需要將靜態內部類的實例綁定在外部類的實例上。


通常情況下,在一個類中創建成員內部類的時候,有一個強製性的規定,即內部類的實例一定要綁定在外部類的實例中。也就是說,在創建內部類之前要先在外部類中要利用new關鍵字來創建這個內部類的對象。如此的話如果從外部類中初始化一個內部類對象,那麼內部類對象就會綁定在外部類對象上。也就是說,普通非靜態內部類的對象是依附在外部類對象之中的。但是,如果成員開發人員創建的時靜態內部類,那麼這就又另當別論了。通常情況下,程序員在定義靜態內部類的時候,是不需要定義綁定在外部類的實例上的。也就是說,要在一個外部類中定義一個靜態的內部類,不需要利用關鍵字new來創建內部類的實例。即在創建靜態類內部對象時,不需要其外部類的對象。


new MainInStaticClass.Main();


 
具體為什麼會這樣,一般程序開發人員不需要了解這麼深入,隻需要記住有這個規則即可。在定義靜態內部類的時候,千萬不要犯畫蛇添足的錯誤。


  從以上的分析中可以看出,靜態內部類與非靜態的內部類還是有很大的不同的。一般程序開發人員可以這麼理解,非靜態的內部類對象隱式地在外部類中保存了一個引用,指向創建它的外部類對象。不管這麼理解,程序開發人員都需要牢記靜態內部類與非靜態內部類的差異。如是否可以創建靜態的成員方法與成員變量(靜態內部類可以創建靜態的成員而非靜態的內部類不可以)、對於訪問外部類的成員的限製(靜態內部類隻可以訪問外部類中的靜態成員變量與成員方法而非靜態的內部類即可以訪問靜態的也可以訪問非靜態的外部類成員方法與成員變量)。這兩個差異是靜態內部類與非靜態外部類最大的差異,也是靜態內部類之所以存在的原因。了解了這個差異之後,程序開發人員還需要知道,在什麼情況下該使用靜態內部類。如在程序測試的時候,為了避免在各個Java源文件中書寫主方法的代碼,可以將主方法寫入到靜態內部類中,以減少代碼的書寫量,讓代碼更加的簡潔。
  總之,靜態內部類在Java語言中是一個很特殊的類,跟普通的靜態類以及非靜態的內部類都有很大的差異。作為程序開發人員,必須要知道他們之間的差異,並在實際工作中在合適的地方采用合適的類。不過總的來說,靜態內部類的使用頻率並不是很高。但是在有一些場合,如果沒有這個內部靜態類的話,可能會起到事倍功半的反麵效果

參考及轉載:

[1] 靜態類:https://blog.sina.com.cn/s/blog_605f5b4f0100zbps.html

[2]靜態代碼塊:https://www.cnblogs.com/panjun-Donet/archive/2010/08/10/1796209.html

[3]靜態變量,方法和塊:https://blog.csdn.net/zhandoushi1982/article/details/8453522










最後更新:2017-04-03 05:40:13

  上一篇:go QTP/UFT11.5官方下載與安裝教程及漢化
  下一篇:go Java4Android之一切都是對象(1)