java static詳解

static表示“全局”或者“靜態”的意思,用來修飾成員變量和成員方法,也可以形成靜態static代碼塊,但是Java語言中沒有全局變量的概念。

被static修飾的成員變量和成員方法獨立於該類的任何對象。也就是說,它不依賴類特定的實例,被類的所有實例共享。

只要這個類被加載,Java虛擬機就能根據類名在運行時數據區的方法區內定找到他們。因此,static對象可以在它的任何對象創建之前訪問,無需引用任何對象。

用public修飾的static成員變量和成員方法本質是全局變量和全局方法,當聲明它類的對象市,不生成static變量的副本,而是類的所有實例共享同一個static變量。

static變量
按照是否靜態的對類成員變量進行分類可分兩種:一種是被static修飾的變量,叫靜態變量或類變量;另一種是沒有被static修飾的變量,叫實例變量。

兩者的區別是:
對於靜態變量在內存中只有一個拷貝(節省內存),JVM只爲靜態分配一次內存,在加載類的過程中完成靜態變量的內存分配,可用類名直接訪問(方便),當然也可以通過對象來訪問(但是這是不推薦的)。
對於實例變量,沒創建一個實例,就會爲實例變量分配一次內存,實例變量可以在內存中有多個拷貝,互不影響(靈活)。

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

(一)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 block
child static block
parent block
parent constructor
child block
child constructor

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

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

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


static和final一塊用表示什麼

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章