只要是有學過Java的都必定知道static,也必定能多多少少說出一些做用和注意事項。若是已經對static瞭如指掌的請點擊關閉按鈕,看下去也只是浪費您寶貴時間而已。這篇隨筆只是我的的習慣總結。java
有時候咱們並不想去new一個對象,只是單純的想要調用一個函數,而且但願這個函數不會與包含它的類的其餘對象有所關聯。說得通俗點,即便沒有建立對象,也能經過類自己來調用函數。編程
被static修飾的變量屬於類變量,經過字面意思就說明了這個變量的歸屬(類),與之相對的是沒有被static修飾的成員變量,也稱爲實例變量,說明這個變量是屬於某個具體的對象。函數
public class StaticDemo { private static int i = 50; private int j = 60; public static void main(String[] args) { StaticDemo staticDemo = new StaticDemo(); StaticDemo staticDemo1 = new StaticDemo(); //即便建立兩個對象,也都指向同一存儲空間 System.out.println(staticDemo.i); System.out.println(staticDemo1.i); //改變值 staticDemo.i = 52; System.out.println(staticDemo1.i); staticDemo.j = 65; staticDemo1.j = 70; System.out.println(staticDemo.j); System.out.println(staticDemo1.j); } }
輸出測試
50 50
52 65 70
經過上面的實例,咱們很快看出他們的區別this
說到靜態函數,就不得不提Java另外一個關鍵詞this,指的是當前的引用。意思是調用這個函數的對象,這意味着和static修飾的函數水火不容。被static修飾的函數,不能出現this關鍵字,不然便會報錯。spa
去掉this,分別調用i或者j,會發現靜態函數調用非靜態資源時出錯。這是爲何?從JVM加載機制角度來講,靜態資源(被staitc修飾)是類在初始化的時候就加載的,而非靜態資源是new的時候加載的。類的初始化是早於new的,加載了say()的函數時,它並不認識 j 這個成員變量,但對於非靜態函數來講,當它加載時,靜態資源已經加載完畢,因此它是認識 i 這個靜態資源的。咱們總結一下static修飾函數時的特色code
如今,咱們也能知道main函數爲何必須是static的,由於程序在執行main函數時候,沒有建立任何對象,只是經過類名來訪問。對象
《Java編程思想》提到「即便沒有顯示地使用static關鍵字,構造器實際上也是靜態方法」。我至今不能確認構造器是否是靜態函數,我的更偏向於不是。緣由待會再闡述,先看個實例blog
public class StaticTest { private static int i; private int j; public StaticTest(int i,int j)
{ this.i = i; this.j = j;
say1() } public void say1() { System.out.println("you age is" + i); System.out.println("you age is" + j); } public static void main(String[] args) { StaticTest staticTest = new StaticTest(4,5); StaticTest staticTest1 = new StaticTest(10,69); System.out.println(staticTest.i); System.out.println(staticTest.j); System.out.println(staticTest1.i); System.out.println(staticTest1.j); } }
輸出資源
you age is4
you age is5
you age is10
you age is69
10
5
10
69
實例中,確實改變了 i 的值,也符合靜態資源的定義,只有一份存儲空間。但構造器裏用了this,與我前文所說的static屬於類,不屬於任何對象,this屬於當前引用對象互相矛盾,而且構造函數還能夠調用實例函數。一臉懵逼,這也是讓我感到困惑而且認爲構造函數不是靜態函數的地方。若有周知,留言解惑,感謝。
private static int i;
static { i = 5; }
靜態塊是static的重要應用之一,無函數名、做用域、返回值以及參數,靜態代碼塊與靜態變量和靜態函數同樣,不論類被調用多少次,該區域代碼只在類初始化時第一次時執行一次,而且嚴格按照靜態資源的定義順序執行加載,與靜態函數區別在於一個主動一個被動。
{ System.out.println("我是靜態塊."); }
非靜態塊,一樣無函數名,做用域,返回值以及參數,非靜態代碼塊會在每次類被調用或者被實例化時執行。
public class StaticTest extends Father { public StaticTest() { System.out.println("我是StaticTest的構造函數"); } { System.out.println("我是StaticTest的非靜態塊"); } static { System.out.println("我是StaticTest的靜態塊"); } public static void main(String[] args) { new StaticTest(); new StaticTest(); } } class Father { public Father() { System.out.println("我是Father構造函數"); } { System.out.println("我是Father非靜態塊1"); } { System.out.println("我是Father非靜態塊2"); } static { System.out.println("我是Father靜態塊"); } }
輸出
我是Father靜態塊
我是StaticTest的靜態塊
我是Father非靜態塊1
我是Father非靜態塊2
我是Father構造函數
我是StaticTest的非靜態塊
我是StaticTest的構造函數
我是Father非靜態塊1
我是Father非靜態塊2
我是Father構造函數
我是StaticTest的非靜態塊
我是StaticTest的構造函數
加載順序 :父類靜態塊 > 子類靜態塊 > 父類非靜態塊 > 父類構造函數 > 子類非靜態塊 > 子類構造函數
靜態代碼塊以及非靜態代碼塊都會在構造函數前執行,首次訪問時,靜態代碼塊會在非靜態代碼塊前執行。
改變main函數
public static void main(String[] args) { }
輸出
我是Father靜態塊
我是StaticTest的靜態塊
靜態代碼塊在類加載時自動執行,非靜態代碼塊是在建立對象時自動執行的代碼,不建立對象不執行該類的非靜態代碼塊。
靜態導入是jdk5引入的新特性,有時咱們在實際應用中,並不須要整個jar包都導入,而只是想使用某部分函數。提升代碼的閱讀性,更好的理解程序。
import static java.lang.System.out; public class StaticTest { public static void main(String[] args) { out.println("import static測試");
System.out.println("import static測試");
}
}
輸出
import static測試 import static測試
會發現,二者輸出是沒有區別的,可是咱們少寫了System. 雖然容許這麼使用,但在實際開發中,我不多發現有同事這麼作,主要是不利於理解,但好處是若是頻繁用這個類,能夠少不少的類名。
===============================================================
如發現錯誤,請及時留言,lz及時修改,避免誤導後來者。感謝!!!