面試官:兄弟疾忍,說說Java的static關鍵字吧

讀者乙在上一篇我去系列文章里留言說乔外,“我盲猜下一篇標題是,‘我去一罩,你竟然不知道 static 關鍵字’”杨幼。我只能說乙猜對了一半,像我這么有才華的博主差购,怎么可能被讀者猜中了心思呢,必須搞點不一樣的啊欲逃,所以本篇文章的標題你看到了饼暑。

七年前稳析,我從美女很多的蘇州回到美女也不少的洛陽,抱著一幅“從二線城市退居三線城市”的心態(tài)撵孤,投了不少簡歷,也“約談”了不少面試官邪码,但僅有兩三個令我感到滿意咬清。其中有一位叫老馬闭专,至今還活在我的微信通訊錄里奴潘。他當時扔了一個面試題把我砸懵了:“兄弟,說說 Java 的 static 關鍵字吧影钉。

我那時候二十三歲画髓,正值青春年華平委,自認為所有的面試題都能對答如流,結果沒想到啊廉赔,被“刁難”了——原來洛陽這塊互聯(lián)網(wǎng)的荒漠也有技術專家啊∪馕ⅲ現(xiàn)在回想起來蜡塌,臉上不自覺地泛起了羞愧的紅暈:主要是自己當時太菜了。

不管怎么說馏艾,經過多年的努力,我現(xiàn)在的技術功底已經非常扎實了铁孵,有能力寫篇文章剖析一下 Java 的 static 關鍵字了——只要能給初學者一些參考房资,我就覺得非常滿足。

先來個提綱挈領(唉呀媽呀志膀,成語區(qū)博主上線了)吧:

static 關鍵字可用于變量、方法溉浙、代碼塊和內部類,表示某個特定的成員只屬于某個類本身馆蠕,而不是該類的某個對象惊奇。

01互躬、靜態(tài)變量

靜態(tài)變量也叫類變量,它屬于一個類吼渡,而不是這個類的對象。

public class Writer {
    private String name;
    private int age;
    public static int countOfWriters;

    public Writer(String name, int age) {
        this.name = name;
        this.age = age;
        countOfWriters++;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

其中乓序,countOfWriters 被稱為靜態(tài)變量寺酪,它有別于 name 和 age 這兩個成員變量,因為它前面多了一個修飾符 static寄雀。

這意味著無論這個類被初始化多少次,靜態(tài)變量的值都會在所有類的對象中共享懂更。

Writer w1 = new Writer("沉默王二",18);
Writer w2 = new Writer("沉默王三",16);

System.out.println(Writer.countOfWriters);

按照上面的邏輯沮协,你應該能推理得出皂股,countOfWriters 的值此時應該為 2 而不是 1命黔。從內存的角度來看悍募,靜態(tài)變量將會存儲在 Java 虛擬機中一個名叫“Metaspace”(元空間,Java 8 之后)的特定池中坠宴。

靜態(tài)變量和成員變量有著很大的不同,成員變量的值屬于某個對象,不同的對象之間庄岖,值是不共享的隅忿;但靜態(tài)變量不是的,它可以用來統(tǒng)計對象的數(shù)量优烧,因為它是共享的链峭。就像上面例子中的 countOfWriters,創(chuàng)建一個對象的時候,它的值為 1捍掺,創(chuàng)建兩個對象的時候,它的值就為 2喂柒。

簡單小結一下:

1)由于靜態(tài)變量屬于一個類灾杰,所以不要通過對象引用來訪問艳吠,而應該直接通過類名來訪問昭娩;

2)不需要初始化類就可以訪問靜態(tài)變量栏渺。

public class WriterDemo {
    public static void main(String[] args) {
        System.out.println(Writer.countOfWriters); // 輸出 0
    }
}

02磕诊、靜態(tài)方法

靜態(tài)方法也叫類方法霎终,它和靜態(tài)變量類似莱褒,屬于一個類保礼,而不是這個類的對象炮障。

public static void setCountOfWriters(int countOfWriters) {
    Writer.countOfWriters = countOfWriters;
}

setCountOfWriters() 就是一個靜態(tài)方法胁赢,它由 static 關鍵字修飾智末。

如果你用過 java.lang.Math 類或者 Apache 的一些工具類(比如說 StringUtils)的話送漠,對靜態(tài)方法一定不會感動陌生由蘑。

Math 類的幾乎所有方法都是靜態(tài)的爷狈,可以直接通過類名來調用涎永,不需要創(chuàng)建類的對象羡微。

簡單小結一下:

1)Java 中的靜態(tài)方法在編譯時解析拷淘,因為靜態(tài)方法不能被重寫(方法重寫發(fā)生在運行時階段启涯,為了多態(tài))结洼。

2)抽象方法不能是靜態(tài)的松忍。

3)靜態(tài)方法不能使用 this 和 super 關鍵字。

4)成員方法可以直接訪問其他成員方法和成員變量摊溶。

5)成員方法也可以直接方法靜態(tài)方法和靜態(tài)變量莫换。

6)靜態(tài)方法可以訪問所有其他靜態(tài)方法和靜態(tài)變量拉岁。

7)靜態(tài)方法無法直接訪問成員方法和成員變量喊暖。

03雅任、靜態(tài)代碼塊

靜態(tài)代碼塊可以用來初始化靜態(tài)變量咨跌,盡管靜態(tài)方法也可以在聲明的時候直接初始化锌半,但有些時候刊殉,我們需要多行代碼來完成初始化记焊。

public class StaticBlockDemo {
    public static List<String> writes = new ArrayList<>();

    static {
        writes.add("沉默王二");
        writes.add("沉默王三");
        writes.add("沉默王四");

        System.out.println("第一塊");
    }

    static {
        writes.add("沉默王五");
        writes.add("沉默王六");

        System.out.println("第二塊");
    }
}

writes 是一個靜態(tài)的 ArrayList,所以不太可能在聲明的時候完成初始化瓤湘,因此需要在靜態(tài)代碼塊中完成初始化弛说。

簡單小結一下:

1)一個類可以有多個靜態(tài)代碼塊木人。

2)靜態(tài)代碼塊的解析和執(zhí)行順序和它在類中的位置保持一致醒第。為了驗證這個結論淘讥,可以在 StaticBlockDemo 類中加入空的 main 方法,執(zhí)行完的結果如下所示:

第一塊
第二塊

04、靜態(tài)內部類

Java 允許我們在一個類中聲明一個內部類侥猩,它提供了一種令人信服的方式欺劳,允許我們只在一個地方使用一些變量划提,使代碼更具有條理性和可讀性鹏往。

常見的內部類有四種伊履,成員內部類唐瀑、局部內部類哄辣、匿名內部類和靜態(tài)內部類柔滔,限于篇幅原因睛廊,前三種不在我們本次文章的討論范圍,以后有機會再細說。

public class Singleton {
    private Singleton() {}

    private static class SingletonHolder {
        public static final Singleton instance = new Singleton();
    }

    public static Singleton getInstance() {
        return SingletonHolder.instance;
    }
}

以上這段代碼是不是特別熟悉蛾坯,對脉课,這就是創(chuàng)建單例的一種方式倘零,第一次加載 Singleton 類時并不會初始化 instance,只有第一次調用 getInstance() 方法時 Java 虛擬機才開始加載 SingletonHolder 并初始化 instance,這樣不僅能確保線程安全也能保證 Singleton 類的唯一性。不過聋迎,創(chuàng)建單例更優(yōu)雅的一種方式是使用枚舉砌庄。

簡單小結一下:

1)靜態(tài)內部類不能訪問外部類的所有成員變量娄昆。

2)靜態(tài)內部類可以訪問外部類的所有靜態(tài)變量萌焰,包括私有靜態(tài)變量扒俯。

3)外部類不能聲明為 static撼玄。

學到了吧?學到就是賺到荔茬。

我是沉默王二竹海,一枚有趣的程序員斋配。如果覺得文章對你有點幫助,請微信搜索「 沉默王二 」第一時間閱讀菩鲜,回復【666】更有我為你精心準備的 500G 高清教學視頻(已分門別類)接校。

本文 GitHub 已經收錄狮崩,有大廠面試完整考點诽凌,歡迎 Star侣诵。

原創(chuàng)不易杜顺,莫要白票躬络,請你為本文點個贊吧搭儒,這將是我寫作更多優(yōu)質文章的最強動力淹禾。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末汪疮,一起剝皮案震驚了整個濱河市铲咨,隨后出現(xiàn)的幾起案子纤勒,更是在濱河造成了極大的恐慌隆檀,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,284評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡纯丸,警方通過查閱死者的電腦和手機觉鼻,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來仇矾,“玉大人若未,你說我怎么就攤上這事粗合∠毒危” “怎么了供屉?”我有些...
    開封第一講書人閱讀 164,614評論 0 354
  • 文/不壞的土叔 我叫張陵伶丐,是天一觀的道長哗魂。 經常有香客問我,道長齿兔,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,671評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮盈咳,結果婚禮上猪贪,老公的妹妹穿的比我還像新娘热押。我一直安慰自己桶癣,他們只是感情好牙寞,可當我...
    茶點故事閱讀 67,699評論 6 392
  • 文/花漫 我一把揭開白布间雀。 她就那樣靜靜地躺著惹挟,像睡著了一般连锯。 火紅的嫁衣襯著肌膚如雪运怖。 梳的紋絲不亂的頭發(fā)上摇展,一...
    開封第一講書人閱讀 51,562評論 1 305
  • 那天吗购,我揣著相機與錄音捻勉,去河邊找鬼踱启。 笑死埠偿,一個胖子當著我的面吹牛冠蒋,可吹牛的內容都是我干的抖剿。 我是一名探鬼主播斩郎,決...
    沈念sama閱讀 40,309評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼肘迎,長吁一口氣:“原來是場噩夢啊……” “哼妓布!你這毒婦竟也來了秋茫?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,223評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎殉农,沒想到半個月后超凳,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 45,668評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,859評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了涧尿。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片姑廉。...
    茶點故事閱讀 39,981評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡萌踱,死狀恐怖虫蝶,靈堂內的尸體忽然破棺而出能真,到底是詐尸還是另有隱情粉铐,我是刑警寧澤蝙泼,帶...
    沈念sama閱讀 35,705評論 5 347
  • 正文 年R本政府宣布汤踏,位于F島的核電站溪胶,受9級特大地震影響哗脖,放射性物質發(fā)生泄漏才避。R本人自食惡果不足惜橱夭,卻給世界環(huán)境...
    茶點故事閱讀 41,310評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望肢娘。 院中可真熱鬧橱健,春花似錦拘荡、人聲如沸珊皿。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽抄淑。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間郑原,已是汗流浹背犯犁。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留簇捍,地道東北人暑塑。 一個月前我還...
    沈念sama閱讀 48,146評論 3 370
  • 正文 我出身青樓事格,卻偏偏與公主長得像驹愚,于是被迫代替她去往敵國和親逢捺。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,933評論 2 355