Java中的static關(guān)鍵字全面解析
static關(guān)鍵字是很多朋友在編寫(xiě)代碼和閱讀代碼時(shí)碰到的比較難以理解的一個(gè)關(guān)鍵字,也是各大公司的面試官喜歡在面試時(shí)問(wèn)到的知識(shí)點(diǎn)之一。下面就先講述一下static關(guān)鍵字的用法和平常容易誤解的地方,最后列舉了一些面試筆試中常見(jiàn)的關(guān)于static的考題。以下是本文的目錄大綱:
一.static關(guān)鍵字的用途
二.static關(guān)鍵字的誤區(qū)
三.常見(jiàn)的筆試面試題
若有不正之處,希望諒解并歡迎批評(píng)指正。
請(qǐng)尊重作者勞動(dòng)成果,轉(zhuǎn)載請(qǐng)標(biāo)明原文鏈接:
http://www.cnblogs.com/dolphin0520/p/3799052.html
一.static關(guān)鍵字的用途
“static方法就是沒(méi)有this的方法。在static方法內(nèi)部不能調(diào)用非靜態(tài)方法,反過(guò)來(lái)是可以的。而且可以在沒(méi)有創(chuàng)建任何對(duì)象的前提下,僅僅通過(guò)類(lèi)本身來(lái)調(diào)用static方法。這實(shí)際上正是static方法的主要用途。”
這段話雖然只是說(shuō)明了static方法的特殊之處,但是可以看出static關(guān)鍵字的基本作用,簡(jiǎn)而言之,一句話來(lái)描述就是:
方便在沒(méi)有創(chuàng)建對(duì)象的情況下來(lái)進(jìn)行調(diào)用(方法/變量)。
很顯然,被static關(guān)鍵字修飾的方法或者變量不需要依賴(lài)于對(duì)象來(lái)進(jìn)行訪問(wèn),只要類(lèi)被加載了,就可以通過(guò)類(lèi)名去進(jìn)行訪問(wèn)。
static可以用來(lái)修飾類(lèi)的成員方法、類(lèi)的成員變量,另外可以編寫(xiě)static代碼塊來(lái)優(yōu)化程序性能。
1)static方法
static方法一般稱(chēng)作靜態(tài)方法,由于靜態(tài)方法不依賴(lài)于任何對(duì)象就可以進(jìn)行訪問(wèn),因此對(duì)于靜態(tài)方法來(lái)說(shuō),是沒(méi)有this的,因?yàn)樗灰栏接谌魏螌?duì)象,既然都沒(méi)有對(duì)象,就談不上this了。并且由于這個(gè)特性,在靜態(tài)方法中不能訪問(wèn)類(lèi)的非靜態(tài)成員變量和非靜態(tài)成員方法,因?yàn)榉庆o態(tài)成員方法/變量都是必須依賴(lài)具體的對(duì)象才能夠被調(diào)用。
但是要注意的是,雖然在靜態(tài)方法中不能訪問(wèn)非靜態(tài)成員方法和非靜態(tài)成員變量,但是在非靜態(tài)成員方法中是可以訪問(wèn)靜態(tài)成員方法/變量的。舉個(gè)簡(jiǎn)單的例子:
在上面的代碼中,由于print2方法是獨(dú)立于對(duì)象存在的,可以直接用過(guò)類(lèi)名調(diào)用。假如說(shuō)可以在靜態(tài)方法中訪問(wèn)非靜態(tài)方法/變量的話,那么如果在main方法中有下面一條語(yǔ)句:
MyObject.print2();
此時(shí)對(duì)象都沒(méi)有,str2根本就不存在,所以就會(huì)產(chǎn)生矛盾了。同樣對(duì)于方法也是一樣,由于你無(wú)法預(yù)知在print1方法中是否訪問(wèn)了非靜態(tài)成員變量,所以也禁止在靜態(tài)成員方法中訪問(wèn)非靜態(tài)成員方法。
而對(duì)于非靜態(tài)成員方法,它訪問(wèn)靜態(tài)成員方法/變量顯然是毫無(wú)限制的。
因此,如果說(shuō)想在不創(chuàng)建對(duì)象的情況下調(diào)用某個(gè)方法,就可以將這個(gè)方法設(shè)置為static。我們最常見(jiàn)的static方法就是main方法,至于為什么main方法必須是static的,現(xiàn)在就很清楚了。因?yàn)槌绦蛟趫?zhí)行main方法的時(shí)候沒(méi)有創(chuàng)建任何對(duì)象,因此只有通過(guò)類(lèi)名來(lái)訪問(wèn)。
另外記住,即使沒(méi)有顯示地聲明為static,類(lèi)的構(gòu)造器實(shí)際上也是靜態(tài)方法。
2)static變量
static變量也稱(chēng)作靜態(tài)變量,靜態(tài)變量和非靜態(tài)變量的區(qū)別是:靜態(tài)變量被所有的對(duì)象所共享,在內(nèi)存中只有一個(gè)副本,它當(dāng)且僅當(dāng)在類(lèi)初次加載時(shí)會(huì)被初始化。而非靜態(tài)變量是對(duì)象所擁有的,在創(chuàng)建對(duì)象的時(shí)候被初始化,存在多個(gè)副本,各個(gè)對(duì)象擁有的副本互不影響。
static成員變量的初始化順序按照定義的順序進(jìn)行初始化。
3)static代碼塊
static關(guān)鍵字還有一個(gè)比較關(guān)鍵的作用就是 用來(lái)形成靜態(tài)代碼塊以?xún)?yōu)化程序性能。static塊可以置于類(lèi)中的任何地方,類(lèi)中可以有多個(gè)static塊。在類(lèi)初次被加載的時(shí)候,會(huì)按照static塊的順序來(lái)執(zhí)行每個(gè)static塊,并且只會(huì)執(zhí)行一次。
為什么說(shuō)static塊可以用來(lái)優(yōu)化程序性能,是因?yàn)樗奶匦?只會(huì)在類(lèi)加載的時(shí)候執(zhí)行一次。下面看個(gè)例子:
class Person{ private Date birthDate; public Person(Date birthDate) { this.birthDate = birthDate; } boolean isBornBoomer() { Date startDate = Date.valueOf("1946"); Date endDate = Date.valueOf("1964"); return birthDate.compareTo(startDate)>=0 && birthDate.compareTo(endDate) < 0; } }
isBornBoomer是用來(lái)這個(gè)人是否是1946-1964年出生的,而每次isBornBoomer被調(diào)用的時(shí)候,都會(huì)生成startDate和birthDate兩個(gè)對(duì)象,造成了空間浪費(fèi),如果改成這樣效率會(huì)更好:
class Person{ private Date birthDate; private static Date startDate,endDate; static{ startDate = Date.valueOf("1946"); endDate = Date.valueOf("1964"); } public Person(Date birthDate) { this.birthDate = birthDate; } boolean isBornBoomer() { return birthDate.compareTo(startDate)>=0 && birthDate.compareTo(endDate) < 0; } }
因此,很多時(shí)候會(huì)將一些只需要進(jìn)行一次的初始化操作都放在static代碼塊中進(jìn)行。
二.static關(guān)鍵字的誤區(qū)
1.static關(guān)鍵字會(huì)改變類(lèi)中成員的訪問(wèn)權(quán)限嗎?
有些初學(xué)的朋友會(huì)將java中的static與C/C++中的static關(guān)鍵字的功能混淆了。在這里只需要記住一點(diǎn):與C/C++中的static不同,Java中的static關(guān)鍵字不會(huì)影響到變量或者方法的作用域。在Java中能夠影響到訪問(wèn)權(quán)限的只有private、public、protected(包括包訪問(wèn)權(quán)限)這幾個(gè)關(guān)鍵字??聪旅娴睦泳兔靼琢耍?br />
提示錯(cuò)誤"Person.age 不可視",這說(shuō)明static關(guān)鍵字并不會(huì)改變變量和方法的訪問(wèn)權(quán)限。
2.能通過(guò)this訪問(wèn)靜態(tài)成員變量嗎?
雖然對(duì)于靜態(tài)方法來(lái)說(shuō)沒(méi)有this,那么在非靜態(tài)方法中能夠通過(guò)this訪問(wèn)靜態(tài)成員變量嗎?先看下面的一個(gè)例子,這段代碼輸出的結(jié)果是什么?
public class Main { static int value = 33; public static void main(String[] args) throws Exception{ new Main().printValue(); } private void printValue(){ int value = 3; System.out.println(this.value); } }
33
這里面主要考察隊(duì)this和static的理解。this代表什么?this代表當(dāng)前對(duì)象,那么通過(guò)new Main()來(lái)調(diào)用printValue的話,當(dāng)前對(duì)象就是通過(guò)new Main()生成的對(duì)象。而static變量是被對(duì)象所享有的,因此在printValue中的this.value的值毫無(wú)疑問(wèn)是33。在printValue方法內(nèi)部的value是局部變量,根本不可能與this關(guān)聯(lián),所以輸出結(jié)果是33。在這里永遠(yuǎn)要記住一點(diǎn):靜態(tài)成員變量雖然獨(dú)立于對(duì)象,但是不代表不可以通過(guò)對(duì)象去訪問(wèn),所有的靜態(tài)方法和靜態(tài)變量都可以通過(guò)對(duì)象訪問(wèn)(只要訪問(wèn)權(quán)限足夠)。
3.static能作用于局部變量么?
在C/C++中static是可以作用域局部變量的,但是在Java中切記:static是不允許用來(lái)修飾局部變量。不要問(wèn)為什么,這是Java語(yǔ)法的規(guī)定。
三.常見(jiàn)的筆試面試題
下面列舉一些面試筆試中經(jīng)常遇到的關(guān)于static關(guān)鍵字的題目,僅供參考,如有補(bǔ)充歡迎下方留言。
1.下面這段代碼的輸出結(jié)果是什么?
public class Test extends Base{ static{ System.out.println("test static"); } public Test(){ System.out.println("test constructor"); } public static void main(String[] args) { new Test(); } } class Base{ static{ System.out.println("base static"); } public Base(){ System.out.println("base constructor"); } }
base static
test static
base constructor
test constructor
至于為什么是這個(gè)結(jié)果,我們先不討論,先來(lái)想一下這段代碼具體的執(zhí)行過(guò)程,在執(zhí)行開(kāi)始,先要尋找到main方法,因?yàn)閙ain方法是程序的入口,但是在執(zhí)行main方法之前,必須先加載Test類(lèi),而在加載Test類(lèi)的時(shí)候發(fā)現(xiàn)Test類(lèi)繼承自Base類(lèi),因此會(huì)轉(zhuǎn)去先加載Base類(lèi),在加載Base類(lèi)的時(shí)候,發(fā)現(xiàn)有static塊,便執(zhí)行了static塊。在Base類(lèi)加載完成之后,便繼續(xù)加載Test類(lèi),然后發(fā)現(xiàn)Test類(lèi)中也有static塊,便執(zhí)行static塊。在加載完所需的類(lèi)之后,便開(kāi)始執(zhí)行main方法。在main方法中執(zhí)行new Test()的時(shí)候會(huì)先調(diào)用父類(lèi)的構(gòu)造器,然后再調(diào)用自身的構(gòu)造器。因此,便出現(xiàn)了上面的輸出結(jié)果。
2.這段代碼的輸出結(jié)果是什么?
public class Test { Person person = new Person("Test"); static{ System.out.println("test static"); } public Test() { System.out.println("test constructor"); } public static void main(String[] args) { new MyClass(); } } class Person{ static{ System.out.println("person static"); } public Person(String str) { System.out.println("person "+str); } } class MyClass extends Test { Person person = new Person("MyClass"); static{ System.out.println("myclass static"); } public MyClass() { System.out.println("myclass constructor"); } }
test static 1
test static 2
雖然在main方法中沒(méi)有任何語(yǔ)句,但是還是會(huì)輸出,原因上面已經(jīng)講述過(guò)了。另外,static塊可以出現(xiàn)類(lèi)中的任何地方(只要不是方法內(nèi)部,記住,任何方法內(nèi)部都不行),并且執(zhí)行是按照static塊的順序執(zhí)行的。
以上所述是小編給大家介紹的Java中的static關(guān)鍵字全面解析,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
相關(guān)文章
Java SpringBoot開(kāi)發(fā)小技巧詳解
這篇文章主要介紹了淺談SpringBoot項(xiàng)目如何讓前端開(kāi)發(fā)提高效率(小技巧),主要介紹了Swagger和Nginx提高效率的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-09-09關(guān)于File與MultipartFile的用法概述
這篇文章主要介紹了關(guān)于File與MultipartFile的用法概述,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-09-09Java函數(shù)式編程(一):你好,Lambda表達(dá)式
這篇文章主要介紹了Java函數(shù)式編程(一):你好,Lambda表達(dá)式,本文講解了新老函數(shù)式編程的一些變化,需要的朋友可以參考下2014-09-09Spring MVC創(chuàng)建項(xiàng)目踩過(guò)的bug
這篇文章主要介紹了Spring MVC創(chuàng)建項(xiàng)目踩過(guò)的bug,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11SpringBoot整合Graylog做日志收集實(shí)現(xiàn)過(guò)程
這篇文章主要為大家介紹了SpringBoot整合Graylog做日志收集實(shí)現(xiàn)過(guò)程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12Spring之關(guān)于PropertyDescriptor的擴(kuò)展剖析
這篇文章主要介紹了Spring之關(guān)于PropertyDescriptor的擴(kuò)展剖析,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-07-07