標籤:代碼 固定 完成 大致 為什麼 mes 協助 理解 載入完成
一、 static的用途
在Java編程思想中有這麼一句話:“static方法就是沒有this的方法。在static方法內部不能調用非靜態方法,反過來是可以的。而且可以在沒有建立任何對象的前提下,僅僅通過類本身來調用static方法。這實際上正是static方法的主要用途”
這句話在我理解來說就相當於是static方法是屬於類的,而非靜態方法是屬於對象的。在實際應用中就相當於非靜態方法只有在new出相應的對象來才能調用,而靜態方法只需要’類名.方法’即可調用。
在什麼情況下我們需要使用static關鍵字呢?
a、 對於一個類相對固定的一些參數及方法
b、 一些需要預先定義的參數及方法
c、 一些調用廣泛的公用參數及方法
在我看來static關鍵字的核心是避免一些記憶體的重複佔用,我們想象一個java工程在開始運行時,會通過jvm分配一片空間,在這一片空間中會積極式載入所有需要的類,然後就是我們在new對象時不停的佔據記憶體。但是例如枚舉類(之後稱為Contact類)中的參數是會在其他很多個物件和函數中調用,如果我們每次調用的時候都需要重新new一個Contact對象,豈不是會在記憶體中重複佔用非常多的資源。這時我們就需要static關鍵字修飾Contact類中的參數,這樣在我們積極式載入所有的類時,Contact類中通過static修飾的參數就會隨著Contact類一起被載入在記憶體中,在我們需要的時候就可以直接通過Contact.參數名來調用這個參數而不需要重複佔用另外的記憶體。(如果在面試中剛好被問到了,答出來應該會很加分的)
1、 修飾類變數
static變數一般也被稱為靜態變數,靜態變數和非靜態變數的區別是:靜態變數被所有的對象所共用,在記憶體中只有一個副本,它若且唯若在類初次載入時會被初始化。而非靜態變數是對象所擁有的,在建立對象的時候被初始化,存在多個副本,各個對象擁有的副本互不影響。
static成員變數的初始化順序按照定義的順序進行初始化。
接下來舉例說明:
這是一個基本的Man類,並產生了兩個對象,但是從類的定義上來看,我們可以認為sex參數的值固定為男,但產生了兩個對象就相當於在記憶體在將sex參數儲存了兩遍,這無疑是一種記憶體上的浪費。而這時我們給sex參數加上static關鍵字會變成什麼樣呢?
我們只需要給Man類中的sex參數賦值就會使所有的Man對象sex值進行改變。
雖然sex參數成為了Man類的共用屬性,但是實際中我們很少這麼使用,因為這樣會使得該參數很難控制,因為它在任何地方都可能被改變。所以我們一般採用其他的使用方法:
通過private+static修飾count屬性,並在Man的建構函式中對Man對象的數量進行統計並賦值給id屬性來區分不同的Man對象。並且因為private修飾外界無法隨意更改count和id參數。
2、 修飾類方法
與靜態參數使用情境基本相同,但是需要注意的是,同一個類,靜態方法中無法直接調用非靜態參數及非靜態方法,但非靜態方法中可以直接調用靜態方法及靜態參數。
3、 靜態代碼塊
靜態代碼塊主要作用是在類載入之前進行一些資料的處理,對需要參數或對象的初始化。保證接下來對該參數或對象的使用。
這個例子就大致展現出了靜態代碼塊的一些基本的作用,另外我們可以看看這個例子,展現了靜態代碼塊和對象初始化時的載入順序:
4、 靜態導包
靜態導包是一種比較少見是static使用方式,接下來使用一個例子來說明一下吧:
,當我們使用import static staticpkg.Man.*;時,在不與本類方法名衝突的前提下,我們可以在本類中直接使用Man類中的static方法,就像是本類自己的方法一樣。但是相應的其他靜態參數和一下非靜態參數和非靜態方法就無法直接調用了。
二、 static作用分析
1、 之前說了static是跟隨著類進行載入的,那麼我們是否能通過this來進行靜態參數的調用呢?
我們可以看到雖然靜態參數是隨著類進行載入的,但是在參數名有衝突的情況下依然可以通過this來進行參數調用,以此區分全域變數和局部變數的不同。
2、 static是跟跟隨著類進行載入的,那麼伴隨著類、基礎、對象的初始化過程中相應的載入順序是怎樣的?
舉例1:
這兩段代碼的輸出結果會是怎樣的?
我們說了static是跟著類一起進行載入的,那麼我們在new Test3()時會載入Test3類這時發現Test3繼承Test2那麼我們需要先載入Test2類的靜態代碼塊,再載入Test3類的靜態代碼塊。類載入完成後我們開始通過Test3提供的構造器來今天Test3對象的初始化,而因為Test3繼承了Test2所以在編譯時間預設Test3的構造器中有一個super()的調用,意思就是先載入Test2的構造器再載入Test3的構造器。所以這兩段的代碼的輸出結果如下:
舉例2:
這三段代碼的載入順序又應該是怎樣的呢?
首先和舉例1一樣main函數中載入Test3類,但是因為繼承Test2所以先載入Test2類的靜態代碼塊,然後是Test3的靜態代碼塊,然後開始載入Test3的建構函式了,同樣因為繼承需要先載入Test2的建構函式,但是需要初始化Test2對象時需要將Test2類中的全域變數進行逐行載入,這時我們就需要載入new Test4(“test22222222”),這時就需要載入Test4類了,執行Test4類的靜態代碼塊,然後執行Test4的構造器,Test4對象載入完成,進行Test2類的構造器載入,然後到了Test3類構造器載入,同上需要先載入Test4類,因為Test4類的靜態代碼塊已經載入完成無需重複載入,所以載入Test4的構造器,然後載入Test3的構造器,所以這三段代碼的輸出結果應為:
舉例3:
Main函數中明明什麼都沒寫為什麼還是會列印呢?
因為在載入main函數時,會先對Test5類進行逐行載入,這時會從上到下依次載入兩個靜態代碼塊,載入完成後,本類載入完成開始執行main函數中的代碼,結果main函數中沒有代碼,程式結束。
以上是我對static的一些基本的認知,希望能對你有所協助,代碼依然是圖片,代碼還是手敲一遍試一下更有感覺的。
參考部落格:
https://www.cnblogs.com/dotgua/p/6354151.html?utm_source=itdadao&utm_medium=referral
http://www.cnblogs.com/dolphin0520/p/3799052.html
Java static基本認知