您好,登錄后才能下訂單哦!
本篇內容介紹了“如何掌握static關鍵字”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!
“哥,一周過去了,教妹學 Java 你都沒有更新,偷懶了呀!”三妹關心地問我。
“今天就更新。”我面帶著微笑對三妹說,“學習可不能落下,今天我們來學 Java 中 static 關鍵字吧?!?/p>
“static 是 Java 中比較難以理解的一個關鍵字,也是各大公司的面試官最喜歡問到的一個知識點之一。”我喝了一口咖啡繼續(xù)說道。
“既然是面試重點,那我可得好好學習下?!比眠B忙說。
“static 關鍵字的作用可以用一句話來描述:‘方便在沒有創(chuàng)建對象的情況下進行調用,包括變量和方法’。也就是說,只要類被加載了,就可以通過類名進行訪問?!蔽曳隽朔龀林匮坨R,繼續(xù)說到,“static 可以用來修飾類的成員變量,以及成員方法。我們一個個來看。”
01、靜態(tài)變量
“如果在聲明變量的時候使用了 static 關鍵字,那么這個變量就被稱為靜態(tài)變量。靜態(tài)變量只在類加載的時候獲取一次內存空間,這使得靜態(tài)變量很節(jié)省內存空間?!奔依锏呐瘹庥悬c足,我跑去開了一點窗戶后繼續(xù)說道。
“來考慮這樣一個 Student 類?!痹捯魟偮洌揖驮阪I盤上噼里啪啦一陣敲。
public class Student { String name; int age; String school = "鄭州大學";}
這段代碼敲完后,我對三妹說:“假設鄭州大學錄取了一萬名新生,那么在創(chuàng)建一萬個 Student 對象的時候,所有的字段(name、age 和 school)都會獲取到一塊內存。學生的姓名和年紀不盡相同,但都屬于鄭州大學,如果每創(chuàng)建一個對象,school 這個字段都要占用一塊內存的話,就很浪費,對吧?三妹。”
“因此,最好將 school 這個字段設置為 static,這樣就只會占用一塊內存,而不是一萬塊。”
安靜的房子里又響起了一陣噼里啪啦的鍵盤聲。
public class Student { String name; int age; static String school = "鄭州大學"; 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ū)?!?/p>
“等等,哥,棧、堆、靜態(tài)區(qū)?”三妹的臉上塞滿了疑惑。
“哦哦,別擔心,三妹,畫幅圖你就全明白了?!闭f完我就打開 draw.io 這個網(wǎng)址,認真地畫起了圖。
“現(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,并且在構造函數(shù)中讓它自增。因為成員變量會在創(chuàng)建對象的時候獲取內存,因此每一個對象都會有一個 count 的副本, count 的值并不會隨著對象的增多而遞增?!?/p>
我在侃侃而談,而三妹似乎有些不太明白。
“沒關系,三妹,你先盲猜一下,這段代碼輸出的結果是什么?”
“按照你的邏輯,應該輸出三個 1?是這樣嗎?”三妹眨眨眼,有點不太自信地回答。
“哎呀,不錯喲?!?/p>
我在 IDEA 中點了一下運行按鈕,程序跑了起來。
111
“每創(chuàng)建一個 Counter 對象,count 的值就從 0 自增到 1。三妹,想一下,如果 count 是靜態(tài)的呢?”
“我不知道啊?!?/p>
“嗯,來看下面這段代碼。”
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(); }}
“來看一下輸出結果?!?/p>
123
“簡單解釋一下哈,由于靜態(tài)變量只會獲取一次內存空間,所以任何對象對它的修改都會得到保留,所以每創(chuàng)建一個對象,count 的值就會加 1,所以最終的結果是 3,明白了吧?三妹。這就是靜態(tài)變量和成員變量之間的差別?!?/p>
“另外,需要注意的是,由于靜態(tài)變量屬于一個類,所以不要通過對象引用來訪問,而應該直接通過類名來訪問,否則編譯器會發(fā)出警告。”
02、 靜態(tài)方法
“說完靜態(tài)變量,我們來說靜態(tài)方法?!闭f完,我準備點一支華子來抽,三妹阻止了我,她指一指煙盒上的「吸煙有害身體健康」,我笑了。
“好吧?!蔽抑缓煤攘艘豢诳Х壤^續(xù)說,“如果方法上加了 static 關鍵字,那么它就是一個靜態(tài)方法?!?/p>
“靜態(tài)方法有以下這些特征?!?/p>
靜態(tài)方法屬于這個類而不是這個類的對象;
調用靜態(tài)方法的時候不需要創(chuàng)建這個類的對象;
靜態(tài)方法可以訪問靜態(tài)變量。
“來,繼續(xù)上代碼”
public class StaticMethodStudent { String name; int age; static String school = "鄭州大學"; public StaticMethodStudent(String name, int age) { this.name = name; this.age = age; } static void change() { school = "河南大學"; } 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(); }}
“仔細聽,三妹。change() 方法就是一個靜態(tài)方法,所以它可以直接訪問靜態(tài)變量 school,把它的值更改為河南大學;并且,可以通過類名直接調用 change() 方法,就像 StaticMethodStudent.change() 這樣?!?/p>
“來看一下程序的輸出結果吧?!?/p>
沉默王二 18 河南大學沉默王三 16 河南大學
“需要注意的是,靜態(tài)方法不能訪問非靜態(tài)變量和調用非靜態(tài)方法。你看,三妹,我稍微改動一下代碼,編譯器就會報錯。”
“先是在靜態(tài)方法中訪問非靜態(tài)變量,編譯器不允許?!?/p>
“然后在靜態(tài)方法中訪問非靜態(tài)方法,編譯器同樣不允許?!?/p>
“關于靜態(tài)方法的使用,這下清楚了吧,三妹?”
看著三妹點點頭,我欣慰地笑了。
“哥,我想到了一個問題,為什么 main 方法是靜態(tài)的啊?”沒想到,三妹串聯(lián)知識點的功力還是不錯的。
“如果 main 方法不是靜態(tài)的,就意味著 Java 虛擬機在執(zhí)行的時候需要先創(chuàng)建一個對象才能調用 main 方法,而 main 方法作為程序的入口,創(chuàng)建一個額外的對象顯得非常多余?!蔽也患偎妓鞯幕卮鹆钊酶械椒浅5臍J佩。
“java.lang.Math 類的幾乎所有方法都是靜態(tài)的,可以直接通過類名來調用,不需要創(chuàng)建類的對象?!?/p>
03、靜態(tài)代碼塊
“三妹,站起來活動一下,我的脖子都有點僵硬了?!?/p>
我們一起走到窗戶邊,映入眼簾的是從天而降的雪花。三妹和我都高興壞了,迫不及待地打開窗口,伸出手去觸摸雪花的溫度,那種稍縱即逝的冰涼,真的舒服極了。
“北國風光,千里冰封,萬里雪飄。望長城內外,惟余莽莽;大河上下,頓失滔滔。山舞銀蛇,原馳蠟象,欲與天公試比高。須晴日,看紅裝素裹,分外妖嬈。。。。。?!比镁谷磺椴蛔越乩收b起了《沁園春·雪》。
確實令人欣喜,這是 2020 年洛陽的第一場雪,的確令人感到開心。
片刻之后。
“除了靜態(tài)變量和靜態(tài)方法,static 關鍵字還有一個重要的作用?!蔽倚那橛鋹偟貙θ谜f,“用一個 static 關鍵字,外加一個大括號括起來的代碼被稱為靜態(tài)代碼塊。”
“就像下面這串代碼?!?/p>
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í)行。”
“來看一下程序的輸出結果吧。”
靜態(tài)代碼塊main 方法
“二哥,既然靜態(tài)代碼塊先于 main() 方法執(zhí)行,那沒有 main() 方法的 Java 類能執(zhí)行成功嗎?”三妹的腦回路越來越令我敬佩了。
“Java 1.6 是可以的,但 Java 7 開始就無法執(zhí)行了?!蔽倚赜谐芍竦鼗卮鸬健?/p>
public class StaticBlockNoMain { static { System.out.println("靜態(tài)代碼塊,沒有 main"); }}
“在命令行中執(zhí)行 java StaticBlockNoMain 的時候,會拋出 NoClassDefFoundError 的錯誤?!?/p>
“三妹,來看下面這個例子。”
public class StaticBlockDemo { public static List
“writes 是一個靜態(tài)的 ArrayList,所以不太可能在聲明的時候完成初始化,因此需要在靜態(tài)代碼塊中完成初始化?!?/p>
“靜態(tài)代碼塊在初始集合的時候,真的非常有用。在實際的項目開發(fā)中,通常使用靜態(tài)代碼塊來加載配置文件到內存當中?!?/p>
04、靜態(tài)內部類
“三妹啊,除了以上只寫,static 還有一個不太常用的功能——靜態(tài)內部類。”
“Java 允許我們在一個類中聲明一個內部類,它提供了一種令人信服的方式,允許我們只在一個地方使用一些變量,使代碼更具有條理性和可讀性?!?/p>
“常見的內部類有四種,成員內部類、局部內部類、匿名內部類和靜態(tài)內部類,限于篇幅原因,前三種不在我們本次的討論范圍之內,以后有機會再細說。”
“來看下面這個例子。”三妹有點走神,我敲了敲她的腦袋后繼續(xù)說。
public class Singleton { private Singleton() {} private static class SingletonHolder { public static final Singleton instance = new Singleton(); } public static Singleton getInstance() { return SingletonHolder.instance; }}
“三妹,打起精神,馬上就結束了。”
“哦哦,這段代碼看起來很別致啊,哥?!?/p>
“是的,三妹,這段代碼在以后創(chuàng)建單例的時候還會見到?!?/p>
“第一次加載 Singleton 類時并不會初始化 instance,只有第一次調用 getInstance()方法時 Java 虛擬機才開始加載 SingletonHolder 并初始化 instance,這樣不僅能確保線程安全,也能保證 Singleton 類的唯一性。不過,創(chuàng)建單例更優(yōu)雅的一種方式是使用枚舉,以后再講給你聽?!?/p>
“需要注意的是。第一,靜態(tài)內部類不能訪問外部類的所有成員變量;第二,靜態(tài)內部類可以訪問外部類的所有靜態(tài)變量,包括私有靜態(tài)變量。第三,外部類不能聲明為 static?!?/p>
“三妹,你看,在 Singleton 類上加 static 后,編譯器就提示錯誤了?!?/p>
“如何掌握static關鍵字”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關的知識可以關注億速云網(wǎng)站,小編將為大家輸出更多高質量的實用文章!
免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經查實,將立刻刪除涉嫌侵權內容。