這是我結合一些自己的思想寫的對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();
}
}
複制
結果:
執行“靜态代碼塊”
無限遞歸,棧堆記憶體滿,報錯