前言
本文是深入Java基礎(chǔ)系列的第四篇琼了,關(guān)于文集介紹可通過(guò)<<Java基礎(chǔ)回爐暨系列開(kāi)篇>>進(jìn)行了解。
這篇文章將整理Java中常見(jiàn)的關(guān)鍵字莹捡,通過(guò)將形似和易混淆的Java關(guān)鍵字進(jìn)行比較和區(qū)分端考,旨在讓大家底掌握常見(jiàn)Java關(guān)鍵字的用法和使用時(shí)的注意事項(xiàng)。
1. final均蜜、finally、finalize
final芒率、finally囤耳、finalize有什么不同? 這個(gè)問(wèn)題在面試的時(shí)候經(jīng)常被問(wèn)到偶芍,因?yàn)樗鼈內(nèi)齻€(gè)長(zhǎng)得有點(diǎn)像充择,但是用途卻完全不同。那你知道它們的區(qū)別嗎匪蟀?
1.1 final
(1)final
可以用來(lái)修飾變量椎麦、方法、類材彪,分別有不同的意義:
-
final
關(guān)鍵字修飾一個(gè)基本類型的變量時(shí)观挎,在定義的時(shí)候就需要進(jìn)行初始化,該變量不能重新賦值段化,第一次的值即為最終的嘁捷。 -
fianl
關(guān)鍵字修飾一個(gè)引用類型變量時(shí),該變量不能重新指向新的對(duì)象显熏。(final
只能約束這個(gè)引用不可以被賦值雄嚣,但是該引用指向的對(duì)象的行為不被final影響,這與immutable
不同)
// final只能約束strList這個(gè)引用不可以被賦值喘蟆,
//但是strList對(duì)象的行為并不受final的影響
final List<String> strList = new ArrayList<>();
strList.add("Hello");
strList.add("world");
//List.of方法創(chuàng)建的本身就是不可變List缓升,最后一句add是會(huì)在運(yùn)行時(shí)拋出異常的
List<String> unmodifiableStrList = List.of("hello", "world");
unmodifiableStrList.add("again");
-
final
關(guān)鍵字修飾一個(gè)方法的時(shí)候,該方法不能被重寫(xiě)蕴轨。(主要用于將方法鎖定仔沿,防止子類修改。) -
final
關(guān)鍵字修飾一個(gè)類的時(shí)候尺棋,該類不能被繼承封锉。(當(dāng)需要一個(gè)完全封裝、無(wú)法改變的類時(shí)膘螟,可以使用final修飾增強(qiáng)安全性成福。)
(2)為什么局部?jī)?nèi)部類(包括匿名內(nèi)部類)訪問(wèn)了局部函數(shù)的形參,該變量需要使用final修飾荆残?
這個(gè)問(wèn)題在 深入類和對(duì)象——深入Java基礎(chǔ)系列(二)中已經(jīng)講過(guò)奴艾,這里就不再重復(fù)。
1.2 finally
(1)finally
是異常體系中的關(guān)鍵字内斯,保證重點(diǎn)代碼一定要被執(zhí)行的一種機(jī)制蕴潦。
我們可以使用try-finally
或者try-catch-finally
像啼,在finally代碼塊中進(jìn)行類似關(guān)閉JDBC連接、保證unlock鎖等動(dòng)作潭苞。在使用的時(shí)候應(yīng)該注意:
-
finally
塊的使用前提是必須要存在try塊才能使用忽冻。(成對(duì)出現(xiàn)) -
finally
塊的代碼在任何情況下都會(huì)執(zhí)行的,除了jvm退出的情況此疹。
// 這里程序在try塊中已經(jīng)退出來(lái)了僧诚,所以finally里面的代碼并不會(huì)執(zhí)行
try {
// do something
System.exit(1);
} finally{
System.out.println(“Print from finally”);
}
-
finally
非常適合做資源釋放的工作,這樣子可以保證資源文件在任何情況下都會(huì)被釋放蝗碎。
(2)當(dāng)try和catch中有return時(shí)湖笨,finally中的代碼能執(zhí)行嗎?
答案是能的蹦骑,這里驗(yàn)證一下:
public class FinallyTest {
public static void main(String[] args) {
int n=test();
System.out.println(n);
}
public static int test() {
int m;
try {
m = 3;
return m+1;
} finally {
m=8;
System.out.println("Print from finally");
}
}
}
// output:
Print from finally
4
這里要清楚一點(diǎn)慈省,finally
代碼塊是在return
關(guān)鍵字后面的代碼執(zhí)行完后再執(zhí)行的,此時(shí)還沒(méi)有出函數(shù)體眠菇,程序先將要返回的值保存起來(lái)边败,即使在finally
代碼塊中修改m的值都不影響最終的返回值。
但是琼锋,我們最好不要在finally
塊中包含return
,否則程序的返回值就不是try
或catch
中的原始保存的返回值了祟昭。
public class FinallyTest {
public static void main(String[] args) {
int n=test();
System.out.println(n);
}
public static int test() {
int m;
try {
m = 3;
return m+1;
} finally {
m=8;
System.out.println("Print from finally");
return m;
}
}
}
// output:
Print from finally
8
關(guān)于finally關(guān)鍵字缕坎,我們只要明確知道怎么使用就足夠了。
1.3 finalize
在介紹finalize之前篡悟,得說(shuō)明它是不推薦使用的谜叹,在Java 9中已經(jīng)將它標(biāo)記為deprecated
,也就是不推薦使用的搬葬。
其實(shí)荷腊,finalize
是java基礎(chǔ)類java.lang.Object
中的一個(gè)方法:
protected void finalize() throws Throwable { }
它的設(shè)計(jì)目的是保證對(duì)象在被垃圾收集前完成特定資源的回收,但是finalize()能做的所有工作急凰,使用try-finally或者其他的方式都可以做得更好女仰、更及時(shí)。
2. static
(1)static 表示靜態(tài)抡锈,它可以修飾屬性疾忍,方法和代碼塊。
- static修飾的變量即為靜態(tài)變量床三,當(dāng)JVM加載類后一罩,可以通過(guò)類名直接訪問(wèn),類的所有實(shí)例共享一個(gè)static變量撇簿。(不光創(chuàng)建多少個(gè)對(duì)象聂渊,靜態(tài)屬性在內(nèi)存中只有一個(gè))在<<深入類和對(duì)象>>中提到:在類的生命周期的連接階段的準(zhǔn)備過(guò)程中差购,JVM會(huì)為類的靜態(tài)變量分配內(nèi)存并設(shè)為jvm默認(rèn)的初值,所以靜態(tài)變量是對(duì)象創(chuàng)建之前就存在的汉嗽。static不能修飾局部變量欲逃。
- static修飾的方法即為靜態(tài)方法, 靜態(tài)方法可以直接通過(guò)類名調(diào)用诊胞,但是不能直接訪問(wèn)所屬類的實(shí)例變量和方法暖夭,只能訪問(wèn)所屬類的靜態(tài)變量和方法,這是因?yàn)閷?shí)例成員只與特定對(duì)象關(guān)聯(lián)撵孤。靜態(tài)方法不能被重寫(xiě)迈着。
- static還可以修飾代碼塊,它是類中獨(dú)立于類成員的static語(yǔ)句塊邪码,不在任何方法體內(nèi)裕菠,當(dāng)JVM加載類時(shí),就會(huì)執(zhí)行靜態(tài)代碼塊闭专,無(wú)需等待實(shí)例化奴潘,static語(yǔ)句塊可以多個(gè),JVM會(huì)按照它們的先后順序依次執(zhí)行影钉。靜態(tài)代碼塊是在類的生命周期的初始化階段執(zhí)行的画髓,詳細(xì)過(guò)程請(qǐng)看<<深入類和對(duì)象>>。
(2)static和final一起使用有什么作用平委?
- static和final修飾的變量可看做“全局變量”奈虾,在類加載在類的生命周期的連接階段的準(zhǔn)備過(guò)程中,JVM會(huì)為類的靜態(tài)常量分配內(nèi)存并設(shè)為程序員賦予的初始值廉赔。
- static和final修飾的方法肉微,不能被繼承,可以通過(guò)類名直接調(diào)用蜡塌。
3. this和super
3.1 this
(1)this關(guān)鍵字指向:
this
關(guān)鍵字代表了this
所屬函數(shù)的調(diào)用者對(duì)象碉纳,這句話的意思是,this
在某個(gè)方法的內(nèi)部馏艾,若這個(gè)方法被一個(gè)對(duì)象調(diào)用劳曹,那么this就指向這個(gè)對(duì)象。
(2)this關(guān)鍵字的作用:
- 如果存在同名
成員變量
與局部變量
時(shí)琅摩,在方法內(nèi)部默認(rèn)是訪問(wèn)局部變量的數(shù)據(jù)(就近原則)厚者,可以通過(guò)this關(guān)鍵字指定訪問(wèn)成員變量的數(shù)據(jù)。- 如果在方法中訪問(wèn)了成員變量迫吐,java編譯器會(huì)在該變量的前面加上this關(guān)鍵字库菲。
- 在一個(gè)構(gòu)造函數(shù)中可以調(diào)用另外一個(gè)構(gòu)造函數(shù)初始化對(duì)象。需注意:
- this關(guān)鍵字調(diào)用其他的構(gòu)造函數(shù)時(shí)志膀,this關(guān)鍵字必須要位于構(gòu)造函數(shù)中的第一個(gè)語(yǔ)句熙宇。
- 如果在一個(gè)方法中訪問(wèn)了一個(gè)變量鳖擒,該變量只存在成員變量的情況下,那么java編譯器會(huì)在該變量的前面添加this關(guān)鍵字烫止。
3.2 super
(1)super 關(guān)鍵字的指向:
super
關(guān)鍵字代表的是父類的引用空間
(2)super關(guān)鍵字的作用:
- 如果子父類存在同名的成員時(shí)蒋荚,在子類中默認(rèn)是訪問(wèn)子類的成員,可以通過(guò)super關(guān)鍵字指定訪問(wèn)父類的成員馆蠕。
- 創(chuàng)建子類對(duì)象時(shí)期升,默認(rèn)會(huì)先調(diào)用父類的無(wú)參構(gòu)造函數(shù),可以通過(guò)super關(guān)鍵字指定調(diào)用父類的構(gòu)造函數(shù)互躬。需注意:
- 如果在子類 的構(gòu)造函數(shù)中沒(méi)有指定調(diào)用具體父類構(gòu)造函數(shù)播赁,那么java編譯器會(huì)在子類的構(gòu)造函數(shù)上添加super()語(yǔ)句。
- super關(guān)鍵字調(diào)用構(gòu)造函數(shù)時(shí)必須出現(xiàn)構(gòu)造函數(shù)中第一個(gè)語(yǔ)句吼渡。
4. 總結(jié)
本文就 final容为、finally、finalize
寺酪、static
和this坎背、super
三組關(guān)鍵字進(jìn)行分析,讓大家清楚每組關(guān)鍵字中的差別和用法寄雀,以及使用的時(shí)候的注意事項(xiàng)得滤。當(dāng)然Java中還有許多的關(guān)鍵字,例如synchronized
盒犹、volatile
等關(guān)鍵字懂更,這將在后面的多線程、高并發(fā)中講到阿趁。