Java中的static關鍵字淺析
- 2020 年 3 月 18 日
- 筆記
這是我結合一些自己的思想寫的對static關鍵字的理解。
1. static關鍵字
【重點】他是單身狗!!!
1.1 static修飾成員變量
1.1.1 static修飾成員變量的需求

「這裡不希望大量的數據浪費」,打錯字了,在這裡糾正一下。
數據區也可以叫做共享區,是一個公共資源的放置地方。
static可以節省大量的冗餘空間,堆區的String country指向數據區的首地址,類似於棧區指向於堆區。
1.1.2 靜態成員變量使用注意事項
- 靜態成員變量是使用static修飾的成員變量,定義在內存的【數據區】
- 靜態成員變量不推薦使用類對象調用,會提示警告 The static field SingleDog.info should be accessed in a static way 使用static修飾的SingleDog類內的info成員變量,應該通過靜態方式訪問. 強烈不推薦通過對象調用,推薦通過類名調用!!! 知道為啥嗎?因為static修飾的成員變量是個單身狗!!! 你用你的對象來找饑渴的單身狗修電腦,你願意嗎???人家單身狗願意嗎???
- 靜態成員變量使用類名調用是沒有任何的問題。【牆裂推薦方式】 但是!!!你通過找電腦店,或者找售後,這個大的一個類,雖然給你對象修電腦的還是一個單身狗,但是人家願意修…
- 在代碼中沒有創建對象時,可以通過類名直接使用靜態成員變量,和【對象無關】 這句話什麼意思呢?就是說雖然static是單身狗,但是人家也是有追求的,即使沒有對象,人家也是要恰飯的!!!
- 代碼中對象已經被JVM的GC銷毀時,依然可以通過類名調用靜態成員變量,和【對象無關】 這句話不用我多說什麼了吧?相信你們已經可以看出來了,這static丫的是個直男!!! static是個直男單身狗!!!和對象無關!!!
- 不管通過哪一種方式調用靜態成員變量,修改對應的靜態成員變量數據,所有使用到當前靜態成員變量的位置,都會受到影響。 一旦單身狗受到刺激或者改變,那麼他周圍的一切都會影響。
好了,經過上面的腦補後,相信static的形象已經深入人心,下邊我們來認真了解一下為什麼靜態成員變量和對象無關…
1.1.3 為什麼靜態成員變量和對象無關
- 從內存角度出發分析 靜態成員變量是保存在內存的數據區 類對象佔用的實際內存空間是在內存的堆區 這兩個區域是完全不同的,所有可以說靜態成員變量和對象沒有關係 【沒有對象】 這叫啥?天各一方!!!君住長江頭,我住長江尾!!!
- 從靜態成員變量以及類對象生命周期來分析 靜態成員變量是隨着類文件(.class) 位元組碼文件的加載過程中,直接定義在內存的數據區。靜態成員變量從程序運行開始就已經存在。 類對象是在代碼的運行過程中,有可能被創建,也有可能不被創建的。程序的運行過中,有可能會被JVM的CG垃圾回收機制銷毀,程序在退出之前一定會銷毀掉當前Java程序使用到的所有內存。 而靜態成員變量在程序退出之後,才會銷毀 靜態成員變量的生命周期是從程序開始,到程序結束 類對象只是從創建開始,而且隨時有可能被JVM的GC銷毀 生命周期不在同一個時間線上,所以靜態成員變量和類對象無關,【沒有對象】 唉…可悲可嘆,我(static)生君(對象)未生,我(static)生君(對象)已老!!! 我就像一粒原子,世界創立時我已存在,經歷世間波瀾壯闊,沉沉浮浮數萬億年; 而你,一個美麗的女子,你需要我時,我就在你身邊任你使用,你不需要我時,我就靜靜待在這世界中看着你。 我的生命與世界相同,而你的出現卻不是定數,即使有那造物主的憐惜,讓你出現數十年,卻也只相當於我生命的億萬分之一,你不在後,我還要在沒有你的世界裏待到末日…
代碼展示
/* * 演示static關鍵字修飾成員變量 */ class SingleDog { // static修飾的靜態成員變量 public static String info = "單身狗"; // 非靜態成員變量 public String name; public SingleDog() {} public SingleDog(String name) { this.name = name; } // 非靜態成員方法 public void test() { System.out.println("test方法"); } } public class Demo2 { public static void main(String[] args) { // 在沒有類對象的情況下,可以直接通過類名調用靜態成員變量 System.out.println(SingleDog.info); // 曾經有過一個對象,31行代碼運行完成,對象銷毀 new SingleDog(); // 在類對象被銷毀之後,依然可以通過類名調用靜態成員變量 System.out.println(SingleDog.info); } }
1.2 static修飾成員方法
1.2.1 靜態成員方法的格式
異常熟悉的格式
public static 返回值類型 方法名(形式參數列表) {
}
1.2.2 靜態成員方法注意事項 【FFF社】
靜態成員方法就是我大FFF社!!!
- 靜態成員方法推薦使用靜態方式調用,通過類名調用【牆裂推薦的】 不推薦使用類對象調用,因為【沒有對象】 不用我解釋了吧…
- 靜態成員方法中不能使用非靜態成員 ==> (非靜態成員方法和非靜態成員變量) 因為【沒有對象】 嘿嘿嘿,FFF社…
- 靜態成員方法中不能使用this關鍵字 回顧:this表示調用當前方法的類對象 因為靜態方法中【沒有對象】 so…
- 靜態成員方法中可以使用類內的其他靜態成員【難兄難弟】 大FFF社員
- 靜態成員方法中可以通過new 構造方法創建對象 大FFF社不燒真愛!!!
1.2.3 靜態成員方法特徵解釋
- 靜態成員方法加載時間問題 靜態成員方法是隨着.class位元組碼文件的加載而直接定義在內存的【方法區】,而且此時的靜態成員方法已經可以直接運行。可以通過類名直接調用,而此時沒有對象存在。【沒有對象】
- 為什麼靜態成員方法不能使用非靜態成員 非靜態成員變量和非靜態成員方法時需要類對象調用的,在靜態成員方法中,是可以通過類名直接執行的,而此時是【沒有對象】的。
- 為什麼靜態成員方法不能使用this關鍵字 this關鍵字表示的是調用當前方法的類對象,但是靜態成員方法可以通過類名調用,this不能代表類名,同時也是【沒有對象】
- 靜態成員方法可以使用其他靜態成員 生命周期一致,調用方式一致
1.3 類變量和類方法
類變量 ==> 靜態成員變量 類方法 ==> 靜態成員方法 類成員 ==> 靜態成員變量和靜態成員方法
面試題 類方法中是否可以使用成員變量? 類方法可以使用當前類內的靜態成員變量,但是不允許使用非靜態成員變量
1.4 靜態代碼塊
補充知識點 代碼塊
構造代碼塊(動態代碼塊) 初始化當前類的所有類對象,只要調用構造方法,【一定】會執行對應的構造代碼塊
執行順序【成員變量之後 構造方法之前】 格式 { }
靜態代碼塊 初始化程序,只要類文件加載,靜態代碼塊中所有內容全部執行
格式: static { // 靜態代碼塊 }
只要【類文件】加載,當前靜態代碼塊中的內容就一定會執行,並且有且只【執行一次】。 注意: 是.class文件加載,不是文件加載,如果主類中沒有用到這個類,那麼就不會加載這個類中的靜態代碼塊。
作用:整個類的初始化過程
局部代碼塊 提高效率,解決內存,讓JVM回收內存的效率提升。
for () { { int num } }
1.5 靜態題
public class Demo3 { static Demo3 demo1 = new Demo3(); static Demo3 demo2 = new Demo3(); { System.out.println("構造代碼塊"); // 1 } static { System.out.println("靜態代碼塊"); // 2 } public Demo3() { System.out.println("構造方法"); // 3 } public static void main(String[] args) { Demo3 demo1 = new Demo3(); } }
請問輸出結果應該是什麼呢?做題,不是寫代碼實踐,思考…
答案:
//答案 /* 構造代碼塊 構造方法 構造代碼塊 構造方法 靜態代碼塊 構造代碼塊 構造方法 */ //解釋 //首先代碼執行static Demo3 demo1 = new Demo3(); 是new一個對象,是new構造方法,所以執行 //構造代碼塊和構造方法 //然後執行static Demo3 demo2 = new Demo3();是new一個對象,是new構造方法,所以執行 //構造代碼塊和構造方法 //然後執行 static { System.out.println("靜態代碼塊"); // 2 } //然後執行 public static void main(String[] args) { Demo3 demo1 = new Demo3(); } //又是創建新的類對象,所以執行構造代碼塊和構造方法
那麼接下來我們將上邊兩個代碼去掉static,結果會怎樣? 如下:
public class Demo3 { Demo3 demo1 = new Demo3(); Demo3 demo2 = new Demo3(); { System.out.println("構造代碼塊"); // 1 } static { System.out.println("靜態代碼塊"); // 2 } public Demo3() { System.out.println("構造方法"); // 3 } public static void main(String[] args) { Demo3 demo1 = new Demo3(); } }
結果:
執行「靜態代碼塊」 無限遞歸,棧堆內存滿,報錯