這是我參與8月更文挑戰的第6天,活動詳情查看:8月更文挑戰java
接上篇Java-static關鍵字(上),今兒繼續寫完,這篇文章主要內容以下:程序員
靜態代碼塊的語法格式是這樣的:markdown
類{
//靜態代碼塊
static{
java語句;
}
}
複製代碼
靜態代碼塊在類加載時執行,而且只執行一次。開發中使用很少,但離了它有的時候還真是無法寫代碼。工具
靜態代碼塊其實是java語言爲程序員準備的一個特殊的時刻,這個時刻就是類加載時刻,若是你想在類加載的時候執行一段代碼,那麼這段代碼就有的放矢了。post
例如咱們要在類加載的時候解析某個文件,而且要求該文件只解析一次,那麼此時就能夠把解析該文件的代碼寫到靜態代碼塊當中了。測試
咱們來測試一下靜態代碼塊:this
public class StaticTest01 {
//靜態代碼塊
static{
System.out.println(2);
}
//靜態代碼塊
static{
System.out.println(1);
}
//main方法
public static void main(String[] args) {
System.out.println("main execute!");
}
//靜態代碼塊
static{
System.out.println(0);
}
}
複製代碼
運行結果以下圖所示:spa
圖1:靜態代碼塊運行結果設計
經過以上的測試能夠得知一個類當中能夠編寫多個靜態代碼塊(儘管大部分狀況下只編寫一個),而且靜態代碼塊遵循自上而下的順序依次執行,因此有的時候放在類體當中的代碼是有執行順序的(大部分狀況下類體當中的代碼沒有順序要求,方法體當中的代碼是有順序要求的,方法體當中的代碼必須遵照自上而下的順序依次逐行執行),另外靜態代碼塊當中的代碼在main方法執行以前執行,這是由於靜態代碼塊在類加載時執行,而且只執行一次。code
再來看一下如下代碼:
public class StaticTest02 {
int i = 100;
static{
System.out.println(i);
}
}
複製代碼
編譯結果以下圖所示:
圖2:靜態代碼塊中訪問實例變量編譯報錯
爲何編譯報錯呢?
那是由於i變量是實例變量,實例變量必須先建立對象才能訪問,靜態代碼塊在類加載時執行,這個時候對象尚未建立呢,因此i變量在這裏是不能這樣訪問的。能夠考慮在i變量前添加static,這樣i變量就變成靜態變量了,靜態變量訪問時不須要建立對象,直接經過「類」便可訪問,例如如下代碼:
public class StaticTest02 {
static int i = 100;
static{
System.out.println("靜態變量i = " + i);
}
public static void main(String[] args) {
}
}
複製代碼
運行結果以下圖所示:
圖3:靜態代碼塊中訪問靜態變量
代碼修改成這樣呢?
public class StaticTest02 {
static{
System.out.println("靜態變量i = " + i);
}
static int i = 100;
}
複製代碼
編譯報錯了,請看下圖:
圖4:編譯報錯信息
經過測試,能夠看到有的時候類體當中的代碼也是有順序要求的(類體當中定義兩個獨立的方法,這兩個方法是沒有前後順序要求的),靜態代碼塊在類加載時執行,靜態變量在類加載時初始化,它們在同一時間發生,因此必然會有順序要求,若是在靜態代碼塊中要訪問i變量,那麼i變量必須放到靜態代碼塊以前。
方法在什麼狀況下會聲明爲靜態的呢?方法實際上描述的是行爲動做,我認爲當某個動做在觸發的時候須要對象的參與,這個方法應該定義爲實例方法,例如:每一個玩籃球的人都會打籃球,可是你打籃球和科比打籃球最終的效果是不同的,顯然打籃球這個動做存在對象差別化,該方法應該定義爲實例方法。
再如:每一個高中生都有考試的行爲,可是你考試和學霸考試最終的結果是不同的,一個上了「家裏蹲大學」,一個上了「清華大學」,顯然這個動做也是須要對象參與才能完成的,因此考試這個方法應該定義爲實例方法。
以上描述是從設計思想角度出發來進行選擇,其實也能夠從代碼的角度來進行判斷,當方法體中須要直接訪問當前對象的實例變量或者實例方法的時候,該方法必須定義爲實例方法,由於只有實例方法中才有this,靜態方法中不存在this。
請看代碼:
public class Customer {
String name;
public Customer(String name){
this.name = name;
}
public void shopping(){
//直接訪問當前對象的name
System.out.println(name + "正在選購商品!");
//繼續讓當前對象去支付
pay();
}
public void pay(){
System.out.println(name + "正在支付!");
}
}
複製代碼
public class CustomerTest {
public static void main(String[] args) {
Customer jack = new Customer("jack");
jack.shopping();
Customer rose = new Customer("rose");
rose.shopping();
}
}
複製代碼
運行結果以下圖所示:
圖5:運行結果
在以上的代碼中,不一樣的客戶購物,最終的效果都不一樣,另外在shopping()
方法中訪問了當前對象的實例變量name
,以及調用了實例方法pay()
,因此shopping()
方法不能定義爲靜態方法,必須聲明爲實例方法。
另外,在實際的開發中,「工具類」當中的方法通常定義爲靜態方法,由於工具類就是爲了方便你們的使用,將方法定義爲靜態方法,比較方便調用,不須要建立對象,直接使用類名就能夠訪問。
請看如下工具類,爲了簡化「System.out.println();
」代碼而編寫的工具類:
public class U {
public static void p(int data){
System.out.println(data);
}
public static void p(long data){
System.out.println(data);
}
public static void p(float data){
System.out.println(data);
}
public static void p(double data){
System.out.println(data);
}
public static void p(boolean data){
System.out.println(data);
}
public static void p(char data){
System.out.println(data);
}
public static void p(String data){
System.out.println(data);
}
}
複製代碼
運行結果以下圖所示:
圖6:測試工具類