2008年3月28日 星期五

Pratical in Java- 6 必要時才使用instanceof

* 實踐06:必要時才使用instanceof
* 嗯,如書上寫就是這樣子
* 名詞解釋:
* 從base class轉型到derived class,稱之為down casting
* 從derived class轉型到base class,稱之為promotion

2008年3月27日 星期四

Static 的意義與實作方式


轉貼自蔡學鏞 網站

一直以來.對static 的用法還是存在一點疑問.看完這篇文章後.就明白了.
Static 的意義與實作方式

「將某 class 產生出一個 instance 之後,此 class 所有的 instance field 都會新增一份,那麼所有的 instance method 是否也會新增一份?」我常常看到網路上有人在討論此問題,所以寫了這篇文章,以為解釋。

Member 的種類
類別(class)的內部組成統稱為成員(member),如果依據成員是「資料」還是「程式」來區分,可以分成:

* 資料,被稱為 field
* 程式,被稱為 method

如果再依據有無使用 static 修飾而細分,則成員可細分成四種:

* class field:有用 static 修飾的 field
* class method:有用 static 修飾的 method
* instance field:沒有用 static 修飾的 field
* instance method:沒有用 static 修飾的 method

顧名思義,class field/method 和 class 本身有密切的關係,而 instance field/method 則與 instance(也就是物件)有密切的關係。請看下面的範例程式。

public class Class1 {
public static int classField;
public static void classMethod1() {
// ...
}
public static void classMethod2() {
// ...
}
public int instanceField;
public void instanceMethod1() {
// ...
}
public void instanceMethod2() {
// ...
}
}
public class Class2 {
public static void classMethod () {
// ...
}
public void instanceMethod() {
// ...
}
}


Field
宣告 field 時,如果前面加上 static 的修飾字,就會使得此 field 變成是 class field。一個 class field 永遠只佔用一塊記憶體,而且此記憶體空間是在此 class 一被載入(load)記憶體之後就立刻配置的(allocate),感覺就如同此 field 與該 class 本身相關,而不是與該 class 的 instance 相關。class field 可以被同一個 class 的 class method 內部所直接使用,舉例來說,上述的 classMethod1() 內部可以出現 classField。如果 Class1 的 class method 或 instance method 欲使用到 Class2 的 class field,就必須在前面冠上 Class2,例如:Class2.classField。

宣告field時,如果前面「不」加上 static 的修飾字,就會使得此 field 變成是 instance field。對 instance field 而言,每產生一個instance(物件)就多一塊 instance field 的記憶體,每少一個 instance 就少一塊 instance field 的記憶體。instance field 可以被同一個 instanc e的 instance method 內部所直接使用,舉例來說,上述的 instanceMethod1() 內部可以出現 instanceField。如果某 class 的class method 或 instance method 欲使用到某 instance 的 instance field,就必須在前面冠上 instance 名稱,例如:obj.classField。

Method
宣告 method 時,如果前面加上 static 的修飾字,就會使得此 method 變成是 class method。對 class method 而言,永遠只佔用一塊記憶體,而且此記憶體空間是在此 class 一被載入進記憶體之後就立刻配置的,就如同此 method 是與該 class 本身相關,而不是與該 class 的 instance 相關。class method 可以被同一個 class 的任何 class method 內部所直接使用,舉例來說,上述的classMethod1() 內部可以出現 classMethod2()。如果 Class1 的 class method 或 instance method 欲使用到 Class2 的 classMethod(),就必須在前面冠上 Class2,也就是 Class2.classMethod()。

宣告 method 時,如果前面「不」加上 static 的修飾字,就會使得此 method 變成是 instance method。對 instance method 而言,每產生一個 instance「並不會」多一塊 instance method 的記憶體。同一個 method 不管被調用(invoke)幾次,也不管被調用時的instance 是何者,每次的程式碼完全都一樣,差別只在每次執行時資料不同,而資料是存放在 call stack 中,所以不會混淆。在 instance method 內,資料的來源包括了參數和 instance field。參數被傳進來變成 call stack 內的 entry,所以不會混淆,這很容易理解,但是 instance field 是如何區隔開來的(前面剛提過:instance field 會隨著 instance 數目增加而增加),這是透過隱匿(implicit)的 this 參數來達到了,稍後會有說明。instance method 可以被同一個 instance 的 instance method 內部所直接使用,舉例來說,上述的 instanceMethod1() 內部可以出現 instanceMethod2()。如果某 class 的 class method 或 instance method 欲使用到某 instance 的某 instance method,就必須在前面冠上此 instance 名稱,例如:obj.classMethod()。

隱匿的 this 參數
綜合上面的敘述來看:

* class field:共用一塊記憶體
* class method:共用一塊記憶體
* instance field:隨著每個 instance 各有一塊記憶體
* instance method:共用一塊記憶體

instance method 為什麼不是隨著每個 instance 佔有一塊記憶體,反倒是共用一塊記憶體?其實,讓每個 instance method 如同instance field 一樣,隨著每個 instance 佔有一塊記憶體,這麼做當然是可以的,只是 Java 編譯器和 JVM 都不這麼做,因為太浪費記憶體空間了。一個 field 少則佔用一個 byte,多則佔用數百 Byte,但是 method 少則數個 byte,多則數百 Kilo Byte。Mehtod耗費的記憶體是 field 的數百倍,甚至數千倍,當然是能共用就盡量共用,比較不會消耗記憶體。既然 JVM 讓一個 class 的所有instance 共用相同的 instance method,下面兩行程式碼在 instanceMethod() 內部時,如何區分是 instance1 或 instance2?

instance1.instanceMethod();
instance2.instanceMethod();

因為編譯器會幫我們在把 instance1 和 instance2 個別傳入 instanceMethod() 中當作第一個參數。也就是說,任何 instance method 參數的實際個數都會比表面上多一個,這個多出來的參數是由 Java 編譯器幫我們加上去的,用來代表對應的 instance。此參數的變數名稱為 this,也是 Java 的一個關鍵字(keyword)。

當調用某個 instance method 或使用某個 instance field 時,你必須在前面加上該 instance 的名稱,如果該 instance method/field 相關的 instance 和當時程式碼所在的 instance method 的 instance 指的是同一個 instance 時,該 instance 的名稱就是 this,這種情況下,你也可以選擇不在前面加上「this.」。

然而,在某些狀況下,非得在前面加上「this.」不可。例如,當method中的參數或區域變數和 instance field 名稱完全相同時,如果不在前面冠上「this.」,那麼指的是參數或區域變數;如果在前面冠上「this.」,那麼指的才是 instance field。

本文作者:蔡學鏞
張貼日期:09/09/2002

2008年3月5日 星期三

MySQL 手動開關

動啟動MySQL Server-Windows作業系統www@slime@com@tw將工作目錄切換至MySQL安裝目錄中的bin資料夾(C:\Program Files\MySQL\MySQL Server 5.0\bin),然後輸入以下指令即可啟動:
_  _引用:
| mysqld (或是mysqld-nt) |
MySQL預設會將錯誤訊息(Error Message)寫入到Error Log,若你希望MySQL將錯誤訊息輸出到terminal以方便你除錯,則可以加上 \--console 選項:
 引用:
|  mysqld \--console |
若是要終止MySQL Server,則請開啟一個新的terminal視窗並輸入:
_  _引用:
| mysqladmin shutdown |
如此一來即可正常的關閉MySQL Server。雖然你也可以使用Windows提供的『工作管理員』或是直接關閉正在執行MySQL Server的terminal視窗以強迫關閉MySQL Server,但這樣子一來有可能會造成資料庫檔案的損毀,或是Server來不及將memory中的資料寫回磁碟,因此非常不建議你這麼做。
*將MySQL Server設定為Windows Service{*}{color:white}www@slime@com@tw{color}若 是你希望在Windows啟動或關閉時,MySQL Server也能夠自動的啟動或關閉,則只要將MySQL Server 設定為Windows Service即可。將工作目錄切換至MySQL安裝目錄中的bin資料夾(C:\Program Files\MySQL\MySQL Server 5.0\bin),然後輸入以下指令:
引用:
| mysqld \--install \[service_name\] \[--defaults-file=file_path\] |
註:若是在這裡指定了'MySQL'以外的Service Name並且沒有指定\- \-defaults-file,則Server除了會從standard option file中讀取 \[mysqld\] group的設定值,還會額外讀取 \[service_name\] group 的設定值。

如此一來即可將MySQL Server設定為Windows Service,若是沒有指定新的Service Name則預設為MySQL。若是要移除該Service,則輸入以下指令:
  引用:
| mysqld \--remove \[service_name\] |
一但我們將MySQL Server設定為Windows Service後,也可以使用以下的指令來啟動或關閉MySQL Server:
引用:
|   net start MySQL <== 啟動MySQL Server\\
  net stop MySQL <== 關閉MySQL Server |
*Log與Status Files{*}{color:white}www@slime@com@tw{color}

MySQL 提供三大類的 LOG。
# General Log:記錄所有Client 發送到Server的SQL Statement
# Binary Log:記錄所有對於資料庫的修改操作
# Slow Log:記錄所有的 Slow Query

註:在預設的情況下這些Log機制都是被關閉的。

*The General Query Log* (_hostname.log_){color:white}www@slime@com@tw{color}在 這個Log檔案中記錄了所有Client 發送到Server的SQL Statement,你可以藉由分析general log來瞭解Server到底都是在執行哪幾類的SQL指令,例如SELECT、UPDATE或INSERT等等。要啟用此功能需要修改 MySQL Server 的系統設定檔並重新啟動MySQL:
   \[mysqld\]
   log
或是
   \[mysqld\]
   log=file_name <<<指定log檔名
*The Binary Log* _(hostname-bin.index, hostname-bin.nnnnnn)_{color:white}www@slime@com@tw{color}在 這個Log檔案中記錄所有對於資料庫的修改操作,指令只有在執行完畢後才會被記錄在Binary Log中,並且是以transactional units為單位進行記錄,它主要是用來進行Replication或是Data Recovery。由於Binary Log是以二進位的格式儲存相關的資料,因此無法直接以文字編輯器觀看其內容,必須透過mysqlbinlog這支工具程式才能將其轉換為一般的文字格 式。要啟用此功能需要修改 MySQL Server 的系統設定檔並重新啟動MySQL:
   \[mysqld\]
   log-bin
或是
   \[mysqld\]
   log-bin=file_name <<<指定log檔名
*The Slow Query Log* _(hostname-slow.log)_{color:white}www@slime@com@tw{color}在 這個Log檔案中記錄所有的Slow Query。Slow Query的判定方式預設是指執行時間超過10秒的SQL Statement,你也可以修改long_query_time的值來改變這個判定時間。要啟用此功能需要修改 MySQL Server 的系統設定檔並重新啟動MySQL:
   \[mysqld\]
   log-slow-queries
或是
   \[mysqld\]
   log-slow-queries=file_name <<<指定log檔名

註:也可以使用log-queries-not-using-indexes來記錄所有未使用到index的query。