Java Static關(guān)鍵字

在java中亏钩,static是一個(gè)修飾符都伪,用于修飾類的成員方法钱床、類的成員變量翠勉,另外可以編寫static代碼塊來優(yōu)化程序性能妖啥;被static關(guān)鍵字修飾的方法或者變量不需要依賴于對(duì)象來進(jìn)行訪問,只要類被加載了对碌,就可以通過類名去進(jìn)行訪問荆虱。

static關(guān)鍵字的用途

在《Java編程思想》P86頁(yè)有這樣一段話:
static方法就是沒有this的方法。在static方法內(nèi)部不能調(diào)用非靜態(tài)方法朽们,反過來是可以的怀读。而且可以在沒有創(chuàng)建任何對(duì)象的前提下,僅僅通過類本身來調(diào)用static方法骑脱。這實(shí)際上正是static方法的主要用途菜枷。
這段話雖然只是說明了static方法的特殊之處,但是可以看出static關(guān)鍵字的基本作用叁丧,簡(jiǎn)而言之啤誊,一句話來描述就是:
  方便在沒有創(chuàng)建對(duì)象的情況下來進(jìn)行調(diào)用(方法/變量)
  很顯然岳瞭,被static關(guān)鍵字修飾的方法或者變量不需要依賴于對(duì)象來進(jìn)行訪問,只要類被加載了蚊锹,就可以通過類名去進(jìn)行訪問寝优。
  static可以用來修飾類的成員方法、類的成員變量枫耳,另外可以編寫static代碼塊來優(yōu)化程序性能乏矾。

static方法

static方法也成為靜態(tài)方法,由于靜態(tài)方法不依賴于任何對(duì)象就可以直接訪問迁杨,因此對(duì)于靜態(tài)方法來說钻心,是沒有this的,因?yàn)椴灰栏接谌魏螌?duì)象铅协,既然都沒有對(duì)象捷沸,就談不上this了,并且由于此特性狐史,在靜態(tài)方法中不能訪問類的非靜態(tài)成員變量和非靜態(tài)方法痒给,因?yàn)榉庆o態(tài)成員變量和非靜態(tài)方法都必須依賴于具體的對(duì)象才能被調(diào)用。

雖然在靜態(tài)方法中不能訪問非靜態(tài)成員方法和非靜態(tài)成員變量骏全,但是在非靜態(tài)成員方法中是可以訪問靜態(tài)成員方法和靜態(tài)成員變量苍柏。

代碼示例:


從上面代碼里看出:

  • 靜態(tài)方法test2()中調(diào)用非靜態(tài)成員變量address,編譯失敗姜贡。這是因?yàn)槭杂酰诰幾g期并沒有對(duì)象生成,address變量根本就不存在楼咳。
  • 靜態(tài)方法test2()中調(diào)用非靜態(tài)方法test1()熄捍,編譯失敗。這是因?yàn)槟噶幾g器無法預(yù)知在非靜態(tài)成員方法test1()中是否訪問了非靜態(tài)成員變量余耽,所以也禁止在靜態(tài)方法中調(diào)用非靜態(tài)成員方法。
  • 非靜態(tài)成員方法test1()訪問靜態(tài)成員方法test2()/變量name是沒有限制的苹熏。

所以碟贾,如果想在不創(chuàng)建對(duì)象的情況下調(diào)用某個(gè)方法,就可以將這個(gè)方法設(shè)置為static柜裸。最常見的靜態(tài)方法就是main方法缕陕,這就是為什么main方法是靜態(tài)方法就一目了然了,因?yàn)槌绦蛟趫?zhí)行main方法的時(shí)候沒有創(chuàng)建任何對(duì)象疙挺,只有通過類名來訪問。

static方法是屬于類的怜浅,非實(shí)例對(duì)象铐然,在JVM加載類時(shí)蔬崩,就已經(jīng)存在內(nèi)存中,不會(huì)被虛擬機(jī)GC回收掉搀暑,這樣內(nèi)存負(fù)荷會(huì)很大沥阳,但是非static方法會(huì)在運(yùn)行完畢后被虛擬機(jī)GC掉,減輕內(nèi)存壓力自点。

static變量

static變量也稱為靜態(tài)變量桐罕,靜態(tài)變量和非靜態(tài)變量的區(qū)別:

  • 靜態(tài)變量被所有對(duì)象共享,在內(nèi)存中只有一個(gè)副本桂敛,在類初次加載的時(shí)候才會(huì)初始化功炮。

  • 非靜態(tài)變量是對(duì)象所擁有的,在創(chuàng)建對(duì)象的時(shí)候被初始化术唬,存在多個(gè)副本薪伏,各個(gè)對(duì)象擁有的副本互不影響。

static成員變量初始化順序按照定義的順序來進(jìn)行初始化

static塊

構(gòu)造方法用于對(duì)象的初始化粗仓。靜態(tài)初始化塊嫁怀,用于類的初始化操作。
在靜態(tài)初始化塊中不能直接訪問非staic成員借浊。

static塊的作用

靜態(tài)初始化塊的作用就是:提升程序性能塘淑。
為什么說static塊可以用來優(yōu)化程序性能,是因?yàn)樗奶匦?只會(huì)在類加載的時(shí)候執(zhí)行一次蚂斤。代碼如下:

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是用來這個(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)行

靜態(tài)初始化塊可以置于類中的任何地方逸爵,類中可以有多個(gè)靜態(tài)初始化塊具滴。
在類初次被加載時(shí),會(huì)按照靜態(tài)初始化塊的順序來執(zhí)行每個(gè)塊师倔,并且只會(huì)執(zhí)行一次构韵。

static關(guān)鍵字的誤區(qū)
  1. static關(guān)鍵字會(huì)改變類中成員的訪問權(quán)限嗎?
    有些初學(xué)的朋友會(huì)將java中的static與C/C++中的static關(guān)鍵字的功能混淆了趋艘。在這里只需要記住一點(diǎn):與C/C++中的static不同疲恢,Java中的static關(guān)鍵字不會(huì)影響到變量或者方法的作用域。在Java中能夠影響到訪問權(quán)限的只有private瓷胧、public显拳、protected(包括包訪問權(quán)限)這幾個(gè)關(guān)鍵字〈晗簦看下面的例子就明白了:


說明static關(guān)鍵字不能改變變量和方法的訪問權(quán)限

  1. 能通過this訪問靜態(tài)成員變量嗎杂数?
    雖然對(duì)于靜態(tài)方法來說沒有this宛畦,那么在非靜態(tài)方法中能夠通過this訪問靜態(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ì)象,那么通過new Main()來調(diào)用printValue的話畅形,當(dāng)前對(duì)象就是通過new Main()生成的對(duì)象怕敬。而static變量是被對(duì)象所享有的,因此在printValue中的this.value的值毫無疑問是33帘皿。在printValue方法內(nèi)部的value是局部變量东跪,根本不可能與this關(guān)聯(lián),所以輸出結(jié)果是33鹰溜。在這里永遠(yuǎn)要記住一點(diǎn):靜態(tài)成員變量雖然獨(dú)立于對(duì)象虽填,但是不代表不可以通過對(duì)象去訪問,所有的靜態(tài)方法和靜態(tài)變量都可以通過對(duì)象訪問(只要訪問權(quán)限足夠)曹动。

3.static能作用于局部變量么斋日?
static是不允許用來修飾局部變量。不要問為什么墓陈,這是Java語法的規(guī)定

static常見筆試面試題

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");
    }
}

輸出結(jié)果為:

base static
test static
base constructor
test constructor

分析下這段代碼的執(zhí)行過程:

  • 找到main方法入口贡必,main方法是程序入口兔港,但在執(zhí)行main方法之前,要先加載Test類
  • 加載Test類的時(shí)候仔拟,發(fā)現(xiàn)Test類繼承Base類衫樊,于是先去加載Base類
  • 加載Base類的時(shí)候,發(fā)現(xiàn)Base類有static塊理逊,而是先執(zhí)行static塊橡伞,輸出base static結(jié)果
  • Base類加載完成后盒揉,再去加載Test類晋被,發(fā)現(xiàn)Test類也有static塊兑徘,而是執(zhí)行Test類中的static塊,輸出test static結(jié)果
  • Base類和Test類加載完成后羡洛,然后執(zhí)行main方法中的new Test()挂脑,調(diào)用子類構(gòu)造器之前會(huì)先調(diào)用父類構(gòu)造器
  • 調(diào)用父類構(gòu)造器,輸出base constructor結(jié)果
  • 然后再調(diào)用子類構(gòu)造器欲侮,輸出test constructor結(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");
    }
}

輸出結(jié)果為:

test static
myclass static
person static
person Test
test constructor
person MyClass
myclass constructor

為什么輸出結(jié)果是這樣的威蕉?我們來分析下這段代碼的執(zhí)行過程:

  • 找到main方法入口刁俭,main方法是程序入口,但在執(zhí)行main方法之前韧涨,要先加載Test類
  • 加載Test類的時(shí)候牍戚,發(fā)現(xiàn)Test類有static塊,而是先執(zhí)行static塊虑粥,輸出test static結(jié)果
  • 然后執(zhí)行new MyClass(),執(zhí)行此代碼之前如孝,先加載MyClass類,發(fā)現(xiàn)MyClass類繼承Test類娩贷,而是要先加載Test類第晰,Test類之前已加載
  • 加載MyClass類,發(fā)現(xiàn)MyClass類有static塊彬祖,而是先執(zhí)行static塊茁瘦,輸出myclass static結(jié)果
  • 然后調(diào)用MyClass類的構(gòu)造器生成對(duì)象,在生成對(duì)象前储笑,需要先初始化父類Test的成員變量甜熔,而是執(zhí)行Person person = new Person("Test")代碼,發(fā)現(xiàn)Person類沒有加載
  • 加載Person類南蓬,發(fā)現(xiàn)Person類有static塊纺非,而是先執(zhí)行static塊,輸出person static結(jié)果
  • 接著執(zhí)行Person構(gòu)造器赘方,輸出person Test結(jié)果
  • 然后調(diào)用父類Test構(gòu)造器烧颖,輸出test constructor結(jié)果,這樣就完成了父類Test的初始化了
  • 再初始化MyClass類成員變量窄陡,執(zhí)行Person構(gòu)造器炕淮,輸出person MyClass結(jié)果
  • 最后調(diào)用MyClass類構(gòu)造器,輸出myclass constructor結(jié)果跳夭,這樣就完成了MyClass類的初始化了

3涂圆、這段代碼的輸出結(jié)果是什么们镜?

public class Test {
     
    static{
        System.out.println("test static 1");
    }
    public static void main(String[] args) {
         
    }
     
    static{
        System.out.println("test static 2");
    }
}

輸出結(jié)果為:

test static 1
test static 2

雖然在main方法中沒有任何語句,但是還是會(huì)輸出润歉,原因上面已經(jīng)講述過了模狭。另外,static塊可以出現(xiàn)類中的任何地方(只要不是方法內(nèi)部踩衩,記住嚼鹉,任何方法內(nèi)部都不行),并且執(zhí)行是按照static塊的順序執(zhí)行的驱富。

參考資料:
https://www.php.cn/java/guide/462574.html
https://bbs.csdn.net/topics/330251070
https://blog.csdn.net/zhu_apollo/article/details/1888219
https://www.cnblogs.com/dolphin0520/p/3799052.html

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末锚赤,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子褐鸥,更是在濱河造成了極大的恐慌线脚,老刑警劉巖抢呆,帶你破解...
    沈念sama閱讀 212,884評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件短荐,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡虾啦,警方通過查閱死者的電腦和手機(jī)翠霍,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,755評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門锭吨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人寒匙,你說我怎么就攤上這事零如。” “怎么了锄弱?”我有些...
    開封第一講書人閱讀 158,369評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵考蕾,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我会宪,道長(zhǎng)肖卧,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,799評(píng)論 1 285
  • 正文 為了忘掉前任掸鹅,我火速辦了婚禮塞帐,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘巍沙。我一直安慰自己葵姥,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,910評(píng)論 6 386
  • 文/花漫 我一把揭開白布句携。 她就那樣靜靜地躺著榔幸,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上削咆,一...
    開封第一講書人閱讀 50,096評(píng)論 1 291
  • 那天牍疏,我揣著相機(jī)與錄音,去河邊找鬼拨齐。 笑死鳞陨,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的奏黑。 我是一名探鬼主播炊邦,決...
    沈念sama閱讀 39,159評(píng)論 3 411
  • 文/蒼蘭香墨 我猛地睜開眼编矾,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼熟史!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起窄俏,我...
    開封第一講書人閱讀 37,917評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤蹂匹,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后凹蜈,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體限寞,經(jīng)...
    沈念sama閱讀 44,360評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,673評(píng)論 2 327
  • 正文 我和宋清朗相戀三年仰坦,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了履植。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,814評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡悄晃,死狀恐怖玫霎,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情妈橄,我是刑警寧澤庶近,帶...
    沈念sama閱讀 34,509評(píng)論 4 334
  • 正文 年R本政府宣布,位于F島的核電站眷蚓,受9級(jí)特大地震影響鼻种,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜沙热,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,156評(píng)論 3 317
  • 文/蒙蒙 一叉钥、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧篙贸,春花似錦投队、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春轧膘,著一層夾襖步出監(jiān)牢的瞬間钞螟,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,123評(píng)論 1 267
  • 我被黑心中介騙來泰國(guó)打工谎碍, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留鳞滨,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,641評(píng)論 2 362
  • 正文 我出身青樓蟆淀,卻偏偏與公主長(zhǎng)得像拯啦,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子熔任,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,728評(píng)論 2 351

推薦閱讀更多精彩內(nèi)容