2010年7月21日 星期三

Java static 之一

===== Javaworld TW, adoo 大大 ======

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


===== Java Gossip: 關 於 static 成員=====
(http://caterpillar.onlyfun.net/Gossip/JavaGossip-V1/AboutStaticMember.htm)

對於每一個基於相同類別所產生的物件而言,其擁有各自的資料成員,然而在某些時候,您會想要這些物件擁有相同的資料成員,其資料是共享的。

舉個例子來說,在Ball類別中,您會使用到圓周率的這個資料,對於任一個球而言,圓周率都是一樣的,您並不需要讓不同的球物件擁有各自的資料成員來記錄 圓周率,而這個記錄的值卻是相同,這只會增加記憶體的消耗而已。

您可以將資料成員宣告為"static",被宣告為"static" 的資料成員,它是屬於類別所擁有,而不是個別的物件,您可以將"static"視為個別物件所擁有、共享的資料成員。

要宣告static變數,您只要在宣告資料成員時加上"static"關鍵字就可以了,例如:
public class Ball {
// ....
public static double PI = 3.14159; // 宣告static資料

public Ball() {
// ..
}

public Ball(double radius, String name) {
//...
}

public double getVolumn() {
// ......
}
}

由於static成員屬於類別所擁有,所以在不使用物件名稱的情況下,您也可以使用類別名稱加上 . 運算子來存取static資料成員,例如:
System.out.println("PI = " + Ball.PI);

static變數同樣遵守public、protected與 private的存取限制,所以若您要在類別之外直接存取static變數,必須注意它的權限(例如必須設定為public成員)。

雖然您也可以在宣告物件之後,使用 . 運算子來存取static資料成員,但是這並不被鼓勵,通常建議使用類別名稱加上 . 運算子來存取,一方面也可以避免與非static成員混淆。

與靜態資料成員類似的,您也可以宣告方法成員為static方法,又稱靜態方法, 被宣告為靜態的方法通常是為了提供工具,例如在Ball類別上增加一個角度轉徑度的方法toRadius():
public class Ball {
...
public static double toRadius(double angle) {
return 3.14159 / 180 * angle;
}
}

與靜態資料成員一樣的,您可以透過類別名稱使用'.'運算子來存取static方法(當然要注意權限設定,例如設定為public),例如:
System.out.println("角 度90等於徑度" + Ball.toRadius(90));


靜態資料與靜態方法的作用通常是為了提供共享的資料或工具方法,例如將數學常用常數或計算公式,以static宣告並撰寫,之後您可以把這個類別當作工 具,透過類別名稱來管理與取用這些靜態資料或方法,例如像J2SE 所提供的Math 類別上,就有Math.PI這個靜態常數,以及Math.Exp()Math.Log()Math.Sin()等 靜態方法可以直接使用,另外還有像Integer.parseInt()Integer. MAX_VALUE等也都是靜態方法與靜態資料成員的實際例 子。

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

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

Java在使用到類別時才會加以載入程式中,如果您要使用一個static資料或方法,而在載入一個類別時,您希望先進行一些初始化動作,您可以使用 static定義一個區塊,並在當中撰寫初始化資源的動作,例如:
public class Ball {
public static int[] arr = new int[10];
static {
// 一些初始化程式碼
}

....
}


像上面這樣一個類別,在第一次呼叫而被載入時,static區塊中的程式碼就會被執行,且只會執行一次,要注意的是,static屬性成員必須撰寫在 static區塊之前,而如果在static區塊中發生了例外,則最後會被包裝為 java.lang.ExceptionInInitializerError。




===== from 海芋小站, http://www.inote.tw/2007/12/java-static.html =====

其實這是海芋最近碰到的一個小問題,為什麼在同一個類別中,Static Method不能存取Non-Static Method呢?於是海芋就想啊想的,加上翻了一下資料,終於恍然大悟,就把他寫下來,避免將來忘記。

其實,若以Static和Non- Static分為兩種不同的型態,則Java大概可以分為四種資料成員,分別為「class field」、「class method」、「instance filed」、「instance method」[1]、而這麼 多的型態,我們該如何去分辨呢?

而在Java中,你可以把Static看成是類別所擁有的,而且是一開始就放置於記憶體中的,而 Instance則是伴隨著物件產生而產生的。

所以,如果我們有下列片段程式碼:
public class CD
{
public static double PI = Math.PI;
public double area = 0;
public CD()
{
.........
}
}

而這段程式碼之中,因為PI這個變數是宣告為static的,所以他是屬於 CD類別,因此若您要在別的類別存取他,只要使用「CD.PI」即可,其中「CD為類別名稱」、「PI則為變數名稱」。

再來,因為 area不為static,因此您只能建立物件,再存取他,所以您如果要在別的類別存取他,只能這樣使用。
CD cd1 = new CD();
cd1.area = 20;

而又倒底是 什麼原因,讓static method只能存取static method呢?原因很簡單,因為在同一個類別之中,沒有建立自己的物件,既然沒有建立物件,那如何存取instance method呢?

而 在instance method中,則是可以存取到static method,但是仍然要以「類別名稱.變數/method名稱」來存取,這點是相當重要的喔!

所以總結如下:
  1. 在 同一個類別中,若有method宣告為static,則此method只能呼叫其它宣告為static的method。
  2. 在不同的類別 中,若要呼叫其它class的static method/field,則使用下列程式碼:
    className.fieldName
    className.methodName

  3. 若 要呼叫instance method或是instance filed,則需先建立物件,再使用下列程式碼:objectVariableName.fieldName
    objectVariableName.methodName
  4. 但 是,在同一類別中,instance method和instance method間,可以互相呼叫。
文章打完也說完了, 如果是您不是程式設計師,或許會看得霧殺殺!那就略過吧!


沒有留言:

張貼留言