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

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

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

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

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

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

static 關鍵字可用于變量、方法、代碼塊和內(nèi)部類,表示某個特定的成員只屬于某個類本身,而不是該類的某個對象。

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。從內(nèi)存的角度來看,靜態(tài)變量將會存儲在 Java 虛擬機中一個名叫“Metaspace”(元空間,Java 8 之后)的特定池中。

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

簡單小結(jié)一下:

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)的,可以直接通過類名來調(diào)用,不需要創(chuàng)建類的對象。

簡單小結(jié)一下:

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)代碼塊中完成初始化。

簡單小結(jié)一下:

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

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

第一塊
第二塊

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

Java 允許我們在一個類中聲明一個內(nèi)部類,它提供了一種令人信服的方式,允許我們只在一個地方使用一些變量,使代碼更具有條理性和可讀性。

常見的內(nèi)部類有四種,成員內(nèi)部類、局部內(nèi)部類、匿名內(nèi)部類和靜態(tài)內(nè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,只有第一次調(diào)用 getInstance() 方法時 Java 虛擬機才開始加載 SingletonHolder 并初始化 instance,這樣不僅能確保線程安全也能保證 Singleton 類的唯一性。不過,創(chuàng)建單例更優(yōu)雅的一種方式是使用枚舉。

簡單小結(jié)一下:

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

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

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

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

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

本文 GitHub 已經(jīng)收錄,有大廠面試完整考點,歡迎 Star。

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

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內(nèi)容