Java零基礎(chǔ)快速入門(mén)|static關(guān)鍵字

本篇文章主要內(nèi)容
static概述
靜態(tài)變量
靜態(tài)代碼塊
靜態(tài)方法
難點(diǎn)疑惑
static?概述
static 是java 語(yǔ)言中的關(guān)鍵字,表示“靜態(tài)的”,它可以用來(lái)修飾變量、方法、代碼塊等, 修飾的變量叫做靜態(tài)變量,修飾的方法叫做靜態(tài)方法,修飾的代碼塊叫做靜態(tài)代碼塊。在 java 語(yǔ)言中凡是用static??修飾的都是類(lèi)相關(guān)的,不需要?jiǎng)?chuàng)建對(duì)象,直接通過(guò)“類(lèi)名”即可訪問(wèn),即使使用“引用”去訪問(wèn),在運(yùn)行的時(shí)候也和堆內(nèi)存當(dāng)中的對(duì)象無(wú)關(guān)。
本小節(jié)要求大家主要掌握:
什么時(shí)候?qū)⒆兞慷x為靜態(tài)變量?
什么時(shí)候把方法定義為靜態(tài)方法?
靜態(tài)代碼塊什么時(shí)候使用?
類(lèi)體中的代碼有執(zhí)行順序要求嗎?
空引用訪問(wèn)靜態(tài)變量和靜態(tài)方法會(huì)出現(xiàn)空指針異常嗎?
?
靜態(tài)變量
Java?中的變量包括:局部變量和成員變量,在方法體中聲明的變量為局部變量,有效范圍很小,只能在方法體中訪問(wèn),方法結(jié)束之后局部變量?jī)?nèi)存就釋放了,在內(nèi)存方面局部變量存儲(chǔ) 在棧當(dāng)中。在類(lèi)體中定義的變量為成員變量,而成員變量又包括實(shí)例變量和靜態(tài)變量,當(dāng)成員 變量聲明時(shí)使用了 static??關(guān)鍵字,那么這種變量稱(chēng)為靜態(tài)變量,沒(méi)有使用 static?關(guān)鍵字稱(chēng)為實(shí)例變量,實(shí)例變量是對(duì)象級(jí)別的,每個(gè)對(duì)象的實(shí)例變量值可能不同,所以實(shí)例變量必須先創(chuàng)建 對(duì)象,通過(guò)“引用”去訪問(wèn),而靜態(tài)變量訪問(wèn)時(shí)不需要?jiǎng)?chuàng)建對(duì)象,直接通過(guò)“類(lèi)名”訪問(wèn)。實(shí) 例變量存儲(chǔ)在堆內(nèi)存當(dāng)中,靜態(tài)變量存儲(chǔ)在方法區(qū)當(dāng)中。實(shí)例變量在構(gòu)造方法執(zhí)行過(guò)程中初始化,靜態(tài)變量在類(lèi)加載時(shí)初始化。那么變量在什么情況下會(huì)聲明為靜態(tài)變量呢?請(qǐng)看以下代碼, 定義一個(gè)“男人”類(lèi):


運(yùn)行結(jié)果如下圖所示:

我們來(lái)看一下以上程序的內(nèi)存結(jié)構(gòu)圖:

“男人類(lèi)”創(chuàng)建的所有“男人對(duì)象”,每一個(gè)“男人對(duì)象”的身份證號(hào)都不一樣,該屬性 應(yīng)該每個(gè)對(duì)象持有一份,所以應(yīng)該定義為實(shí)例變量,而每一個(gè)“男人對(duì)象”的性別都是“男”, 不會(huì)隨著對(duì)象的改變而變化,性別值永遠(yuǎn)都是“男”,這種情況下,性別這個(gè)變量還需要定義 為實(shí)例變量嗎,有必要讓每一個(gè)“男人對(duì)象”持有一份嗎,這樣豈不是浪費(fèi)了大量的堆內(nèi)存空 間,所以這個(gè)時(shí)候建議將“性別=男”屬性定義為類(lèi)級(jí)別的屬性,聲明為靜態(tài)變量,上升為“整 個(gè)族”的數(shù)據(jù),這樣的變量不需要?jiǎng)?chuàng)建對(duì)象直接使用“類(lèi)名”即可訪問(wèn)。請(qǐng)看代碼:


運(yùn)行結(jié)果如下圖所示:

我們來(lái)看一下以上程序的內(nèi)存結(jié)構(gòu)圖:

通過(guò)以上內(nèi)容的學(xué)習(xí)我們得知,當(dāng)一個(gè)類(lèi)的所有對(duì)象的某個(gè)“屬性值”不會(huì)隨著對(duì)象的改 變而變化的時(shí)候,建議將該屬性定義為靜態(tài)屬性(或者說(shuō)把這個(gè)變量定義為靜態(tài)變量),靜態(tài) 變量在類(lèi)加載的時(shí)候初始化,存儲(chǔ)在方法區(qū)當(dāng)中,不需要?jiǎng)?chuàng)建對(duì)象,直接通過(guò)“類(lèi)名”來(lái)訪問(wèn)。如果靜態(tài)變量使用“引用”來(lái)訪問(wèn),可以嗎,如果可以的話,這個(gè)訪問(wèn)和具體的對(duì)象有關(guān)系嗎? 來(lái)看以下代碼:

運(yùn)行結(jié)果如下圖所示:

通過(guò)以上代碼以及運(yùn)行結(jié)果可以看出,靜態(tài)變量也可以使用“引用”去訪問(wèn),但實(shí)際上在 執(zhí)行過(guò)程中,“引用”所指向的對(duì)象并沒(méi)有參與,如果是空引用訪問(wèn)實(shí)例變量,程序一定會(huì)發(fā) 生空指針異常,但是以上的程序編譯通過(guò)了,并且運(yùn)行的時(shí)候也沒(méi)有出現(xiàn)任何異常,這說(shuō)明雖然表面看起來(lái)是采用“引用”去訪問(wèn),但實(shí)際上在運(yùn)行的時(shí)候還是直接通過(guò)“類(lèi)”去訪問(wèn)的。靜態(tài)方法是這樣嗎?請(qǐng)看以下代碼:


運(yùn)行結(jié)果如下圖所示:

通過(guò)以上代碼測(cè)試得知,靜態(tài)變量和靜態(tài)方法比較正式的方式是直接采用“類(lèi)名”訪問(wèn), 但實(shí)際上使用“引用”也可以訪問(wèn),并且空引用訪問(wèn)靜態(tài)變量和靜態(tài)方法并不會(huì)出現(xiàn)空指針異常。實(shí)際上,在開(kāi)發(fā)中并不建議使用“引用”去訪問(wèn)靜態(tài)相關(guān)的成員,因?yàn)檫@樣會(huì)讓程序員困惑,因?yàn)椴捎谩耙谩狈绞皆L問(wèn)的時(shí)候,程序員會(huì)認(rèn)為你訪問(wèn)的是實(shí)例相關(guān)的成員。
總之,所有實(shí)例相關(guān)的,包括實(shí)例變量和實(shí)例方法,必須先創(chuàng)建對(duì)象,然后通過(guò)“引用” 的方式去訪問(wèn),如果空引用訪問(wèn)實(shí)例相關(guān)的成員,必然會(huì)出現(xiàn)空指針異常。所有靜態(tài)相關(guān)的, 包括靜態(tài)變量和靜態(tài)方法,直接使用“類(lèi)名”去訪問(wèn)。雖然靜態(tài)相關(guān)的成員也能使用“引用” 去訪問(wèn),但這種方式并不被主張。
?
靜態(tài)代碼塊
靜態(tài)代碼塊的語(yǔ)法格式是這樣的:

靜態(tài)代碼塊在類(lèi)加載時(shí)執(zhí)行,并且只執(zhí)行一次。開(kāi)發(fā)中使用不多,但離了它有的時(shí)候還真是沒(méi)法寫(xiě)代碼。靜態(tài)代碼塊實(shí)際上是 java 語(yǔ)言為程序員準(zhǔn)備的一個(gè)特殊的時(shí)刻,這個(gè)時(shí)刻就是類(lèi)加載時(shí)刻,如果你想在類(lèi)加載的時(shí)候執(zhí)行一段代碼,那么這段代碼就有的放矢了。例如我們要在類(lèi)加載的時(shí)候解析某個(gè)文件,并且要求該文件只解析一次,那么此時(shí)就可以把解析該文件的代碼寫(xiě)到靜態(tài)代碼塊當(dāng)中了。我們來(lái)測(cè)試一下靜態(tài)代碼塊:

運(yùn)行結(jié)果如下圖所示:

通過(guò)以上的測(cè)試可以得知一個(gè)類(lèi)當(dāng)中可以編寫(xiě)多個(gè)靜態(tài)代碼塊(盡管大部分情況下只編寫(xiě)一個(gè)),并且靜態(tài)代碼塊遵循自上而下的順序依次執(zhí)行,所以有的時(shí)候放在類(lèi)體當(dāng)中的代碼是有執(zhí)行順序的(大部分情況下類(lèi)體當(dāng)中的代碼沒(méi)有順序要求,方法體當(dāng)中的代碼是有順序要求的,方法體當(dāng)中的代碼必須遵守自上而下的順序依次逐行執(zhí)行),另外靜態(tài)代碼塊當(dāng)中的代碼在 main 方法執(zhí)行之前執(zhí)行,這是因?yàn)殪o態(tài)代碼塊在類(lèi)加載時(shí)執(zhí)行,并且只執(zhí)行一次。再來(lái)看一下以下代碼:

編譯結(jié)果如下圖所示:

為什么編譯報(bào)錯(cuò)呢?那是因?yàn)?i??變量是實(shí)例變量,實(shí)例變量必須先創(chuàng)建對(duì)象才能訪問(wèn),靜態(tài)代碼塊在類(lèi)加載時(shí)執(zhí)行,這個(gè)時(shí)候?qū)ο筮€沒(méi)有創(chuàng)建呢,所以 i 變量在這里是不能這樣訪問(wèn)的。可以考慮在i 變量前添加static,這樣 i 變量就變成靜態(tài)變量了,靜態(tài)變量訪問(wèn)時(shí)不需要?jiǎng)?chuàng)建對(duì)象,直接通過(guò)“類(lèi)”即可訪問(wèn),例如以下代碼:

運(yùn)行結(jié)果如下圖所示:

代碼修改為這樣呢?

編譯報(bào)錯(cuò)了,請(qǐng)看下圖:

通過(guò)測(cè)試,可以看到有的時(shí)候類(lèi)體當(dāng)中的代碼也是有順序要求的(類(lèi)體當(dāng)中定義兩個(gè)獨(dú)立的方法,這兩個(gè)方法是沒(méi)有先后順序要求的),靜態(tài)代碼塊在類(lèi)加載時(shí)執(zhí)行,靜態(tài)變量在類(lèi)加載時(shí)初始化,它們?cè)谕粫r(shí)間發(fā)生,所以必然會(huì)有順序要求,如果在靜態(tài)代碼塊中要訪問(wèn) i?變量,那么i?變量必須放到靜態(tài)代碼塊之前。
?
靜態(tài)方法
方法在什么情況下會(huì)聲明為靜態(tài)的呢?方法實(shí)際上描述的是行為動(dòng)作,我認(rèn)為當(dāng)某個(gè)動(dòng)作在觸發(fā)的時(shí)候需要對(duì)象的參與,這個(gè)方法應(yīng)該定義為實(shí)例方法,例如:每個(gè)玩籃球的人都會(huì)打籃球,但是你打籃球和科比打籃球最終的效果是不一樣的,顯然打籃球這個(gè)動(dòng)作存在對(duì)象差異化,該方法應(yīng)該定義為實(shí)例方法。再如:每個(gè)高中生都有考試的行為,但是你考試和學(xué)霸考試最終的結(jié)果是不一樣的,一個(gè)上了“家里蹲大學(xué)”,一個(gè)上了“清華大學(xué)”,顯然這個(gè)動(dòng)作也是需要對(duì)象參與才能完成的,所以考試這個(gè)方法應(yīng)該定義為實(shí)例方法。
以上描述是從設(shè)計(jì)思想角度出發(fā)來(lái)進(jìn)行選擇,其實(shí)也可以從代碼的角度來(lái)進(jìn)行判斷,當(dāng)方 法體中需要直接訪問(wèn)當(dāng)前對(duì)象的實(shí)例變量或者實(shí)例方法的時(shí)候,該方法必須定義為實(shí)例方法, 因?yàn)橹挥袑?shí)例方法中才有this,靜態(tài)方法中不存在this。請(qǐng)看代碼:

運(yùn)行結(jié)果如下圖所示:

在以上的代碼中,不同的客戶購(gòu)物,最終的效果都不同,另外在 shopping()方法中訪問(wèn)了當(dāng)前對(duì)象的實(shí)例變量 name,以及調(diào)用了實(shí)例方法 pay(),所以 shopping()方法不能定義為靜態(tài)方法,必須聲明為實(shí)例方法。
另外,在實(shí)際的開(kāi)發(fā)中,“工具類(lèi)”當(dāng)中的方法一般定義為靜態(tài)方法,因?yàn)楣ぞ哳?lèi)就是為了方便大家的使用,將方法定義為靜態(tài)方法,比較方便調(diào)用,不需要?jiǎng)?chuàng)建對(duì)象,直接使用類(lèi)名就可以訪問(wèn)。請(qǐng)看以下工具類(lèi),為了簡(jiǎn)化“System.out.println();”代碼而編寫(xiě)的工具類(lèi):


運(yùn)行結(jié)果如下圖所示:

?難點(diǎn)解惑
在本章節(jié)中,對(duì)于static來(lái)說(shuō),代碼的執(zhí)行順序是一個(gè)需要大家注意的地方,一般來(lái)說(shuō)方法體當(dāng)中的代碼是有執(zhí)行順序要求的,之前所接觸的程序中,類(lèi)體當(dāng)中的程序沒(méi)有順序要求, 但自從認(rèn)識(shí)了static之后,我們發(fā)現(xiàn)類(lèi)體當(dāng)中的代碼也有執(zhí)行順序的要求了,尤其是static修飾的靜態(tài)變量,以及static 修飾的靜態(tài)代碼塊他們是有先后順序的,這里需要囑咐大家的是static修飾的靜態(tài)變量以及靜態(tài)代碼塊都是在類(lèi)加載時(shí)執(zhí)行,并且遵循自上而下的順序依次逐行執(zhí)行。
小結(jié)
通過(guò)本章節(jié)內(nèi)容的學(xué)習(xí),要求大家掌握Java中兩個(gè)關(guān)鍵字的用法,一個(gè)是this,一個(gè)是static。其中this?要理解的是this?是什么,內(nèi)存中存儲(chǔ)在哪里,要掌握?this?在實(shí)例方法和構(gòu)造方法中的用法。對(duì)于?static??來(lái)說(shuō),要理解?static?代表什么含義,要掌握靜態(tài)變量、靜態(tài)代碼塊、靜態(tài)方法的使用。
最后附Java零基礎(chǔ)視頻教程給大家,配合學(xué)習(xí)效果更佳?。?/strong>
