Java中static作用及用法詳解
1.1概述:
static是靜態修飾符,什麼叫靜態修飾符呢?大家都知道,在程式中任何變數或者程式碼都是在編譯時由系統自動分配記憶體來儲存的,而所謂靜態就是指在編譯後所分配的記憶體會一直存在,直到程式退出記憶體才會釋放這個空間,也就是隻要程式在執行,那麼這塊記憶體就會一直存在。這樣做有什麼意義呢?在Java程式裡面,所有的東西都是物件,而物件的抽象就是類,對於一個類而言,如果要使用他的成員,那麼普通情況下必須先例項化物件後,通過物件的引用才能夠訪問這些成員,但是用static修飾的成員可以通過類名加“.”進行直接訪問。
static表示“全域性”或者“靜態”的意思,用來修飾成員變數和成員方法,也可以形成靜態static程式碼塊,但是Java語言中沒有全域性變數的概念。
被static修飾的成員變數和成員方法獨立於該類的任何物件。也就是說,它不依賴類特定的例項,被類的所有例項共享。只要這個類被載入,Java虛擬機器就能根據類名在執行時資料區的方法區內定找到他們。因此,static物件可以在它的任何物件建立之前訪問,無需引用任何物件。
用public修飾的static成員變數和成員方法本質是全域性變數和全域性方法,當宣告它類的物件市,不生成static變數的副本,而是類的所有例項共享同一個static變數。
static變數前可以有private修飾,表示這個變數可以在類的靜態程式碼塊中,或者類的其他靜態成員方法中使用(當然也可以在非靜態成員方法中使用--廢話),但是不能在其他類中通過類名來直接引用,這一點很重要。實際上你需要搞明白,private
static修飾的成員變數和成員方法習慣上稱為靜態變數和靜態方法,可以直接通過類名來訪問,訪問語法為:
類名.靜態方法名(引數列表...)
類名.靜態變數名
用static修飾的程式碼塊表示靜態程式碼塊,當Java虛擬機器(JVM)載入類時,就會執行該程式碼塊(用處非常大,呵呵)。
按照是否靜態的對類成員變數進行分類可分兩種:一種是被static修飾的變數,叫靜態變數或類變數;另一種是沒有被static修飾的變數,叫例項變數。兩者的區別是:
對於靜態變數在記憶體中只有一個拷貝(節省記憶體),JVM只為靜態分配一次記憶體,在載入類的過程中完成靜態變數的記憶體分配,可用類名直接訪問(方便),當然也可以通過物件來訪問(但是這是不推薦的)。
對於例項變數,沒建立一個例項,就會為例項變數分配一次記憶體,例項變數可以在記憶體中有多個拷貝,互不影響(靈活)。
靜態方法可以直接通過類名呼叫,任何的例項也都可以呼叫,因此靜態方法中不能用this和super關鍵字,不能直接訪問所屬類的例項變數和例項方法(就是不帶static的成員變數和成員成員方法),只能訪問所屬類的靜態成員變數和成員方法。因為例項成員與特定的物件關聯!這個需要去理解,想明白其中的道理,不是記憶!!!因為static方法獨立於任何例項,因此static方法必須被實現,而不能是抽象的abstract。
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");
}
}
執行結果:
3
hhahhahah
1000
4
5
利用靜態程式碼塊可以對一些static變數進行賦值,最後再看一眼這些例子,都一個static的main方法,這樣JVM在執行main方法的時候可以直接呼叫而不用建立例項。
1、 static和final一塊用表示什麼
static final用來修飾成員變數和成員方法,可簡單理解為“全域性常量”!
對於變數,表示一旦給值就不可修改,並且通過類名可以訪問。
對於方法,表示不可覆蓋,並且可以通過類名直接訪問。
特別要注意一個問題:
對於被static和final修飾過的例項常量,例項本身不能再改變了,但對於一些容器型別(比如,ArrayList、HashMap)的例項變數,不可以改變容器變數本身,但可以修改容器中存放的物件,這一點在程式設計中用到很多。看個例子:
public class TestStaticFinal {
private static final String strStaticFinalVar ="aaa";
private static String strStaticVar =null;
private final String strFinalVar = null;
private static final int intStaticFinalVar = 0;
private static final Integer integerStaticFinalVar =new Integer(8);
private static final ArrayList<String>alStaticFinalVar = new ArrayList<String>();
private void test() {
System.out.println("-------------值處理前----------\r\n");
System.out.println("strStaticFinalVar=" +strStaticFinalVar + "\r\n");
System.out.println("strStaticVar=" +strStaticVar + "\r\n");
System.out.println("strFinalVar=" +strFinalVar + "\r\n");
System.out.println("intStaticFinalVar=" +intStaticFinalVar + "\r\n");
System.out.println("integerStaticFinalVar=" +integerStaticFinalVar + "\r\n");
System.out.println("alStaticFinalVar=" +alStaticFinalVar + "\r\n");
//strStaticFinalVar="哈哈哈哈"; //錯誤,final表示終態,不可以改變變數本身.
strStaticVar = "哈哈哈哈"; //正確,static表示類變數,值可以改變.
//strFinalVar="呵呵呵呵"; //錯誤, final表示終態,在定義的時候就要初值(哪怕給個null),一旦給定後就不可再更改。
//intStaticFinalVar=2; //錯誤, final表示終態,在定義的時候就要初值(哪怕給個null),一旦給定後就不可再更改。
//integerStaticFinalVar=new Integer(8); //錯誤, final表示終態,在定義的時候就要初值(哪怕給個null),一旦給定後就不可再更改。
alStaticFinalVar.add("aaa"); //正確,容器變數本身沒有變化,但存放內容發生了變化。這個規則是非常常用的,有很多用途。
alStaticFinalVar.add("bbb"); //正確,容器變數本身沒有變化,但存放內容發生了變化。這個規則是非常常用的,有很多用途。
System.out.println("-------------值處理後----------\r\n");
System.out.println("strStaticFinalVar=" +strStaticFinalVar + "\r\n");
System.out.println("strStaticVar=" +strStaticVar + "\r\n");
System.out.println("strFinalVar=" +strFinalVar + "\r\n");
System.out.println("intStaticFinalVar=" +intStaticFinalVar + "\r\n");
System.out.println("integerStaticFinalVar=" +integerStaticFinalVar + "\r\n");
System.out.println("alStaticFinalVar=" +alStaticFinalVar + "\r\n");
}
public static void main(String args[]) {
new TestStaticFinal().test();
}
}
執行結果如下:
-------------值處理前----------
strStaticFinalVar=aaa
strStaticVar=null
strFinalVar=null
intStaticFinalVar=0
integerStaticFinalVar=8
alStaticFinalVar=[]
-------------值處理後----------
strStaticFinalVar=aaa
strStaticVar=哈哈哈哈
strFinalVar=null
intStaticFinalVar=0
integerStaticFinalVar=8
alStaticFinalVar=[aaa, bbb]Process finished with exit code 0
看了上面這個例子,就清楚很多了,但必須明白:通過static final修飾的容器型別變數中所“裝”的物件是可改變的。這是和一般基本型別和類型別變數差別很大的地方。
1.5 java static塊和static方法的使用區別
如果有些程式碼必須在專案啟動的時候就執行,就需要使用靜態程式碼塊,這種程式碼是主動執行的;需要在專案啟動的時候就初始化但是不執行,在不建立物件的情況下,可以供其他程式呼叫,而在呼叫的時候才執行,這需要使用靜態方法,這種程式碼是被動執行的。 靜態方法在類載入的時候 就已經載入 可以用類名直接呼叫。
靜態程式碼塊和靜態方法的區別是:
• 靜態程式碼塊是自動執行的;
• 靜態方法是被呼叫的時候才執行的.
• 靜態方法:如果我們在程式編寫的時候需要一個不例項化物件就可以呼叫的方法,我們就可以使用靜態方法,具體實現是在方法前面加上static,如下:
public static void method(){}
在使用靜態方法的時候需要注意一下幾個方面:
在靜態方法裡只能直接呼叫同類中其他的靜態成員(包括變數和方法),而不能直接訪問類中的非靜態成員。這是因為,對於非靜態的方法和變數,需要先建立類的例項物件後才可使用,而靜態方法在使用前不用建立任何物件。(備註:靜態變數是屬於整個類的變數而不是屬於某個物件的)
靜態方法不能以任何方式引用this和super關鍵字,因為靜態方法在使用前不用建立任何例項物件,當靜態方法呼叫時,this所引用的物件根本沒有產生。
靜態程式塊:當一個類需要在被載入時就執行一段程式,這樣可以使用靜態程式塊。
1.6總結
有時你希望定義一個類成員,使它的使用完全獨立於該類的任何物件。通常情況下,類成員必須通過它的類的物件訪問,但是可以建立這樣一個成員,它能夠被它自己使用,而不必引用特定的例項。在成員的宣告前面加上關鍵字static(靜態的)就能建立這樣的成員。如果一個成員被宣告為static,它就能夠在它的類的任何物件建立之前被訪問,而不必引用任何物件。你可以將方法和變數都宣告為static。static 成員的最常見的例子是main( ) 。因為在程式開始執行時必須呼叫main() ,所以它被宣告為static。
宣告為static的變數實質上就是全域性變數。當宣告一個物件時,並不產生static變數的拷貝,而是該類所有的例項變數共用同一個static變數。宣告為static的方法有以下幾條限制:
• 它們僅能呼叫其他的static方法。
• 它們只能訪問static資料。
• 它們不能以任何方式引用this或super(關鍵字super 與繼承有關,在下一章中描述)。
如果你需要通過計算來初始化你的static變數,你可以宣告一個static塊,Static 塊僅在該類被載入時執行一次。