本人初學(xué)Java,看到別人都說學(xué)Java先不要用EcliPSe、NetBeans這些開發(fā)工具,所以索性就自己試試。過程犯的錯(cuò)誤極多,參照著李剛老師那本瘋狂Java一點(diǎn)一點(diǎn)的實(shí)驗(yàn).由于自己使用過Makefile,所以就用Makefile做了實(shí)驗(yàn),總算是可以不用eclipse、NetBeans就能自己編譯運(yùn)行一些小的程序了,下面就是我自己總結(jié)的心得,如有錯(cuò)誤,請(qǐng)大家指正,謝謝。
本文分四小節(jié):
第一節(jié):配置Java運(yùn)行時(shí)環(huán)境
第二節(jié):代碼的編譯以及運(yùn)行
第三節(jié):如何打jar包以及使用jar包
第四節(jié):利用Makefile自動(dòng)編譯運(yùn)行Java程序
第一節(jié):配置Java運(yùn)行時(shí)環(huán)境
本節(jié)以Windows XP為例,來配置Java運(yùn)行環(huán)境。這節(jié)很簡單,我就長話短說。
1:下載JDK開發(fā)包,解壓安裝。
2:在用戶環(huán)境變量中增加PATH變量(在系統(tǒng)的環(huán)境變量中增加也行,但是可能需要重新啟動(dòng)操作系統(tǒng)),并設(shè)置其值。
例如我把JDK安裝在F:\program\java目錄下,則把PATH變量設(shè)置成F:\program\java\jdk\bin,因?yàn)檫@個(gè)路徑下有我們要編譯、運(yùn)行Java程序所需要的所有工具,比如javac.exe,java.exe,jar.exe....。之后我們就可以在cmd下使用javac、java、jar等命令了。
例如有一下Java源文件test.java,執(zhí)行javac Test.java就會(huì)在當(dāng)前目錄下生成Test.class文件。之后我們運(yùn)行java Test即可運(yùn)行程序。當(dāng)然也可以人為指定class文件的生成位置,利用-d選項(xiàng)。比如 javac -d D:\ Test.java,那么就可以在D:\目錄下看到Test.class了。
第二節(jié):代碼的編譯以及運(yùn)行
對(duì)于寫Java程序而言,我們主張?jiān)次募cclass文件都有相同的目錄結(jié)構(gòu),這樣不僅會(huì)方便代碼的組織管理,也使得在編譯以及運(yùn)行Java程序時(shí)少犯錯(cuò)誤。
1:位于默認(rèn)包下的文件的編譯以及運(yùn)行
//D:\src\A.java
class A{
private int value;
public A(){
value = 0;
}
public void setValue(int var){
value = var;
}
public int getValue(){
return value;
}
}
//D:\src\Test.java
public class Test{
public void static void main(String[] args){
A a = new A();
a.setValue(10);
System.out.println(a.getValue());
}
}
我們運(yùn)行javac Test.java,會(huì)發(fā)現(xiàn)D:\src目錄下多了A.class和Test.class兩個(gè)文件。運(yùn)行java Test則可以在Dos中看到輸出為10。我們發(fā)現(xiàn)這兩個(gè)Java文件中并沒有package語句,所以這兩個(gè)文件同屬于一個(gè)默認(rèn)包中(沒有顯示寫package的文件都是屬于默認(rèn)包的)。
2: Java類發(fā)現(xiàn)規(guī)則
要想成功編譯java文件,需要有classpath和包名的共同配合。
類發(fā)現(xiàn)規(guī)則:class文件所在目錄 = classpath + '\' + 包名中的'.'全變成'\'
這個(gè)規(guī)則大家一定要記住,保證萬事OK!Java就是靠這個(gè)規(guī)則來尋找需要的class文件的。
例如:classpath=D:
//D:\src\A.java
package src;
public class A{
private int value;
public A(){
value = 0;
}
public void setValue(int var){
value = var;
}
public int getValue(){
return value;
}
}
//D:\Test.java
import src.*;
public class Test{
public void static void main(String[] args){
A a = new A();
a.setValue(10);
System.out.println(a.getValue());
}
}
如果想要javac Test.java成功,則需要在D:\src(D:\src = D:\ + src)路徑下能夠找到A.class,否則編譯出錯(cuò)。如果不存在D:\src目錄,則會(huì)返回包名不存在的錯(cuò)誤信息。如果D:\src存在,但是該路徑下不存在A.class時(shí),則報(bào)告沒有找到class文件。如果java文件存放目錄正確,并且也正確的指定了其所在的包,則javac會(huì)自動(dòng)編譯A.java來生成A.class。
例如:上例就能夠正確的生成所有需要的class文件。但是如果把A.java中package語句去掉。之后編譯A.java生成A.class文件,之后在D:\下運(yùn)行javac Test.java并不會(huì)成功,雖然在D:\src下存在A.class文件。
所以綜上所述,package語句中包名必須與生成的class文件所在的目錄保持一個(gè)關(guān)系,使得javac能夠找到相應(yīng)的class文件并且驗(yàn)證一個(gè)文件是否處于正確的包中。
那么classpath是什么呢?從名字也能猜得到,classpath代表class文件的存放路徑。這是個(gè)環(huán)境變量,可以添加到用戶的環(huán)境變量中,其值則根據(jù)編程時(shí)具體包名、以及類的存放路徑來設(shè)定。如果不想用環(huán)境變量,也可在編譯時(shí)用-classpath來設(shè)置。
classpath可以設(shè)置多個(gè)路徑,路徑之間利用';'相隔。編譯時(shí),javac會(huì)逐個(gè)嘗試classpath的每個(gè)路徑和文件的包名的組合,直到找到相應(yīng)的class文件為止。但是如果通過classpath與包名的組合在多個(gè)不同的路徑下都找到了同名類,則會(huì)返回錯(cuò)誤信息。
由于javac默認(rèn)情況下在java文件的當(dāng)前目錄生成class文件,所以人們經(jīng)常把'.'添加到classpath中,代表當(dāng)前文件所在的路徑。高版本的Java編譯以及運(yùn)行程序可能會(huì)自動(dòng)把'.'添加到classpath中。上面的例子中由于Test.java位于A.java的上一級(jí)目錄中,所以把classpath設(shè)置成'.'時(shí),也能編譯成功。
現(xiàn)在說說把classpath設(shè)置成'.',它代表當(dāng)前運(yùn)行目錄。那么什么是這個(gè)當(dāng)前運(yùn)行目錄呢?其實(shí)就是運(yùn)行javac時(shí)所在的目錄,注意:切不可認(rèn)為是當(dāng)前編譯的那個(gè)java文件所在的目錄。
如果java文件中顯示的寫了package packagename 則為class文件指定了包,那么這個(gè)class文件也必須應(yīng)在packagename轉(zhuǎn)換后的相應(yīng)子目錄下。如果不寫,則表示該class文件在默認(rèn)包中。
現(xiàn)在來說說如運(yùn)行java程序。
例如:classpath=D:
/D:\src\A.java
package src;
public class A{
private int value;
public A(){
value = 0;
}
public void setValue(int var){
value = var;
}
public int getValue(){
return value;
}
}
//D:\src\Test.java
package src;
import src.*;
public class Test{
public void static void main(String[] args){
A a = new A();
a.setValue(10);
System.out.println(a.getValue());
}
}
我們?nèi)绾芜\(yùn)行這個(gè)程序呢?
首先在src目錄下運(yùn)行: javac Test.java
之后在任意目錄下運(yùn)行:java src.Test
注意:切不可運(yùn)行java Test命令,會(huì)提示找不到類的錯(cuò)誤(即使在Test.class文件所在目錄也不行)。所以運(yùn)行指定了package程序時(shí),需要顯示的寫出其包名,即:java packagename.classname,其遵循與class文件一樣的尋找規(guī)則,即在classpath+packagename中'.'變成'\' 所表示的路徑下能夠找到相應(yīng)的classname所指的class文件。
第三節(jié):如何打jar包以及使用jar包
打jar包使用jar命令。
//D:\src\A.java
package src;
public class A{
private int value;
public A(){
value = 0;
}
public void setValue(int var){
value = var;
}
public int getValue(){
return value;
}
}
首先在src目錄下運(yùn)行javac A.java生成A.class。之后在D:\目錄下運(yùn)行jar -cvf test.jar src就會(huì)在D:\這個(gè)目錄下生成test.jar,即我們打的jar包。那么我們?nèi)绾问褂眠@個(gè)jar包呢?首先必須把test.jar的路徑加入到classpath中。之后我們有如下的測試程序。
import src.*; //必須得有此import,因?yàn)锳.class位于src包中。如果不寫則編譯不通過。
public class B{
public static void main(String[] args){
A a = new A();
}
}
jar文件其實(shí)是一個(gè)壓縮包,可以很容易的用解壓軟件進(jìn)行解壓。解壓后有如下目錄關(guān)系:
test.jar |--src---|--A.java |--A.class
這里可以把test.jar當(dāng)成目錄來處理,javac會(huì)自動(dòng)在classpath中解壓這個(gè)test.jar并根據(jù)B.java中的import找到其中的src文件夾下的A.class文件并使用。
現(xiàn)在看看我們的打包命令 jar -cvf test.jar src //意思是把src文件夾整個(gè)打包
如果我們這么打包: 在src目錄下運(yùn)行jar -cvf test.jar A.java A.class,行嗎?答案是不行。因?yàn)檫@樣打包后路徑關(guān)系為:
test.jar
|--A.java
|--A.class
javac尋找A.class時(shí)發(fā)現(xiàn)test.jar下不存在src目錄,則會(huì)報(bào)不存在包的錯(cuò)誤。所以大家一定要注意打包時(shí)應(yīng)該把那個(gè)目錄打進(jìn)去,不應(yīng)把哪個(gè)目錄打進(jìn)去。如果對(duì)屬于默認(rèn)包的class文件打包,則只要把jar包路徑添加到classpath中即可使用,無需再在程序中使用import。當(dāng)然jar命令還有很多參數(shù)可選,來滿足各種不同需要的打包需求,這些就不說了。
4:利用Makefile自動(dòng)編譯運(yùn)行Java程序
下面給出一個(gè)簡單的例子:這個(gè)例子中,沒有手動(dòng)設(shè)置Windows的環(huán)境變量,而是用-classpath指定,這樣方便在不同機(jī)器之間移植。
如下目錄結(jié)構(gòu):
project---|---src---|---main---|---Test.java
| |---package1---|---A.java
| | |---B.java
| |
| |---package2---|---C.java
| |---Makefile
|
|---classes---|---main---|---Test.class
|---package1---|---A.class
| |---B.class
|
|---package2---|---C.class
代碼如下:
//A.java package package1; public class A{ private int value; public A(){ value = 0; } public void setValue(int var){ value = var; } public int getValue(){ return value; } } //B.java package package1; public class B{ private String name; public B(){ name = null; } public void setName(String name){ this.name = name; } public String getName(){ return name; } } //C.java package package2; public class C{ private String name; public C(){ name = null; } public void setName(String name){ this.name = name; } public String getName(){ return name; } } //Test.java import java.util.*; import package1.*; import package2.*; public class Test{ public static void main(String[] args){ A a = new A(); B b = new B(); C c = new C(); a.setValue(3); b.setName("Java"); c.setName("Test"); System.out.println(a.getValue()); System.out.println(b.getName()); System.out.println(c.getName()); } }
Makefile如下:
//Makefile target: javac ./package1/A.java -d ../classes javac ./package1/B.java -d ../classes javac ./package2/C.java -d ../classes javac ./main/Test.java -d ../classes/main/ -classpath ../classes run: java -classpath ../classes/main;../classes Test clean: rm -rf ../classes/package1/*.class rm -rf ../classes/package2/*.class rm -rf ../classes/main/*.class
運(yùn)行:make
D:\Java\project\src>make
javac ./package1/A.java -d ../classes
javac ./package1/B.java -d ../classes
javac ./package2/C.java -d ../classes
javac ./main/Test.java -d ../classes/main/ -classpath ../classes
運(yùn)行:make run
D:\Java\project\src>make run
java -classpath ../classes/main;../classes Test
3
Java
Test
這樣,其實(shí)我們完全可以不用Eclipse、Netbeans等開發(fā)工具就能自己編譯運(yùn)行自己的系統(tǒng)了。