java中靜態代碼塊的用法 static用法詳解

來源:互聯網
上載者:User

  static表示“全域”或者“靜態”的意思,用來修飾成員變數和成員方法,也可以形成靜態static代碼塊,但是Java語言中沒有全域變數的概念。被static修飾的成員變數和成員方法獨立於該類的任何對象。也就是說,它不依賴類特定的執行個體,被類的所有執行個體共用。

  只要這個類被載入,Java虛擬機器就能根據類名在運行時資料區的方法區內定找到他們。因此,static對象可以在它的任何對象建立之前訪問,無需引用任何對象。用public修飾的static成員變數和成員方法本質是全域變數和全域方法,當聲明它類的對象市,不產生static變數的副本,而是類的所有執行個體共用同一個static變數。

  static變數前可以有private修飾,表示這個變數可以在類的靜態代碼塊中,或者類的其他靜態成員方法中使用(當然也可以在非靜態成員方法中使用--廢話),但是不能在其他類中通過類名來直接引用,這一點很重要。實際上你需要搞明白,private是存取權限限定,static表示不要執行個體化就可以使用,這樣就容易理解多了。static前面加上其它存取權限關鍵字的效果也以此類推。

  static修飾的成員變數和成員方法習慣上稱為靜態變數和靜態方法,可以直接通過類名來訪問,訪問文法為:
  類名.靜態方法名(參數列表...)
  類名.靜態變數名

  用static修飾的代碼塊表示靜態代碼塊,當Java虛擬機器(JVM)載入類時,就會執行該代碼塊(用處非常大,呵呵)。 

  1、static變數
    按照是否靜態對類成員變數進行分類可分兩種:一種是被static修飾的變數,叫靜態變數或類變數;另一種是沒有被static修飾的變數,叫執行個體變數。

  兩者的區別是:
   對於靜態變數在記憶體中只有一個拷貝(節省記憶體),JVM只為靜態分配一次記憶體,在載入類的過程中完成靜態變數的記憶體配置,可用類名直接存取(方便),當然也可以通過對象來訪問(但是這是不推薦的)。
   對於執行個體變數,沒建立一個執行個體,就會為執行個體變數分配一次記憶體,執行個體變數可以在記憶體中有多個拷貝,互不影響(靈活)。

  所以一般在需要實現以下兩個功能時使用靜態變數:
    在對象之間共用值時
    方便訪問變數時

  2、靜態方法
    靜態方法可以直接通過類名調用,任何的執行個體也都可以調用,
    因此靜態方法中不能用this和super關鍵字,不能直接存取所屬類的執行個體變數和執行個體方法(就是不帶static的成員變數和成員成員方法),只能訪問所屬類的靜態成員變數和    成員方法。
    因為執行個體成員與特定的對象關聯!這個需要去理解,想明白其中的道理,不是記憶!!!
    因為static方法獨立於任何執行個體,因此static方法必須被實現,而不能是抽象的abstract。

    例如為了方便方法的調用,Java API中的Math類中所有的方法都是靜態,而一般類內部的static方法也是方便其它類對該方法的調用。

    靜態方法是類內部的一類特殊方法,只有在需要時才將對應的方法聲明成靜態,一個類內部的方法一般都是非靜態

  3、static代碼塊

   static代碼塊也叫靜態代碼塊,是在類中獨立於類成員的static語句塊,可以有多個,位置可以隨便放,它不在任何的方法體內,JVM載入類時會執行這些靜態代碼塊,如果static代碼塊有多個,JVM將按照它們在類中出現的先後順序依次執行它們,每個代碼塊只會被執行一次。例如:

public class Test5 {private static int a;private int b;static{Test5.a=3;System.out.println(a);Test5 t=new Test5();t.f();t.b=1000;System.out.println(t.b);}static{Test5.a=4;System.out.println(a);}public static void main(String[] args) {// TODO 自動產生方法存根}static{Test5.a=5;System.out.println(a);}public void f(){System.out.println("hhahhahah");}} 

  運行結果:

3hhahhahah100045

  利用靜態代碼塊可以對一些static變數進行賦值,最後再看一眼這些例子,都一個static的main方法,這樣JVM在運行main方法的時候可以直接調用而不用建立執行個體。 

  4、static和final一塊用表示什麼
  static final用來修飾成員變數和成員方法,可簡單理解為“全域常量”!
  對於變數,表示一旦給值就不可修改,並且通過類名可以訪問。
  對於方法,表示不可覆蓋,並且可以通過類名直接存取。

  有時你希望定義一個類成員,使它的使用完全獨立於該類的任何對象。通常情況下,類成員必須通過它的類的對象訪問,但是可以建立這樣一個成員,它能夠被它自己使用,而不必引用特定的執行個體。在成員的聲明前面加上關鍵字static(靜態)就能建立這樣的成員。如果一個成員被聲明為static,它就能夠在它的類的任何對象建立之前被訪問,而不必引用任何對象。你可以將方法和變數都聲明為static。static 成員的最常見的例子是main( ) 。因為在程式開始執行時必須調用main() ,所以它被聲明為static。

  聲明為static的變數實質上就是全域變數。當聲明一個對象時,並不產生static變數的拷貝,而是該類所有的執行個體變數共用同一個static變數。聲明為static的方法有以下幾條限制:
  •它們僅能調用其他的static 方法。
  •它們只能訪問static資料。
  •它們不能以任何方式引用this 或super(關鍵字super 與繼承有關,在下一章中描述)。
  如果你需要通過計算來初始化你的static變數,你可以聲明一個static塊,Static 塊僅在該類被載入時執行一次。下面的例子顯示的類有一個static方法,一些static變數,以及一個static 初始化塊:

// Demonstrate static variables,methods,and blocks.class UseStatic {static int a = 3;static int b;static void meth(int x) {System.out.println("x = " + x);System.out.println("a = " + a);System.out.println("b = " + b);}static {System.out.println("Static block initialized.");b = a * 4;}public static void main(String args[]) {meth(42);}} 

  一旦UseStatic 類被裝載,所有的static語句被運行。首先,a被設定為3,接著static 塊執行(列印一條訊息),最後,b被初始化為a*4 或12。然後調用main(),main() 調用meth() ,把值42傳遞給x。3個println ( ) 語句引用兩個static變數a和b,以及局部變數x 。

  注意:在一個static 方法中引用任何執行個體變數都是非法的。

  下面是該程式的輸出:

Static block initialized.x = 42a = 3b = 12 

  在定義它們的類的外面,static 方法和變數能獨立於任何對象而被使用。這樣,你只要在類的名字後面加點號運算子即可。例如,如果你希望從類外面調用一個static方法,你可以使用下面通用的格式:

  classname.method( )

  這裡,classname 是類的名字,在該類中定義static方法。可以看到,這種格式與通過對象引用變數調用非static方法的格式類似。一個static變數可以以同樣的格式來訪問——類名加點號運算子。這就是Java 如何?全域功能和全域變數的一個控製版本。

  下面是一個例子。在main() 中,static方法callme() 和static 變數b在它們的類之外被訪問。

class StaticDemo {static int a = 42;static int b = 99;static void callme() {System.out.println("a = " + a);}}class StaticByName {public static void main(String args[]) {StaticDemo.callme();System.out.println("b = " + StaticDemo.b);}} 

  下面是該程式的輸出:

a = 42b = 99

  static成員是不能被其所在class建立的執行個體訪問的。如果不加static修飾的成員是對象成員,也就是歸每個對象所有的。加static修飾的成員是類成員,就是可以由一個類直接調用,為所有對象共有的。

1、static變數
 按照是否靜態對類成員變數進行分類可分兩種:一種是被static修飾的變數,叫靜態變數或類變數;另一種是沒有被static修飾的變數,叫執行個體變數。

兩者的區別是:
 對於靜態變數在記憶體中只有一個拷貝(節省記憶體),JVM只為靜態分配一次記憶體,在載入類的過程中完成靜態變數的記憶體配置,可用類名直接存取(方便),當然也可以通過對象來訪問(但是這是不推薦的)。
 對於執行個體變數,沒建立一個執行個體,就會為執行個體變數分配一次記憶體,執行個體變數可以在記憶體中有多個拷貝,互不影響(靈活)。

所以一般在需要實現以下兩個功能時使用靜態變數:
  在對象之間共用值時
  方便訪問變數時

2、靜態方法
靜態方法可以直接通過類名調用,任何的執行個體也都可以調用,
因此靜態方法中不能用this和super關鍵字,不能直接存取所屬類的執行個體變數和執行個體方法(就是不帶static的成員變數和成員成員方法),只能訪問所屬類的靜態成員變數和成員方法。
因為執行個體成員與特定的對象關聯!這個需要去理解,想明白其中的道理,不是記憶!!!
因為static方法獨立於任何執行個體,因此static方法必須被實現,而不能是抽象的abstract。

例如為了方便方法的調用,Java API中的Math類中所有的方法都是靜態,而一般類內部的static方法也是方便其它類對該方法的調用。

靜態方法是類內部的一類特殊方法,只有在需要時才將對應的方法聲明成靜態,一個類內部的方法一般都是非靜態

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

靜態方法
(1)在Java裡,可以定義一個不需要建立對象的方法,這種方法就是靜態方法。要實現這樣的效果,只需要在類中定義的方法前加上static關鍵字。例如:

public static int maximum(int n1,int n2)

使用類的靜態方法時,注意:

a在靜態方法裡只能直接調用同類中其他的靜態成員(包括變數和方法),而不能直接存取類中的非靜態成員。這是因為,對於非靜態方法和變數,需要先建立類的執行個體對象後才可使用,而靜態方法在使用前不用建立任何對象。

b 靜態方法不能以任何方式引用this和super關鍵字,因為靜態方法在使用前不用建立任何執行個體對象,當靜態方法調用時,this所引用的對象根本沒有產生。

(2)靜態變數是屬於整個類的變數而不是屬於某個對象的。注意不能把任何方法體內的變數聲明為靜態,例如:
fun()
{
static int i=0;//非法。
}

(3)一個類可以使用不包含在任何方法體中的靜態代碼塊,當類被載入時,靜態代碼塊被執行,且只被執行一次,靜態塊常用來執行類屬性的初始化。例如:
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 blockchild static blockparent blockparent constructorchild blockchild constructor

  

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

總結:
對象的初始化順序:首先執行父類靜態內容,父類靜態內容執行完畢後,接著去執行子類的靜態內容,當子類的靜態內容執行完畢之後,再去看父類有沒有非靜態代碼塊,如果有就執行父類的非靜態代碼塊,父類的非靜態代碼塊執行完畢,接著執行父類的構造方法;父類的構造方法執行完畢之後,它接著去看子類有沒有非靜態代碼塊,如果有就執行子類的非靜態代碼塊。子類的非靜態代碼塊執行完畢再去執行子類的構造方法。總之一句話,靜態代碼塊內容先執行,接著執行父類非靜態代碼塊和構造方法,然後執行子類非靜態代碼塊和構造方法。

注意:子類的構造方法,不管這個構造方法帶不帶參數,預設的它都會先去尋找父類的不帶參數的構造方法。如果父類沒有不帶參數的構造方法,那麼子類必須用supper關鍵子來調用父類帶參數的構造方法,否則編譯不能通過。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.