夯實Java基礎(七)——static關鍵字

一、static介紹

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修飾的成員變量稱做靜態變量,靜態變量被全部的對象所共享,在內存中只有一個,它會隨着類的加載而加載。工具

另外主要: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方法

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代碼塊

被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修飾的內部類能夠直接做爲一個普通類來使用,而不需先實例一個外部類。

static修飾內部類注意幾點:

  • 靜態內部類只能訪問外部類的靜態成員,不然編譯會報錯。
  • 不論是靜態方法仍是非靜態方法均可以在非靜態內部類中訪問。
  • 若是須要調用內部類的非靜態方法,必須先new一個OuterClass的對象outerClass,而後經過outer。new生成內部類的對象,而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導包

這個知識點很是的冷門,基本上不多的地方會用,咱們只須要了解一下便可,用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修飾成員變量、成員方法、代碼塊會隨着類的加載而加載。

⑧、靜態導包用法,將類的方法直接導入到當前類中,從而直接使用「方法名」便可調用類方法,更加方便,可是代碼的可讀性下降。

相關文章
相關標籤/搜索