<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          親妹都能學(xué)會的 static 關(guān)鍵字

          共 6309字,需瀏覽 13分鐘

           ·

          2020-12-11 13:04

          “哥,一周過去了,教妹學(xué) Java 你都沒有更新,偷懶了呀!”三妹關(guān)心地問我。

          “今天就更新。”我面帶著微笑對三妹說,“學(xué)習(xí)可不能落下,今天我們來學(xué) Java 中 static 關(guān)鍵字吧。”

          “static 是 Java 中比較難以理解的一個關(guān)鍵字,也是各大公司的面試官最喜歡問到的一個知識點之一。”我喝了一口咖啡繼續(xù)說道。

          “既然是面試重點,那我可得好好學(xué)習(xí)下。”三妹連忙說。

          “static 關(guān)鍵字的作用可以用一句話來描述:‘方便在沒有創(chuàng)建對象的情況下進(jìn)行調(diào)用,包括變量和方法’。也就是說,只要類被加載了,就可以通過類名進(jìn)行訪問。”我扶了扶沉重眼鏡,繼續(xù)說到,“static 可以用來修飾類的成員變量,以及成員方法。我們一個個來看。”

          01、靜態(tài)變量

          “如果在聲明變量的時候使用了 static 關(guān)鍵字,那么這個變量就被稱為靜態(tài)變量。靜態(tài)變量只在類加載的時候獲取一次內(nèi)存空間,這使得靜態(tài)變量很節(jié)省內(nèi)存空間。”家里的暖氣有點足,我跑去開了一點窗戶后繼續(xù)說道。

          “來考慮這樣一個 Student 類。”話音剛落,我就在鍵盤上噼里啪啦一陣敲。

          public?class?Student?{
          ????String?name;
          ????int?age;
          ????String?school?=?"鄭州大學(xué)";
          }

          這段代碼敲完后,我對三妹說:“假設(shè)鄭州大學(xué)錄取了一萬名新生,那么在創(chuàng)建一萬個 Student 對象的時候,所有的字段(name、age 和 school)都會獲取到一塊內(nèi)存。學(xué)生的姓名和年紀(jì)不盡相同,但都屬于鄭州大學(xué),如果每創(chuàng)建一個對象,school 這個字段都要占用一塊內(nèi)存的話,就很浪費,對吧?三妹。”

          “因此,最好將 school 這個字段設(shè)置為 static,這樣就只會占用一塊內(nèi)存,而不是一萬塊。”

          安靜的房子里又響起了一陣噼里啪啦的鍵盤聲。

          public?class?Student?{
          ????String?name;
          ????int?age;
          ????static?String?school?=?"鄭州大學(xué)";

          ????public?Student(String?name,?int?age)?{
          ????????this.name?=?name;
          ????????this.age?=?age;
          ????}

          ????public?static?void?main(String[]?args)?{
          ????????Student?s1?=?new?Student("沉默王二",?18);
          ????????Student?s2?=?new?Student("沉默王三",?16);
          ????}
          }

          “瞧,三妹。s1 和 s2 這兩個引用變量存放在棧區(qū)(stack),沉默王二+18 這個對象和沉默王三+16 這個對象存放在堆區(qū)(heap),school 這個靜態(tài)變量存放在靜態(tài)區(qū)。”

          “等等,哥,棧、堆、靜態(tài)區(qū)?”三妹的臉上塞滿了疑惑。

          “哦哦,別擔(dān)心,三妹,畫幅圖你就全明白了。”說完我就打開 draw.io 這個網(wǎng)址,認(rèn)真地畫起了圖。

          “現(xiàn)在,是不是一下子就明白了?”看著這幅漂亮的手繪圖,我心里有點小開心。

          “哇,哥,驚艷了呀!”三妹也不忘拍馬屁,給我了一個大大的贊。

          “好了,三妹,我們來看下面這串代碼。”

          public?class?Counter?{
          ????int?count?=?0;

          ????Counter()?{
          ????????count++;
          ????????System.out.println(count);
          ????}

          ????public?static?void?main(String?args[])?{
          ????????Counter?c1?=?new?Counter();
          ????????Counter?c2?=?new?Counter();
          ????????Counter?c3?=?new?Counter();
          ????}
          }

          “我們創(chuàng)建一個成員變量 count,并且在構(gòu)造函數(shù)中讓它自增。因為成員變量會在創(chuàng)建對象的時候獲取內(nèi)存,因此每一個對象都會有一個 count 的副本, count 的值并不會隨著對象的增多而遞增。”

          我在侃侃而談,而三妹似乎有些不太明白。

          “沒關(guān)系,三妹,你先盲猜一下,這段代碼輸出的結(jié)果是什么?”

          “按照你的邏輯,應(yīng)該輸出三個 1?是這樣嗎?”三妹眨眨眼,有點不太自信地回答。

          “哎呀,不錯喲。”

          我在 IDEA 中點了一下運行按鈕,程序跑了起來。

          1
          1
          1

          “每創(chuàng)建一個 Counter 對象,count 的值就從 0 自增到 1。三妹,想一下,如果 count 是靜態(tài)的呢?”

          “我不知道啊。”

          “嗯,來看下面這段代碼。”

          public?class?StaticCounter?{
          ????static?int?count?=?0;

          ????StaticCounter()?{
          ????????count++;
          ????????System.out.println(count);
          ????}

          ????public?static?void?main(String?args[])?{
          ????????StaticCounter?c1?=?new?StaticCounter();
          ????????StaticCounter?c2?=?new?StaticCounter();
          ????????StaticCounter?c3?=?new?StaticCounter();
          ????}
          }

          “來看一下輸出結(jié)果。”

          1
          2
          3

          “簡單解釋一下哈,由于靜態(tài)變量只會獲取一次內(nèi)存空間,所以任何對象對它的修改都會得到保留,所以每創(chuàng)建一個對象,count 的值就會加 1,所以最終的結(jié)果是 3,明白了吧?三妹。這就是靜態(tài)變量和成員變量之間的差別。”

          “另外,需要注意的是,由于靜態(tài)變量屬于一個類,所以不要通過對象引用來訪問,而應(yīng)該直接通過類名來訪問,否則編譯器會發(fā)出警告。”

          02、 靜態(tài)方法

          “說完靜態(tài)變量,我們來說靜態(tài)方法。”說完,我準(zhǔn)備點一支華子來抽,三妹阻止了我,她指一指煙盒上的「吸煙有害身體健康」,我笑了。

          “好吧。”我只好喝了一口咖啡繼續(xù)說,“如果方法上加了 static 關(guān)鍵字,那么它就是一個靜態(tài)方法。”

          “靜態(tài)方法有以下這些特征。”

          • 靜態(tài)方法屬于這個類而不是這個類的對象;
          • 調(diào)用靜態(tài)方法的時候不需要創(chuàng)建這個類的對象;
          • 靜態(tài)方法可以訪問靜態(tài)變量。

          “來,繼續(xù)上代碼”

          public?class?StaticMethodStudent?{
          ????String?name;
          ????int?age;
          ????static?String?school?=?"鄭州大學(xué)";

          ????public?StaticMethodStudent(String?name,?int?age)?{
          ????????this.name?=?name;
          ????????this.age?=?age;
          ????}
          ????
          ????static?void?change()?{
          ????????school?=?"河南大學(xué)";
          ????}
          ????
          ????void?out()?{
          ????????System.out.println(name?+?"?"?+?age?+?"?"?+?school);
          ????}

          ????public?static?void?main(String[]?args)?{
          ????????StaticMethodStudent.change();
          ????????
          ????????StaticMethodStudent?s1?=?new?StaticMethodStudent("沉默王二",?18);
          ????????StaticMethodStudent?s2?=?new?StaticMethodStudent("沉默王三",?16);
          ????????
          ????????s1.out();
          ????????s2.out();
          ????}
          }

          “仔細(xì)聽,三妹。change() 方法就是一個靜態(tài)方法,所以它可以直接訪問靜態(tài)變量 school,把它的值更改為河南大學(xué);并且,可以通過類名直接調(diào)用 change() 方法,就像 StaticMethodStudent.change() 這樣。”

          “來看一下程序的輸出結(jié)果吧。”

          沉默王二?18?河南大學(xué)
          沉默王三?16?河南大學(xué)

          “需要注意的是,靜態(tài)方法不能訪問非靜態(tài)變量和調(diào)用非靜態(tài)方法。你看,三妹,我稍微改動一下代碼,編譯器就會報錯。”

          “先是在靜態(tài)方法中訪問非靜態(tài)變量,編譯器不允許。”

          “然后在靜態(tài)方法中訪問非靜態(tài)方法,編譯器同樣不允許。”

          “關(guān)于靜態(tài)方法的使用,這下清楚了吧,三妹?”

          看著三妹點點頭,我欣慰地笑了。

          “哥,我想到了一個問題,為什么 main 方法是靜態(tài)的啊?”沒想到,三妹串聯(lián)知識點的功力還是不錯的。

          “如果 main 方法不是靜態(tài)的,就意味著 Java 虛擬機(jī)在執(zhí)行的時候需要先創(chuàng)建一個對象才能調(diào)用 main 方法,而 main 方法作為程序的入口,創(chuàng)建一個額外的對象顯得非常多余。”我不假思索的回答令三妹感到非常的欽佩。

          “java.lang.Math 類的幾乎所有方法都是靜態(tài)的,可以直接通過類名來調(diào)用,不需要創(chuàng)建類的對象。”

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

          “三妹,站起來活動一下,我的脖子都有點僵硬了。”

          我們一起走到窗戶邊,映入眼簾的是從天而降的雪花。三妹和我都高興壞了,迫不及待地打開窗口,伸出手去觸摸雪花的溫度,那種稍縱即逝的冰涼,真的舒服極了。

          “北國風(fēng)光,千里冰封,萬里雪飄。望長城內(nèi)外,惟余莽莽;大河上下,頓失滔滔。山舞銀蛇,原馳蠟象,欲與天公試比高。須晴日,看紅裝素裹,分外妖嬈。。。。。。”三妹竟然情不自禁地朗誦起了《沁園春·雪》。

          確實令人欣喜,這是 2020 年洛陽的第一場雪,的確令人感到開心。

          片刻之后。

          “除了靜態(tài)變量和靜態(tài)方法,static 關(guān)鍵字還有一個重要的作用。”我心情愉悅地對三妹說,“用一個 static 關(guān)鍵字,外加一個大括號括起來的代碼被稱為靜態(tài)代碼塊。”

          “就像下面這串代碼。”

          public?class?StaticBlock?{
          ????static?{
          ????????System.out.println("靜態(tài)代碼塊");
          ????}

          ????public?static?void?main(String[]?args)?{
          ????????System.out.println("main?方法");
          ????}
          }

          “靜態(tài)代碼塊通常用來初始化一些靜態(tài)變量,它會優(yōu)先于 main() 方法執(zhí)行。”

          “來看一下程序的輸出結(jié)果吧。”

          靜態(tài)代碼塊
          main?方法

          “二哥,既然靜態(tài)代碼塊先于 main() 方法執(zhí)行,那沒有 main() 方法的 Java 類能執(zhí)行成功嗎?”三妹的腦回路越來越令我敬佩了。

          “Java 1.6 是可以的,但 Java 7 開始就無法執(zhí)行了。”我胸有成竹地回答到。

          public?class?StaticBlockNoMain?{
          ????static?{
          ????????System.out.println("靜態(tài)代碼塊,沒有?main");
          ????}
          }

          “在命令行中執(zhí)行 java StaticBlockNoMain 的時候,會拋出 NoClassDefFoundError 的錯誤。”

          “三妹,來看下面這個例子。”

          public?class?StaticBlockDemo?{
          ????public?static?List?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)代碼塊中完成初始化。”

          “靜態(tài)代碼塊在初始集合的時候,真的非常有用。在實際的項目開發(fā)中,通常使用靜態(tài)代碼塊來加載配置文件到內(nèi)存當(dāng)中。”

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

          “三妹啊,除了以上只寫,static 還有一個不太常用的功能——靜態(tài)內(nèi)部類。”

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

          “常見的內(nèi)部類有四種,成員內(nèi)部類、局部內(nèi)部類、匿名內(nèi)部類和靜態(tài)內(nèi)部類,限于篇幅原因,前三種不在我們本次的討論范圍之內(nèi),以后有機(jī)會再細(xì)說。”

          “來看下面這個例子。”三妹有點走神,我敲了敲她的腦袋后繼續(xù)說。

          public?class?Singleton?{
          ????private?Singleton()?{}

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

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

          “三妹,打起精神,馬上就結(jié)束了。”

          “哦哦,這段代碼看起來很別致啊,哥。”

          “是的,三妹,這段代碼在以后創(chuàng)建單例的時候還會見到。”

          “第一次加載 Singleton 類時并不會初始化 instance,只有第一次調(diào)用 getInstance() 方法時 Java 虛擬機(jī)才開始加載 SingletonHolder 并初始化 instance,這樣不僅能確保線程安全,也能保證 Singleton 類的唯一性。不過,創(chuàng)建單例更優(yōu)雅的一種方式是使用枚舉,以后再講給你聽。”

          “需要注意的是。第一,靜態(tài)內(nèi)部類不能訪問外部類的所有成員變量;第二,靜態(tài)內(nèi)部類可以訪問外部類的所有靜態(tài)變量,包括私有靜態(tài)變量。第三,外部類不能聲明為 static。”

          “三妹,你看,在 Singleton 類上加 static 后,編譯器就提示錯誤了。”

          三妹點了點頭,所有所思。

          05、ending

          “三妹,static 關(guān)鍵字我們就學(xué)到這里吧,你還有什么問題嗎?”三妹學(xué)習(xí) Java 的勁頭讓我對她未來的編程生涯充滿了信心。

          “沒有了,哥,你講的挺棒的,我已經(jīng)全部都消化了。”三妹的臉上帶著微笑,“對了,哥,《教妹學(xué) Java》已經(jīng)更新到第 19 講了,你的 PDF 同步更新了嗎?”

          “更新了啊,不僅有亮白版的,還有暗黑版的,你瞧。”

          “怎么白嫖呢?”三妹也太干脆利落了。

          “方法很簡單,第一步,長按識別下面的二維碼。”

          “第二步,在公眾號后臺發(fā)送 003 獲取百度網(wǎng)盤鏈接,就可以直接下載。”

          聽我說完,三妹放心地下樓去買奶茶了,她最愛的是布丁。我趁她不在的這一會時間,跑到廚房,麻溜地打開抽油煙機(jī),狠狠地抽起了華子。

          瀏覽 49
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  超碰在线大香蕉 172.86.93.25 | 日本激情视频在线播放 | 三级久久免费 | 国产精品自产拍在线 | 午夜免费福利视频 |