Java中的static關鍵字淺析

這是我結合一些自己的思想寫的對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();
    }
    
}

結果:

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章