Java基礎-static關鍵字和單例模式

正兒八經小青年就是我發表於2018-11-08

static關鍵字

  • static關鍵字的特點

    1. 用來修飾類的成員-修飾成員變數的稱之為類變數(靜態變數),修飾成員方法的稱之為類方法(靜態方法)。(屬性拿static修飾完之後就不叫屬性了,他也就不屬於任何物件了,而是屬於多個物件共享的,就叫類變數或靜態變數,方法也一樣)

    2. 當類被載入的時候就會被載入,優先於物件的存在。

    3. 用來修飾與語句塊-稱之為靜態程式碼塊。先於構造方法之前執行,只會執行一次。用來對靜態成員做初始化

    4. 靜態修飾的成員被所有的物件共享

    5. 呼叫的時候可以直接通過類名.成員來進行訪問。

  • static關鍵字注意事項

    1.靜態方法中只能訪問外部的靜態成員 (為什麼?當我們去呼叫靜態方法的時候,物件都沒產生,物件沒產生怎麼可能有屬性呢,因為屬性是屬於某個物件的對吧) 2.靜態方法中不能出現this關鍵字 (為什麼?同樣的道理,當我們去呼叫靜態方法的時候,物件都沒產生,物件沒產生this又是指誰呢?)

ok 上程式碼!

public class StaticDemo {


    public static void main(String[] args)
    {
        Device device1 = new Device();
        device1.showName();
        device1.showEnergy();
        Device device2 = new Device();
        device2.energy++;
        device2.showName();
        device2.showEnergy();
    }
}

class Device
{
    private String name="device1";//普通的屬性
    public int energy=2;//普通的屬性

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getEnergy() {
        return energy;
    }

    public void setEnergy(int energy) {
        this.energy = energy;
    }

    public void showName()
    {
        System.out.println(name);
    }

    public void showEnergy()
    {
        System.out.println(energy);
    }
}
複製程式碼

看下輸出結果:

device1
2
device1
3
複製程式碼

ok,現在分析下,我第一個物件的energy屬性初始值時2,第二個物件的energy屬性我用public修飾了,所以我直接可以呼叫下,然後加一了,列印出來的結果兩個物件是不一樣的。這就說明了什麼?每個物件都有他自己的獨立的一份屬性。對不對?~對的哈。。這句話很重要~~

那我現在如果把name這個屬性改成用static來修飾的話,現在會怎麼樣? public static String name="device1";//靜態變數,他現在不屬於任何一個物件了,被多個物件共享,他現在是屬於類的,他也稱為類變數

現在我們把呼叫方法改成這樣

public static void main(String[] args)
    {
        Device device1 = new Device();
        device1.name = "cyy";
        device1.showName();
        device1.showEnergy();
        Device device2 = new Device();
        device2.energy++;
        device2.showName();
        device2.showEnergy();
    }
複製程式碼

現在name不是個屬性了,他現在是個靜態變數,我在device1裡面把他設定成cyy,現在列印結果來看下。

cyy
2
cyy
3
複製程式碼

看到沒兩個name都變成cyy了。這說明了什麼?這是不是說明了,這個name大家都共享了呀,不再是每個物件獨立擁有的了,對吧! 那既然他都不是共享的了,那我們訪問的時候是不是就可以直接Device.name就可以了啊,因為他現在不屬於物件了,他現在屬於類的。 而age可不可以直接通過Device.age來訪問啊,當然不可以,因為他現在並不屬於類對吧。

好的,現在如果我們把一個方法改成靜態的呢,比如這樣:

public static void showName()
{
    System.out.println(energy);
    System.out.println(name);
}
複製程式碼

如果這麼寫的話,是不是會報錯呀,編譯時就會報錯,會提示: Non-static field 'energy' cannot be referenced from a static context

什麼意思?大概意思就是說,你靜態方法不能訪問非靜態變數~為什麼?!因為你靜態方法呼叫的時候,還沒有建立物件呢,人家energy是個屬性,又不是靜態變數,你會跑的時候,人家還沒出生呢,你咋能去找人家玩兒呢?對吧,所以靜態方法不能訪問非靜態變數靜態方法中不能使用this,只能訪問外部靜態的東西。

非靜態方法可不可以訪問靜態變數?思考一下?答案當然是可以的,想像一下,靜態變數在你物件建立之前就已經分配好記憶體空間了,已經存在了,你物件建立完之後,他已經存在了,所以肯定是可以訪問的,對吧。總結就是靜態的只能訪問靜態的,非靜態的都可以訪問

還有個static語句塊

他什麼時候執行呢?

在類被載入的時候就會執行,只會執行一次,用來對靜態變數進行初始化。優先於構造方法的執行。

上程式碼:

class Device
{
    public static String name;//普通的屬性
    public int energy=2;//普通的屬性

    //static語句塊
    static {

        name = "device1";
        System.out.println("===我是靜態語句塊裡的"+name);
    }

    //構造方法
    public Device(String name)
    {
        this.name = name;
        System.out.println("===我是構造方法裡的"+name);
    }


    public static void showName()
    {
        System.out.println(name);
    }

    public void showEnergy()
    {
        System.out.println(energy);
    }
}

複製程式碼

我們現在使用下:

Device device1 = new Device("cyy");
        Device device2 = new Device("cyy513");
複製程式碼

看下列印結果:

===我是靜態語句塊裡的device1
===我是構造方法裡的cyy
===我是構造方法裡的cyy513
複製程式碼

發現了吧,我new了兩個物件,但是靜態語句塊裡的system.out.println只列印了一次,說明啥static語句塊只執行一次,不管你建立多少次物件。而且我是先於構造方法執行的。

那會有人說,那我以後都不用屬性了,我全部用static變數,多好,多方便,其實這樣有很多缺點:

  • 破壞了java物件導向的封裝性
  • static變數的生命週期比較長,程式結束的時候,他的記憶體才會釋放,而屬性呢,這個物件執行完了他的屬性記憶體是不是就釋放了呀。

那我們什麼時候用static呀?

當我們一個類裡面,沒有任何屬性,只有方法 ,而這個方法是為其他的類服務的,這個時候適合用static的。

單例模式

定義:

顧名思義,單例模式的意思就是隻有一個例項,單例模式確保某一個類只有一個例項,而且自行例項化併為整個系統提供這個例項,這個類稱為單例類。

通俗的說,就是我有一個類,整個系統就一個例項,而且他是自己建立自己,他必須對外提供個方法,把我自己給你。

上程式碼:

class SingleTon
{

    private SingleTon singleTon = new SingleTon();

    /**
     * 構造方法一定不能是公開的,不然別人就可以隨便構造了。
     * 所以構造方法必須是private,對吧
     */
    private SingleTon()
    {

    }
    //如果我這麼寫,會出現什麼問題
    public static SingleTon getInstance()
    {
        return singleTon;
    }
}
複製程式碼

是不是會出現之前說的那種錯誤呀,靜態方法不能引用非靜態變數。對不對。所以要怎麼做?是不是給前面singleton加上個static就可以了是吧。因為這個SingleTon是靜態的在記憶體裡只有一份對吧~正確寫法,

class SingleTon
{

    public static SingleTon singleTon = new SingleTon();
    private SingleTon()
    {}
 
    public static SingleTon getInstance()
    {
        return singleTon;
    }
}
複製程式碼

這種方式稱之為餓漢式。為什麼?因為我在呼叫getInstance()之前這個物件是不是就已經產生了呀,因為它是靜態的嘛,在類載入時候,就已經new SingleTon()了呀。那我們現在有沒有更好的方法呢? 比如在getInstance()的時候再去建立這個物件呀?當然可以呀~這麼寫就可以了.

class SingleTon
{

    public static SingleTon singleTon = null;

    /**
     * 構造方法一定不能是公開的,不然別人就可以隨便構造了。
     * 所以構造方法必須是private,對吧
     */
    private SingleTon()
    {

    }
    //如果我這麼寫,會出現什麼問題
    public static SingleTon getInstance()
    {
        if (singleTon==null)
        {
            singleTon = new SingleTon();
        }
        return singleTon;
    }
}
複製程式碼

這種就是懶漢式載入。

不管是懶漢式還是餓漢式,是不是目的就是一個,讓他整個系統中只有一個例項。

ok,結束~ 後續我會繼續更新,Android自定義View,Android NDK,音視訊方向的文章,歡迎大家關注,共同進步。

相關文章