以下程式碼與說明擷取自 JavaWorld, 並加以改編 :
 
session 1)
 
資料成員有分 static/non-static。

instance variable => non-static field(field: data member)
class variable => static field
 

class Insect
{
    int x1=prt("static Insect.x1 initialized");
 
    int prt(String s)
    {
        System.out.println(s);
        return 47;
    }
}
 
public class Beetle extends Insect
{
    public static void main(String[] args)
    {
    }
}

---------- java ----------
Normal Termination
輸出完成 (耗費 0 秒)。

 
將 x1 跟 prt() 重新改寫為 static.
 
class Insect
{
    static int x1=prt("static Insect.x1 initialized");
 
    static int prt(String s)
    {
        System.out.println(s);
        return 47;
    }
}
 
public class Beetle extends Insect
{
    public static void main(String[] args)
    {
    }
}
---------- java ----------
static Insect.x1 initialized
Normal Termination
輸出完成 (耗費 0 秒)。
 
我們可以將資料成員宣告為static,被宣告為static的資料成員,它是屬於類別所擁有,而不是個別的物件,我們可以將static視為個別物件所擁有、共享的資料成員
 
static資料與函式的作用之一,是提供公用類別函式,例如將數學常用常數或計算公式,以static宣告並撰寫,之後我們可以透過類別名稱來管理與取用這些函式,例如像Math.Exp、Math.Log()、Math.Sin()等等的static常數或函式等,事實上,像PI這個常數,在Math.PI就有定義,我們可以直接呼叫使用。
 

由於static成員是屬於類別而不是物件,所以當您呼叫static函式時,並不會傳入物件的位置參考,所以static函式中不會有this參考,由於沒有this參考,所以在Java的static函式成員中不允許使用非static成員,因為程式沒有this來參考至物件位址,也就無法辨別要存取哪一個物件的成員,事實上,如果您在static函式中使用非static資料成員,在編譯時就會出現以下的錯誤訊息:

1
non-static variable test cannot be referenced from a static context


或者是在static函式中呼叫非static函式,在編譯時就會出現以下的錯誤訊息:
1
non-static method showMe() cannot be referenced from a static context


如果以c++來說 就是固定一個記憶體位置給宣告成 static 的成員或函式,
不管你 new 幾個物件, static 的成員或函式始終指向同樣的記憶體位置,
所以當你更改 static 的成員的值時
所有 new 出來的物件中的static 的成員的值就都會變了

 

1. 最常見的就是 main(),宣告為 static 可在任何物件存在之前被呼叫
2. 在需要建立多個 class 使用的公用 method 時: 如 Math 類別,目的在公用,而不需要擁有自己的狀態,用 public static 會較方便,其它像是: java.lang.System、java.swing.SwingUtilites…等。
3. 建立只在 class 中使用的「外包工作用的 method」: 避免被一些 實體 method 任意存取 實體variable/field。因為 static method 沒有 this,不能擅自呼叫 實體method 或 實體variable。


object 以 member access operator 來 access static member,這和透過 class name 來取得 static member 兩者感覺起來一樣,但語意上不太一樣,至少對 sun 的編譯器來說是不一樣的。前者的寫法會使得 object reference 被 push 進 stack 隨即又 pop 掉,所以會平白犧牲掉一點效率,後者則不會。

 

Code Convention也不建議這麼寫
都是建議使用ClassName.staticMember

 

類別包含"資料"和"操作"(或稱方法, 函式).
當產生N個物件時, "資料"被產生N分, 但操作還是只有一份.
因此, "操作"只是被共用來操作N個物件的資料用.

問題是, "一般的操作"只有在物件產生時才可以呼叫,
而"static操作"則在物件產生前就可以呼叫.

 

(Kalin's 心得)

回歸Beetle...

第二個Beetle印出字串static Insect.x1 initialized, 那是因為執行Beetle時, 雖然在main()裡沒有做任何事, 但是Beetle extends Insect, 而prt()這個method被宣告為static , 所以在執行Beetle時會先跑base class (Insect)的prt()這個mathod.


 
session 2)
 

" base class 建構完成之後,其 instance variable(譯注:亦即資料成員,相對於 class variable)會以其出現次序被初始化 ... "

 

再次複習一下 :

instance variable => non-static field(field: data member)
class variable => static field

 
 
class Insect
{
    int i=9;
    int j;
 
    Insect()
    {
        prt("i="+i+",j="+j);
        j=39;
    }
 
    static int x1=prt("static Insect.x1 initialized");
 
    static int prt(String s)
    {
        System.out.println(s);
        return 47;
    }
}
 
public class Beetle extends Insect
{
    Beetle()
    {
        System.out.println(prt("j="+j));
    }
    public static void main(String[] args)
    {
        Beetle b = new Beetle();
    }
}
---------- java ----------
static Insect.x1 initialized
i=9,j=0
j=39
47
Normal Termination
輸出完成 (耗費 0 秒)。
 
(Kalin's 心得)
 
接上一個部份,
 
step 1 :
執行Beetle時, 會先到父類別Insect執行static method prt(), 而印出 static Insect.x1 initialized,
 
step 2 :
因為Beetle的main()裡面new了自己, 所以先去始執行父類別Insect的constructor, 印出 i=9,j=0, 然後把39給class variable j,
 
step 3 :
再接著執行自己的constructor, Beetle() 裡面是System.out.println(prt("j="+j));, 所以先執行了prt("j="+j), 所以利用了super印出了j=39, 最後執行System.out.println(prt("j="+j));, 因為Insect的prt()是return 47, 所以最後印出了47.
 

 
 
session 3)
 
最後再練習一次...
 
class Insect
{
    int i=9;
    int j;
 
    Insect()
    {
        prt("i="+i+",j="+j);
        j=39;
    }
 
    static int x1=prt("static Insect.x1 initialized");
 
    static int prt(String s)
    {
        System.out.println(s);
        return 47;
    }
}
 
public class Beetle extends Insect
{
    int k=prt("Beetle.k initialized");
    Beetle()
    {
        System.out.println(prt("k="+k));
        System.out.println(prt("j="+j));
    }
    public static void main(String[] args)
    {
        Beetle b = new Beetle();
        prt("Beetle constructor");
    }
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
---------- java ----------
static Insect.x1 initialized
i=9,j=0
Beetle.k initialized
k=47
47
j=39
47
Beetle constructor
Normal Termination
輸出完成 (耗費 0 秒)。
 
(Kalin's 心得)
 
幹! 本來是要寫作業的, 竟然花了那麼久的時間來釐清 static... 嗚~
文章標籤
全站熱搜
創作者介紹
創作者 Kalin 的頭像
Kalin

Kalin的部落格

Kalin 發表在 痞客邦 留言(1) 人氣(377)