1.static
靜態(tài)的 全局的,一旦被修飾,說(shuō)明被修飾的東西在一定范圍內(nèi)是共享的离福,誰(shuí)都可以訪問(wèn),這時(shí)候需要注意并發(fā)讀寫(xiě)的問(wèn)題炼蛤。
1.1修飾的對(duì)象
只能修飾類(lèi)變量妖爷,方法和方法塊。
當(dāng) static 修飾類(lèi)變量時(shí)理朋,如果該變量是 public 的話(huà)絮识,表示該變量任何類(lèi)都可以直接訪問(wèn),而且無(wú)需初始化類(lèi)嗽上,直接使用 類(lèi)名.static 變量 這種形式訪問(wèn)即可次舌。
這時(shí)候我們非常需要注意的一點(diǎn)就是線(xiàn)程安全的問(wèn)題了,因?yàn)楫?dāng)多個(gè)線(xiàn)程同時(shí)對(duì)共享變量進(jìn)行讀寫(xiě)時(shí)兽愤,很有可能會(huì)出現(xiàn)并發(fā)問(wèn)題彼念,如我們定義了:public static List<String> list = new ArrayList();這樣的共享變量。這個(gè) list 如果同時(shí)被多個(gè)線(xiàn)程訪問(wèn)的話(huà)浅萧,就有線(xiàn)程安全的問(wèn)題逐沙,這時(shí)候一般有兩個(gè)解決辦法:
- 把線(xiàn)程不安全的 ArrayList 換成 線(xiàn)程安全的 CopyOnWriteArrayList;
- 每次訪問(wèn)時(shí)洼畅,手動(dòng)加鎖吩案。
所以在使用 static 修飾類(lèi)變量時(shí),如何保證線(xiàn)程安全是我們常常需要考慮的帝簇。
當(dāng) static 修飾方法時(shí)徘郭,代表該方法和當(dāng)前類(lèi)是無(wú)關(guān)的,任意類(lèi)都可以直接訪問(wèn)(如果權(quán)限是 public 的話(huà))丧肴。
有一點(diǎn)需要注意的是残揉,該方法內(nèi)部只能調(diào)用同樣被 static 修飾的方法,不能調(diào)用普通方法闪湾,我們常用的 util 類(lèi)里面的各種方法冲甘,我們比較喜歡用 static 修飾方法,好處就是調(diào)用特別方便途样。
static 方法內(nèi)部的變量在執(zhí)行時(shí)是沒(méi)有線(xiàn)程安全問(wèn)題的江醇。方法執(zhí)行時(shí),數(shù)據(jù)運(yùn)行在棧里面何暇,棧的數(shù)據(jù)每個(gè)線(xiàn)程都是隔離開(kāi)的陶夜,所以不會(huì)有線(xiàn)程安全的問(wèn)題,所以 util 類(lèi)的各個(gè) static 方法裆站,我們是可以放心使用的条辟。
當(dāng) static 修飾方法塊時(shí)黔夭,我們叫做靜態(tài)塊,靜態(tài)塊常常用于在類(lèi)啟動(dòng)之前羽嫡,初始化一些值本姥,比如:
public static List<String> list = new ArrayList<>();
//進(jìn)行初始化操作
static {
list.add("1");
list.add("2");
list.add("3");
}
1.2 初始化時(shí)機(jī)
對(duì)于被 static 修飾的類(lèi)變量、方法塊和靜態(tài)方法的初始化時(shí)機(jī)杭棵,我們寫(xiě)了一個(gè)測(cè)試 demo婚惫,如下圖:
我們運(yùn)行子類(lèi)中的new StaticClass();
輸出如下:
父類(lèi)靜態(tài)變量初始化
父類(lèi)靜態(tài)塊初始化
子類(lèi)靜態(tài)變量初始化
子類(lèi)靜態(tài)塊初始化
main方法調(diào)用
父類(lèi)構(gòu)造器初始化
子類(lèi)構(gòu)造器初始化
從結(jié)果中,我們可以看出兩點(diǎn):
- 父類(lèi)的靜態(tài)變量和靜態(tài)塊比子類(lèi)優(yōu)先初始化魂爪;
- 靜態(tài)變量和靜態(tài)塊比類(lèi)構(gòu)造器優(yōu)先初始化先舷。
我們運(yùn)行子類(lèi)中的StaticClass.testStatic();
輸出如下:
父類(lèi)靜態(tài)變量初始化
父類(lèi)靜態(tài)塊初始化
子類(lèi)靜態(tài)變量初始化
子類(lèi)靜態(tài)塊初始化
main方法調(diào)用
子類(lèi)靜態(tài)方法被調(diào)用
從結(jié)果中,我們可以看出:
被 static 修飾的方法滓侍,在類(lèi)初始化的時(shí)候并不會(huì)初始化蒋川,只有當(dāng)自己被調(diào)用時(shí),才會(huì)被執(zhí)行撩笆。
2. final
final 的意思是不變的捺球,一般來(lái)說(shuō)用于以下三種場(chǎng)景:
被 final 修飾的類(lèi),表明該類(lèi)是無(wú)法繼承的浇衬;
被 final 修飾的方法懒构,表明該方法是無(wú)法覆寫(xiě)的;
被 final 修飾的變量耘擂,說(shuō)明該變量在聲明的時(shí)候,就必須初始化完成絮姆,而且以后也不能修改其內(nèi)存地址醉冤。
第三點(diǎn)注意下,我們說(shuō)的是無(wú)法修改其內(nèi)存地址篙悯,并沒(méi)有說(shuō)無(wú)法修改其值蚁阳。因?yàn)閷?duì)于 List、Map 這些集合類(lèi)來(lái)說(shuō)鸽照,被 final 修飾后螺捐,是可以修改其內(nèi)部值的,但卻無(wú)法修改其初始化時(shí)的內(nèi)存地址矮燎。
例子我們就不舉了定血,String 的不變性就是一個(gè)很好的例子。
3. try诞外、catch澜沟、finally
這三個(gè)關(guān)鍵字常用于我們捕捉異常的一整套流程,try 用來(lái)確定代碼執(zhí)行的范圍峡谊,catch 捕捉可能會(huì)發(fā)生的異常茫虽,finally 用來(lái)執(zhí)行一定要執(zhí)行的代碼塊刊苍,除了這些,我們還需要清楚濒析,每個(gè)地方如果發(fā)生異常會(huì)怎么辦.:
public void testCatchFinally() {
try {
System.out.println("try is run");
if (true) {
throw new RuntimeException("try exception");
}
} catch (Exception e) {
System.out.println("catch is run");
if (true) {
throw new RuntimeException("catch exception");
}
} finally {
System.out.println("finally is run");
}
}
輸出:
try is run
catch is run
finally is run
Exception in thread "main" java.lang.RuntimeException: catch exception
at
這個(gè)代碼演示了在 try正什、catch 中都遇到了異常,代碼的執(zhí)行順序?yàn)椋簍ry -> catch -> finally
可以看到兩點(diǎn):
- finally 先執(zhí)行后号杏,再拋出 catch 的異常埠忘;
- 最終捕獲的異常是 catch 的異常,try 拋出來(lái)的異常已經(jīng)被 catch 吃掉了馒索,所以當(dāng)我們遇見(jiàn) catch 也有可能會(huì)拋出異常時(shí)莹妒,我們可以先打印出 try 的異常,這樣 try 的異常在日志中就會(huì)有所體現(xiàn)绰上。