1检号、 static在java中到底代表什么熔号,為何要用它赴肚?
static――靜態(tài)――“指定位置“
首先素跺,我們來看看java的內(nèi)存:
java把內(nèi)存分為棧內(nèi)存和堆內(nèi)存二蓝,棧內(nèi)存用來存放一些基本類型的變量和數(shù)組及對(duì)象的引用變量,而堆內(nèi)存主要是來放置對(duì)象的指厌。
用static的修飾的變量和方法刊愚,實(shí)際上是指定了這些變量和方法在內(nèi)存中的“固定位置”-static storage。既然要有“固定位置”那么他們的“大小”似乎就是固定的了踩验,有了固定位置和固定大小的特征了鸥诽,在棧中或堆中開辟空間那就是非常的方便了。如果靜態(tài)的變量或方法在不出其作用域的情況下箕憾,其引用句柄是不會(huì)發(fā)生改變的牡借。
我們常看到:static變量有點(diǎn)類似于C中的全局變量的概念厕九;靜態(tài)表示的是內(nèi)存的共享蓖捶,就是它的每一個(gè)實(shí)例都指向同一個(gè)內(nèi)存地址。 把static拿來扁远,就是告訴JVM它是靜態(tài)的俊鱼,它的引用(含間接引用)都是指向同一個(gè)位置,在那個(gè)地方畅买,你把它改了并闲,它就不會(huì)變成原樣,你把它清理了谷羞,它就不會(huì)回來了帝火。我們常可看到類似以下的例子來說明這個(gè)問題:
class Student {
static int numberOfStudents = 0;
Student() {
numberOfStudents++;
}
}
每一次創(chuàng)建一個(gè)新的Student實(shí)例時(shí),成員numberOfStudents都會(huì)不斷的遞增,并且所有的Student實(shí)例都訪問同一個(gè)numberOfStudents變量,實(shí)際上int numberOfStudents變量在內(nèi)存中只存儲(chǔ)在一個(gè)位置上湃缎。
多個(gè)實(shí)例共享一個(gè)變量似乎不足以讓我們對(duì)static那么的熱情犀填,實(shí)際上java引入static卻有另外的含義:
(1)、引用static的方法和變量嗓违,不需要和實(shí)例捆綁在一起,這可以提高代碼的編寫的效率九巡,這樣的例子我們隨處可見;
(2)蹂季、java的主類中main()方法本身就是一個(gè)static的冕广,所以main方法的執(zhí)行就是在沒有產(chǎn)生新的實(shí)例的情況;對(duì)于靜態(tài)的東西偿洁,JVM在加載類時(shí)撒汉,就在內(nèi)存中開辟了這些靜態(tài)的空間,所以雖沒有靜態(tài)的main()方法但是程序還是執(zhí)行了涕滋,不過拋出來了無main()方法的異常睬辐。這也不知算不算是java的一個(gè)漏洞;
(3)、如果需要?jiǎng)?chuàng)建一個(gè)脫離于實(shí)例的變量或方法(只與整個(gè)類有關(guān))溉委,那么用static作修飾是再好不過了鹃唯,如我們經(jīng)常看到要統(tǒng)計(jì)實(shí)例實(shí)現(xiàn)的個(gè)數(shù)(通常的例子就是計(jì)數(shù))瓣喊。
(4)坡慌、使用一種靜態(tài)的方法的編程通常叫做防御(defensive)編程,它可以在API供應(yīng)商突然中斷支持的情況下保護(hù)代碼
靜態(tài)塊的初始化要早于非靜態(tài)的,原因就是在于這些東西是在類裝載時(shí)就開始初始化了藻三。
說起static的“局限“洪橘,總結(jié)起來就是:
- 在static的方法中僅能夠調(diào)用其他的static方法和static變量;
- 在static方法中不能以任何方式引用this或super棵帽;
- static變量在定義時(shí)必須進(jìn)行初始化熄求,并且初始化的時(shí)間早于非靜態(tài)。
- 還有一個(gè)局限我需要具體的說明一下逗概,static的變量的初始化僅能一次弟晚,如下例:
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();
}
}
class T1 {
static int t = 1;
T1(int b) {
t = b;
}
}
運(yùn)行結(jié)果:
t1: 4
t2: 4
t3: 4
該static變量只是接受了最后一次的初始化.實(shí)際這還是我們先前提到的多個(gè)實(shí)例共享一個(gè)靜態(tài)的變量的問題。
總之逾苫,static就是給我們一個(gè)這樣的忠告:static的東西在編譯時(shí)卿城,就已向內(nèi)存要到了存取空間了。
2铅搓、 static在java中怎么用瑟押?
使用static時(shí),要記著我闡述的static代表什么星掰。
static使用非常的簡單多望,
- 如果要修飾一個(gè)靜態(tài)塊只需:staic {……..}即可(常用靜態(tài)塊來初始化一些變量);
- 靜態(tài)方法就參照main()的形式:
- 訪問標(biāo)識(shí) static returnType method(…) {};
- 靜態(tài)變量就是:static type fields氢烘;
在使用靜態(tài)的方法時(shí)怀偷,可以直接用類名來引用,不需要?jiǎng)?chuàng)建實(shí)例(當(dāng)然創(chuàng)建實(shí)例也是可以的)播玖,例如枢纠,System.out,String.valueOf()等等。
3黎棠、 static 有哪些特點(diǎn)和使用的“局限”?
從上面的分析可知镰绎,static的東西在類加載時(shí)脓斩,就分配了內(nèi)存空間,即編譯時(shí)就為這些成員變量的實(shí)例分配了空間畴栖。
那么在static塊內(nèi)和方法體內(nèi)随静,我們能給它放一個(gè)在內(nèi)存中還沒有著落的變量?顯然與我們先前所說的相左。static的東西燎猛,人家是在static storage中有“指定位置“的恋捆,如果我們茫然的在static的作用域中放置一個(gè)普通的變量,那么編譯時(shí)JVM就毫不客氣的給你個(gè)異常:
non-static variable a cannot be referenced from a static context或non-static method Test() cannot be referenced from a static context(注:Test()是我試驗(yàn)時(shí)的一個(gè)例子)重绷,除非我在static中現(xiàn)場開辟空間沸停,用new來要內(nèi)存。
對(duì)于static的初始化問題昭卓,我們還是值得討論的》呒兀現(xiàn)看下面的例子
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);
}
}
運(yùn)行結(jié)果如下:
i 的初始化5
a 的初始化6