學習本文你到底要學到什麼:
1、 static在java中到底代表什麼,為何要用它?
2、 static在java中怎麼用?
3、 static 有那些特點和使用的“局限”?
static――靜态――“指定位置“
首先,我們來看看java的記憶體:java把記憶體分為棧記憶體和堆記憶體,棧記憶體用來存放一些基本類型的變量和數組及對象的引用變量,而堆記憶體主要是來放置對象的。
用 static的修飾的變量和方法,實際上是指定了這些變量和方法在記憶體中的“固定位置”-static storage。既然要有“固定位置”那麼他們的 “大小”似乎就是固定的了,有了固定位置和固定大小的特征了,在棧中或堆中開辟空間那就是非常的友善了。如果靜态的變量或方法在不出其作用域的情況下,其 引用句柄是不會發生改變的。
我們常看到:static變量有點類似于c中的全局變量的概念;靜态表示的是記憶體的共享,就是它的每一個 執行個體都指向同一個記憶體位址。把static拿來,就是告訴jvm它是靜态的,它的引用(含間接引用)都是指向同一個位置,在那個地方,你把它改了,它就不 會變成原樣,你把它清理了,它就不會回來了。我們常可看到類似以下的例子來說明這個問題:
class student{
static int numberofstudents=0;
student()
{
numberofstudents++;
}
} 每一次建立一個新的student執行個體時,成員numberofstudents都會不斷的遞增,并且所有的student執行個體都通路同一個 numberofstudents變量,實際上int numberofstudents變量在記憶體中隻存儲在一個位置上。為了來更好的說明這個問題,我 特意學習張老師(張孝祥)使用一個形象的圖解:
建立兩個student執行個體,stu1=new student(); stu2=new student();
多個執行個體共享一個變量似乎不足以讓我們對static那麼的熱情,實際上java引入static卻有另外的含義:
(1)、引用static的方法和變量,不需要和執行個體捆綁在一起,這可以提高代碼的編寫的效率,這樣的例子我們随處可見;
(2)、 java的主類中main()方法本身就是一個static的,是以main方法的執行就是在沒有産生新的執行個體的情況;對于靜态的東西,jvm在加載類 時,就在內存中開辟了這些靜态的空間,是以雖沒有靜态的main()方法但是程式還是執行了,不過抛出來了無main()方法的異常。這也不知算不算是 java的一個漏洞;
(3)、如果需要建立一個脫離于執行個體的變量或方法(隻與整個類有關),那麼用static作修飾是再好不過了,如我們經常看到要統計執行個體實作的個數(通常的例子就是計數)。
(4)、使用一種靜态的方法的程式設計通常叫做防禦(defensive)程式設計,它可以在api供應商突然中斷支援的情況下保護代碼
使用static時,要記着我闡述的static代表什麼。
static 使用非常的簡單,如果要修飾一個靜态塊隻需:staic {……..}即可(常用靜态塊來初始化一些變量); 靜态方法就參照main()的形式:通路标 識 static returntype method(…) {};靜态變量就是:static type fields;
在使用靜态的方法時,可以直接用類名來引用,不需要建立執行個體(當然建立執行個體也是可以的),例如,system.out,string.valueof()等等。
從上面的分析可知,static的東西在類加載時,就配置設定了記憶體空間,即編譯時就為這些成員變量的執行個體配置設定了空間。
那 麼在static塊内和方法體内,我們能給它放一個在記憶體中還沒有着落的變量?顯然與我們先前所說的相左。static的東西,人家是在 static storage中有“指定位置“的,如果我們茫然的在static的作用域中放置一個普通的變量,那麼編譯時jvm就毫不客氣的給你個異 常:
non-static variable a cannot be referenced from a static context或 non- static method test() cannot be referenced from a static context(注:test() 是我試驗時的一個例子 ),除非我在static中現場開辟空間,用new來要記憶體。
對于static的初始化問題,我們還是值得讨論的。現看下面的例子:
//staticinit show the static decorated initialization
package com.blogchina.qb2049;
public class staticinit
{
static int i;
int a;
public staticinit()
{
a=6;
system.out.println("a 的初始化"+a);
}
public static void main(string[] args)
{
new staticinit();
}
static
i=5;
system.out.println("i 的初始化"+i);
}運作結果如下:i 的初始化5
a 的初始化6 靜态塊的初始化要早于非靜态的,原因就是在于這些東西是在類裝載時就開始初始化了。
說 起static的“局限“,總結起來就是:在static的方法中僅能夠調用其他的static方法和static變量;在static方法中不能以任何 方式引用this或super;static變量在定義時必須進行初始化,并且初始化的時間早于非靜态。還有一個局限我需要具體的說明一下,static 的變量的初始化僅能一次,如下例:
//static.java, initialize only one
class t1
{
static int t=1;
t1(int b)
{
t=b;
}
}
public class static
{
t1 t1=new t1(2);
t1 t2=new t1(3);
t1 t3=new t1(4);
public static()
{
system.out.println("t1: "+t1.t);
system.out.println("t2: "+t2.t);
system.out.println("t3: "+t3.t);
}
public static void main(string args[])
{
new static();
運作結果為: t1: 4
t2: 4
t3: 4
該static變量隻是接受了最後一次的初始化.實際這還是我們先前提到的多個執行個體共享一個靜态的變量的問題。
總之,static就是給我們一個這樣的忠告:static的東西在編譯時,就已向記憶體要到了存取空間了。