天天看點

Java中的static關鍵字淺析

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

1. static關鍵字

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

1.1 static修飾成員變量

1.1.1 static修飾成員變量的需求
Java中的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();
    }
    
}           

複制

結果:

執行“靜态代碼塊”

無限遞歸,棧堆記憶體滿,報錯