Java中的static關鍵字淺析

  • 2020 年 3 月 18 日
  • 筆記

這是我結合一些自己的思想寫的對static關鍵字的理解。

1. static關鍵字

【重點】他是單身狗!!!

1.1 static修飾成員變量

1.1.1 static修飾成員變量的需求

「這裡不希望大量的數據浪費」,打錯字了,在這裡糾正一下。

數據區也可以叫做共享區,是一個公共資源的放置地方。

static可以節省大量的冗餘空間,堆區的String country指向數據區的首地址,類似於棧區指向於堆區。

1.1.2 靜態成員變量使用注意事項
  1. 靜態成員變量是使用static修飾的成員變量,定義在內存的【數據區】
  2. 靜態成員變量不推薦使用類對象調用,會提示警告 The static field SingleDog.info should be accessed in a static way 使用static修飾的SingleDog類內的info成員變量,應該通過靜態方式訪問. 強烈不推薦通過對象調用,推薦通過類名調用!!! 知道為啥嗎?因為static修飾的成員變量是個單身狗!!! 你用你的對象來找饑渴的單身狗修電腦,你願意嗎???人家單身狗願意嗎???
  3. 靜態成員變量使用類名調用是沒有任何的問題。【牆裂推薦方式】 但是!!!你通過找電腦店,或者找售後,這個大的一個類,雖然給你對象修電腦的還是一個單身狗,但是人家願意修…
  4. 在代碼中沒有創建對象時,可以通過類名直接使用靜態成員變量,和【對象無關】 這句話什麼意思呢?就是說雖然static是單身狗,但是人家也是有追求的,即使沒有對象,人家也是要恰飯的!!!
  5. 代碼中對象已經被JVM的GC銷毀時,依然可以通過類名調用靜態成員變量,和【對象無關】 這句話不用我多說什麼了吧?相信你們已經可以看出來了,這static丫的是個直男!!! static是個直男單身狗!!!和對象無關!!!
  6. 不管通過哪一種方式調用靜態成員變量,修改對應的靜態成員變量數據,所有使用到當前靜態成員變量的位置,都會受到影響。 一旦單身狗受到刺激或者改變,那麼他周圍的一切都會影響。

好了,經過上面的腦補後,相信static的形象已經深入人心,下邊我們來認真了解一下為什麼靜態成員變量和對象無關…

1.1.3 為什麼靜態成員變量和對象無關
  1. 從內存角度出發分析 靜態成員變量是保存在內存的數據區 類對象佔用的實際內存空間是在內存的堆區 這兩個區域是完全不同的,所有可以說靜態成員變量和對象沒有關係 【沒有對象】 這叫啥?天各一方!!!君住長江頭,我住長江尾!!!
  2. 從靜態成員變量以及類對象生命周期來分析 靜態成員變量是隨着類文件(.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社!!!

  1. 靜態成員方法推薦使用靜態方式調用,通過類名調用【牆裂推薦的】 不推薦使用類對象調用,因為【沒有對象】 不用我解釋了吧…
  2. 靜態成員方法中不能使用非靜態成員 ==> (非靜態成員方法和非靜態成員變量) 因為【沒有對象】 嘿嘿嘿,FFF社…
  3. 靜態成員方法中不能使用this關鍵字 回顧:this表示調用當前方法的類對象 因為靜態方法中【沒有對象】 so…
  4. 靜態成員方法中可以使用類內的其他靜態成員【難兄難弟】 大FFF社員
  5. 靜態成員方法中可以通過new 構造方法創建對象 大FFF社不燒真愛!!!
1.2.3 靜態成員方法特徵解釋
  1. 靜態成員方法加載時間問題 靜態成員方法是隨着.class位元組碼文件的加載而直接定義在內存的【方法區】,而且此時的靜態成員方法已經可以直接運行。可以通過類名直接調用,而此時沒有對象存在。【沒有對象】
  2. 為什麼靜態成員方法不能使用非靜態成員 非靜態成員變量和非靜態成員方法時需要類對象調用的,在靜態成員方法中,是可以通過類名直接執行的,而此時是【沒有對象】的。
  3. 為什麼靜態成員方法不能使用this關鍵字 this關鍵字表示的是調用當前方法的類對象,但是靜態成員方法可以通過類名調用,this不能代表類名,同時也是【沒有對象】
  4. 靜態成員方法可以使用其他靜態成員 生命周期一致,調用方式一致

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();      }    }

結果:

執行「靜態代碼塊」 無限遞歸,棧堆內存滿,報錯