static關鍵字一直是各大企業中面試經常會問到的問題,主要考察面試者的基礎是否紮實,下面來介紹一下static關鍵字。java
Java中static表示「全局」或者「靜態」的意思,能夠用來修飾成員變量、成員方法、代碼塊、內部類和導包。在Java中並不存在全局變量的概念,可是咱們能夠經過static來實現一個「僞全局」的概念,被static修飾的成員變量和成員方法獨立於該類的任何對象。也就是說,它不依賴類特定的實例,被類的全部實例共享。只要這個類被加載了,Java虛擬機就能根據類名在運行時數據區的方法區內定找到他們。所以,static對象能夠在它的任何對象建立以前訪問,無需引用任何對象,因此被static修飾的成員變量和成員方法能夠直接使用類名調用。面試
class Person{ private static int num=0; public Person() { num++; } public static void plus(){ System.out.println(Person.num); } public static void main(String[] args) { new Person(); new Person(); Person.plus(); plus(); } } //結果:二、2
static修飾的成員變量稱做靜態變量,靜態變量被全部的對象所共享,在內存中只有一個,它會隨着類的加載而加載。工具
另外主要:static是不容許用來修飾局部變量。this
提到靜態變量咱們來看靜態變量和非靜態變量的區別:spa
靜態變量(類變量):靜態變量被全部的對象所共享,也就是說咱們建立了一個類的多個對象,多個對象共享着一個靜態變量,若是咱們修改了靜態變量的值,那麼其餘對象的靜態變量也會隨之修改。3d
非靜態變量(實例變量):若是咱們建立了一個類的多個對象,那麼每一個對象都有它本身該有的非靜態變量。當你修改其中一個對象中的非靜態變量時,不會引發其餘對象非靜態變量值得改變。code
class Person{ private static int num; private int num1; public static void main(String[] args) { Person p1 = new Person(); Person p2 = new Person(); Person.num=10; p1.num1=11; Person.num=100; p2.num1=111; System.out.println(Person.num); System.out.println(p1.num); System.out.println(p2.num); System.out.println(p1.num1); System.out.println(p2.num1); } }
從運行結果來看,static變量的值是相同的,說明是共享的,而非靜態變量他們的值則不相同,說明依賴於實例。雖然static修飾的變量它不依賴類特定的實例,但它畢竟也是類中的一個屬性,也是能夠經過類的實例來調用的,只不過屬性的值是共享的而已。可是最好仍是用類名調用。對象
static修飾的成員方法稱做靜態方法,這樣咱們就能夠經過「類名. 方法名」進行調用。因爲靜態方法在類加載的時候就存在了,因此它不依賴於任何對象的實例就能夠進行調用,所以對於靜態方法而言,是木有當前對象的概念,即沒有this、super關鍵字的。由於static方法獨立於任何實例,所以static方法必須被實現,而不能是抽象的abstract。blog
而且因爲獨立於任何實例,在靜態方法中不能訪問類的非靜態成員變量和非靜態成員方法,由於非靜態成員方法/變量都是必須依賴具體的對象纔可以被調用。可是要注意的是,雖然在靜態方法中不能訪問非靜態成員方法和非靜態成員變量,可是在非靜態成員方法中是能夠訪問靜態成員方法/變量的。舉個簡單的例子:繼承
class Person{ public static void main(String[] args) { Person p=new Person(); p.show1(); } public void show1(){ System.out.println("非靜態方法show1()..."); show2(); show3(); } public static void show2(){ System.out.println("靜態方法show2()..."); //這裏編譯會報錯Non-static method 'show1()' cannot be referenced from a static context //show1(); } public static void show3(){ System.out.println("靜態方法show3()..."); show2(); } }
被static修飾的代碼塊也叫靜態代碼塊,會隨着JVM加載類的時候而加載這些靜態代碼塊,而且會自動執行。它們能夠有多個,能夠存在於該類的任何地方。JVM會按照它們的前後順序依次執行它們,並且每一個靜態代碼塊只會被初始化一次,不會進行屢次初始化。
示例:
public class Person{ static { System.out.println("Person類靜態塊"); } public Person() { System.out.println("Person類構造器"); } public static void main(String[] args) { new Son(); System.out.println("-------"); new Son(); } } class Son extends Person{ static { System.out.println("Son類靜態塊"); } public Son() { System.out.println("Son類構造器"); } }
運行結果:
從運行結果分析:首先運行main()方法,而後JVM就會加載類,由於Son類繼承了Person類,因此會先加載父類Person類,再去加載子類Son。因爲靜態代碼塊會隨着類的加載而加載,因此先輸出父類中靜態代碼塊內容"Person類靜態塊",而後輸出子類中靜態代碼塊內容"Son類靜態塊"。加載完類以後執行main()方法內容,先new了第一個Son實例,因爲子類構造器中默認調用了super(),因此先輸出父類構造器的內容,再輸出子類構造器的內容。以後又new了第二個Son實例,倒是輸出的構造器的內容,說明static靜態塊只加載了一次。結論:靜態代碼塊是先加載父類的靜態代碼塊,而後再加載子類靜態代碼塊,是隨着類的加載而加載,並且只會加載一次。
補充:由於入口main()是個方法,也須要用類去調用,因此類的加載優先級>main()方法。
static修飾內部類的用法不多,畢竟內部類用的就不是不少,通常在源碼中才能看見。可是就是有這麼一個特殊的用法是用static修飾內部類。普通類是不容許聲明爲靜態的,只要內部類才能夠,被static修飾的內部類能夠直接做爲一個普通類來使用,而不需先實例一個外部類。
static修飾內部類注意幾點:
簡單舉例:
public class OuterClass { private static int num=6; // 靜態內部類 public static class InnerStaticClass{ public void print() { System.out.println("靜態內部類方法print()=="+num); } } //非靜態內部類 public class InnerClass{ public void display(){ System.out.println("非靜態內部類方法display()=="+num); show(); } } public void show(){ System.out.println("外部類的show()方法=="+num); } public static void main(String[] args) { //非static對象實例 OuterClass outer = new OuterClass(); OuterClass.InnerClass innerClass = outer.new InnerClass(); innerClass.display(); //static對象實例 OuterClass.InnerStaticClass staticClass=new OuterClass.InnerStaticClass(); staticClass.print(); } }
這個知識點很是的冷門,基本上不多的地方會用,咱們只須要了解一下便可,用static修飾導包的格式是 import static 包名,static不能寫在import前面,這樣能夠指定導入某個類中的指定靜態資源,而且不須要使用類名.資源名,能夠直接使用資源名。
來看一下案例:
import static java.lang.Math.*; public class StaticTest { public static void main(String[] args) { System.out.println(sqrt(9)); System.out.println(abs(-12)); } } //結果:三、12
從上面的案例看出,使用import static咱們導入了Math類下的全部靜態資,因此咱們就能夠直接使用sqrt(9)、abs(-12)靜態方法了。
這樣在寫代碼的時候確實能省一點代碼,可是會影響代碼可讀性,因此通常狀況下不建議這麼使用。
static是很是重要的一個關鍵字,它的用法也很豐富,如下總結爲:
①、static能夠用來修飾成員變量、成員方法、代碼塊、內部類和導包。
②、用來修飾成員變量,將其變爲靜態變量,從而實現全部對象對於該成員的共享,經過「類名.變量名」便可調用。
③、用來修飾成員方法,將其變爲靜態方法,能夠直接使用「類名.方法名」的方式調用,經常使用於工具類。
④、靜態方法中不能使用關鍵字this和super 。
⑤、靜態塊用法,將多個類成員放在一塊兒初始化,使得程序更加規整,其中理解對象的初始化過程很是關鍵。
⑥、靜態代碼塊是先加載父類的靜態代碼塊,而後再加載子類靜態代碼塊,並且只會加載一次。
⑦、static修飾成員變量、成員方法、代碼塊會隨着類的加載而加載。
⑧、靜態導包用法,將類的方法直接導入到當前類中,從而直接使用「方法名」便可調用類方法,更加方便,可是代碼的可讀性下降。