星期四, 12月 02, 2004

Java , main 方法是具有特權的方法

main 方法是具有特權的方法。記憶體內若無此方法的存在,

程式便無法啟動。但是 Java 有項「所有的方法(包括物件)都必

須在 class 內定義」的限制,不能像 C++ 一樣在 class 以外定義

全域的物件或方法。這樣一來,解決之道只有一途,那就是將

main 方法宣告成 static,並在定義類別時,確立記憶體的空間。

static 的 main 方法為 Java 的必然歸宿。

在 JVM 裡面在執行一個 class 的時候所需要的一個入口
比如說:
public final class METAVIGE {

private String name = "metavige";
private static final String nickname = "gentleman";

public String toString() {
return name + " is " + nickname;
}
}

如果要執行這個 class, 就必須替這個 class 建立一個 入口 給 JVM
讓 JVM 知道要先執行哪一個 method
所以就必須在這個 class 裡面加入一個 靜態方法 (static method)
原始碼就會變成這樣:
public final class METAVIGE {

private String name = "metavige";
private static final String nickname = "gentleman";

public String toString() {
return name + " is a " + nickname;
}

public static void main(String args[]) {
METAVIGE me = new METAVIGE();
System.out.println(me);
}

}


所以呢
在執行的時候:
C:\JavaTest>java METAVIGE

JVM 就會知道去找 METAVIGE class 裡面的 main() 方法來執行

不知道我這樣解釋
是不是能比較明白的了解

星期三, 12月 01, 2004

Java classpath的解說

# 摘要

Class Path是Java執行時期環境用來搜尋類別與其它資源所用之路徑。Class Search Path(通常使用Class Path這個縮寫名稱比較為人所知)可以在呼叫SDK工具程式時使用-classpath或者是設定CLASSPATH環境變數。建議是使用-classpath選項,因為您可以獨立的為每一個應用程式設定,而不會影響其它的應用程式,且不會有其它的應用程式來改變這個值。

C:> sdkTool -classpath classpath1;classpath2...

-或-
C:> set CLASSPATH=classpath1;classpath2...


在這邊:
sdkTool:是一個命令列工具程式,像是java、javac 或 javadoc.
classpath1;classpath2:指向.jar、.zip或 .class檔案的Class Path,每一個classpath都應以檔名或目錄名稱(這與您所要設定的classpath有關)作結束。

* 對於一個包括.class的.jar或.zip檔案而言,class path要以.zip或.jar檔案的名稱作結束。
* 對於一個未命名的package而言,class path要以包括所有.class檔案的目錄作結束。
* 對於一個已命名的package而言,class path要以包括"根"package(完整package名稱的第一個package)的目錄名稱作結束。


多個路徑項目要以 分號 作區隔,使用set指令,重要的是等號兩邊不可有空白。

預設的class path是目前的目錄,設定CLASSPATH變數或使用-classpath命令列選項時會覆蓋這個預設,所以如果您要在目前的搜尋路徑中包括目前的目錄,您必須在新設定中包括"." 。

即不是目錄也不是文件檔案(.zip或.java)的classpath會被忽略。

# 說明

class path告訴SDK工具程式與應用程式要到哪邊尋找第三元件(third-party)與使用者定義的classes,也就是它們非Java延伸套件或非 Java平台的一部份。在您使用javac編譯器編譯類別時,需要使用class path來找出任何所需的套件 -- 預設是目前的目錄,以方便找到這些類別。

Java2 SDK、JVM與其它的SDK工具藉由搜尋Java平台、classes、其它延伸classes與class path來找到所需的classes,以這個順序(要瞭解搜尋策略的細節,請看如何尋找Classes, How Classes Are Found),大部份應用程式所用的類別庫就可以利用延伸套件機制(extensions mechanism),在您載入一個不在目前目錄的類別或它的其它子目錄且它們不在伸延伸套件機制中時,您所要作的就是設定class path。

如 果您從舊版本的SDK昇級上來,在您的啟動設定中可能包括已經不再使用的CLASSPATH設定,您必須將這些非特定應用程式的設定移除,像是 classes.zip,一些使用到Java虛擬機器的第三元件應用程式可能會更改您的CLASSPATH環境變數,以將它們所使用的程式庫包括進去,這 些設定則可以保留。

在您要求JVM或其它SDK工具程式時,您可以在使用Java工具程式時藉由-classpath選項 來改變class path,或是使用CLASSPATH環境變數來指定。建議是使用-classpath選項會比設定CLASSPATH環境變數來得好,因為您可以為每一 個應用程式分別設定,而不會影響其它的應 用程式,而其它應用程式也不會改變這個值。

Classes可以被儲存在目錄(資料夾)或是在文 件檔案(archive files),Java平台的classes是被儲存在rt.jar,要瞭解文件檔案的細節或是class path如何運作的資訊,請看看稍後小節的 "瞭解class path與package名稱"。

重 要、注意:一些舊版本的JDK軟體在預設的class path中包括了/classes項目,這些目錄的存在是為了被JDK軟體使用,而不應被應用程式classes使用。應 用程式類別應該被放在JDK目錄結構之外的其它目錄,用這種方式,新的JDK就不會強迫您重新安裝應用程式classes,為了要與舊版本相容,必須使用 /classes目錄作為類別庫的的應用程式,在目前的版本也可以運作,但不保證在未來的版本中仍可以運作。

# 使用SDK工具程式的-classpath選項

SDK 工具程式 java、jdb、javac與javah擁有一個-classpath項目,當執行工具程式時,它用於取代由CLASSPATH環境變數所設定的路徑, 在改變class path設定時,這是個建議使用的選項,因為每一個應用程式可以擁有自已所需的class path,而不會與其它應用程式相互干擾。

執行時期工具程式java也有一個 -cp 選項,這個選項是-classpath的縮寫名稱。

對於一些相當特殊的例子來說,java與javac都擁有一些項目可以讓您改變它們用來找到專屬類別庫的路徑,然而絕大多數的使用者從未需要使用這些項目。

# 使用CLASSPATH環境變數

一般而言,建議您使用-classpath命令列選項,就如同上面所提過的,這個小節將告讓您如何設定CLASSPATH環境變數,如果您想這麼作的話,或者是想清除之前安裝所留下的設定。

設定 CLASSPATH:

CLASSPATH環境變數可以藉由set指令來修改,格式是:

set CLASSPATH=path1;path2 ....


路徑應該以磁碟機代號開始,例如C:\,用這種方式,即使您切換至另一個磁碟機也可以找得到classes。(舉個例子來說,假如路徑項目以斜線開始而您在磁碟機D:,那麼classes將會預期是在D:,而不是C:)

清除 CLASSPATH:

如果您的CLASSPATH環境變數已經被設定為某個值,但是並不正確,或者是您的啟動檔案或是命令稿被設定了錯誤的路徑,您可以藉由以下來取消CLASSPATH的設定:

C:> set CLASSPATH=


這個指令只取消目前的命令列提示視窗CLASSPATH設定,您應當刪除或修正您的啟動設定,以保證您在下一次操作也會有正確的CLASSPATH設定。

改變啟動設定:

如果CLASSPATH被設定於系統啟動時,設定的地方則視您所使用的作業系統而定:
作業系統方法:
*Windows 95與98 檢查autoexec.bat中的set指令
*其它(Windows NT、Windows 2000、....)使用控制台中的系統工具來設定CLASSPATH變數

# 瞭解class path與package名稱

Java 的classes被組織為packages,它們對應於檔案系統的目錄結構,但是不像檔案系統,每當您指定一個package名稱時,您指定整個 package名稱而不是部份名稱,例如,java.awt.Button的package名稱是使用java.awt來指定。

例如,假設您要Java執行環境找到一個在 package名稱 utility.myapp 中名叫Cool.class的class,假如該目錄的路徑是C:\java\MyClasses\utility\myapp,您要設定class path以包括 C:\java\MyClasses

要執行這個應用程式,您可以使用下面的JVM指令:
c:> java -classpath C:\java\MyClasses utility.myapp.Cool


當應用程式執行時,JVM會使用class path設定來找到任一其它被定義於utility.myapp package(它被Cool類別使用)中的類別。

注意在指令中被指定的整個package名稱,這是不可能的,例如,設定class path包括C:\java\MyClasses\utility並使用指令java myapp.Cool,這麼作並不會找到class。

(您可能會想是什麼定義了一個class的package名稱,答案是package名稱是class的一部份,而且不可被修改,除非重新編譯)

注意:一個package指定機制的有趣的結果是,同一個package中的部份檔案可以存在於不同的目錄,對於每一個class而言,package名稱將會相同,但是每一個檔案的路徑將會以class path中不同的目錄開始。

目錄與文件檔案(archive files):

當classes 被儲存在目錄(資料夾),像是c:\java\MyClasses\utility\myapp,那麼class path項目指向包括package名稱第一個元素的目錄(在這個例子中是c:\java\MyClasses,因為package名稱是 utility.myapp)

但是當classes被儲存在文件檔案時(a.zip或.jar檔案),class path項目就是指向且包括.zip或.jar的檔案,例如,使用在.jar檔案中的類別庫,指令會像是:

C:> java -classpath C:\java\MyClasses\myclasses.jar utility.myapp.Cool



多個指定:

要尋找C:\java\MyClasses中與C:\java\OtherClasses中的classes,您可以這麼設定class path:

C:> java -classpath C:\java\MyClasses;C:\java\OtherClasses ...


注意兩個路徑是以分號作區隔。

指定順序:

指 定多個class path項目的順序很重要,Java解碼器(interpreter)會以class path變數 中的順序來於目錄中尋找classes,在上面的例子中,Java解碼器首先會在目錄C:\java\MyClasses中尋找所需的類別,只有在它於該 目錄中找不到適當名稱的類別時,解碼器才會於C:\java\OtherClasses目錄中尋找。
anthonycs edited on 2004-04-22 22:53

萬年歷 for dos版(Java)

/*----------------------------------------------------------------------------------*/
/* 萬年曆 ---------------------------- */
/*-大家參考看看,說明不太會寫,有人可以改一下嗎?---------------*/
import java.io.*;

public class Calendar{

public static void main(String ags[])throws IOException
{
BufferedReader input_data=new BufferedReader(new InputStreamReader(System.in));
int read_data,year,month,thefirst_day=0,end_day=0;
boolean check=true,tmp_year,tmp_month;
Date data =new Date();

while(check){

System.out.println("----------萬年曆----------");
System.out.println(" (1).列印指定年份及月份(月曆).");
System.out.println(" (2).列印指定年份(年曆).");
System.out.println(" (0).離開.");
System.out.println("請輸入列印方式");
read_data=Integer.parseInt(input_data.readLine());
System.out.println("你選擇的列印方式:"+read_data);
switch(read_data){
case 1:
tmp_year=true;
tmp_month=true;
do{
System.out.println("請輸入年份");
year=Integer.parseInt(input_data.readLine());

if(year > 0 & year <= 30000){
tmp_year=false;
}else{
System.out.println("無效的年份,請重新輸入.");
}
}while(tmp_year);
do{
System.out.println("請輸入月份(1-12)");
month=Integer.parseInt(input_data.readLine());
if(month > 0 & month < 13){
tmp_month=false;
}else{
System.out.println("無效的月份,請重新輸入.");
}
}while(tmp_month);



System.out.println("********萬年曆********");
System.out.println(" 西元 "+year+" 年 "+month+" 月份");
thefirst_day=data.count_first_day(year,month);
end_day=data.count_days(year,month);
data.prical(thefirst_day,end_day);
System.out.println(" ");
break;
case 2:
tmp_year=true;
do{
System.out.println("請輸入您要印出的年份");
year=Integer.parseInt(input_data.readLine());
if(year > 0 & year <= 30000){
tmp_year=false;
}else{
System.out.println("無效的年份,請重新輸入.");
}
}while(tmp_year);
System.out.println("********萬年曆********");
for(month=1;month<=12;month++){
System.out.println(" 西元 "+year+" 年 "+month + "月份");
thefirst_day=data.count_first_day(year,month);
end_day=data.count_days(year,month);
data.prical(thefirst_day,end_day);
System.out.println(" ");
}
break;

case 0 :
System.out.println("This program will be exit...");
check=false;
break;
default:
System.out.println("無效的輸入,請重新選擇列印方法...");
break;
}
}
}
}
class Date{
/*以下為計算該年該月有幾天之副程式:因為1752年之前為四年一閏,
1752年以後位四年一閏,逢百不閏,而四百又要閏,故分為以下狀況。*/
static int count_days(int year,int month){
int days;
if(year<=1752 && year%4==0 && month==2)
days=29;
else if(year>1752 && ((year%4==0 && year%100!=0)||year%400==0) && month==2)
days=29;
else if(month==1||month==3||month==5||month==7||month==8||month==10||month==12)
days = 31;
else if(month==4||month==6||month==9||month==11)
days = 30;
else
days = 28;
return(days);
}
/* 以下為計算第一天為星期幾之副程式:分為三部分:
* (1)1752年8月以前,利用西元1年1月1日為星期六,及除7求餘的方式,
*  來計算所求年月第一天為星期幾。
* (2)1752年10月~12月,利用1752年10月1日為星期日,及除7求餘的方式,
*  來計算所求年月第一天為星期幾。
* (3)1753年以後,利用1753年1月1日為星期一,及除7求餘的方式, 
*  來計算所求年月第一天為星期幾。
*/
static int count_first_day(int year,int month){
int i,j,f_day=0;
if(year<1752 || (year==1752 && month<=8))
{ f_day=6;
for(i=1;i { if(i%4==0)
f_day=(f_day+366%7)%7;
else
f_day=(f_day+365%7)%7;
}
for(j=1;j { f_day=(f_day+count_days(year,j))%7;
}
}
else if(year>1752)
{ f_day=1;
for(i=1753;i { if((i%4==0&&i%100!=0)||i%400==0)
f_day=(f_day+366%7)%7;
else
f_day=(f_day+365%7)%7;
}
for(j=1;j f_day=(f_day+count_days(year,j))%7;
}
else if(year==1752 && month>=10)
{ f_day=0;
for(j=10;j f_day=(f_day+count_days(year,j))%7;
}
return(f_day);
}
/* 此為特例之副程式,由於1752年9月無3~13日,故寫一專門處理該年月之副程式。 */
void special_program()
{
int counter,days,first_day,end_day;
first_day=2;
end_day=30;
String s="Sun\tMon\tTue\tWed\tThu\tFri\tSar\n";
for(counter=0;counter s+="\t";
for(days=1;days<=end_day;++days){
s+=Integer.toString(days)+"\t";
if((first_day+days)%7==4&&days!=2)
s+="\n";
if(days==2)
days=13;
}

}
/* 以下為列印月曆之副程式:藉由該月第一天是星期幾及該月之天數來
* 決定如何列印。
*/
void prical(int first_day,int end_day){
int i,j;
String s;
System.out.println("日 一 二 三 四 五 六 ");
for(i=0;i System.out.print(" ");
}
for(j=1;j<=end_day;++j){
if(j>0&j<10){
System.out.print(j+" ");
}
else{
System.out.print(j+" ");
}
if((first_day+j)%7==0)
System.out.println(" ");
}
System.out.println(" ");
}
}