Java FAQ
目錄:
Q1.1 什么是Java、Java2、JDK?JDK后面的1.3、1.4版本號又是怎么回事?
Q1.2 什么是JRE/J2RE?
Q1.3 學習Java用什么工具比較好?
Q1.4 學習Java有哪些好的參考書?
Q1.5 Java和C++哪個更好?
Q1.6 什么是J2SE/J2EE/J2ME?
Q2.1 我寫了第一個Java程序,應該如何編譯/運行?
Q2.2 我照你說的做了,但是出現什么“'javac' 不是內部或外部命令,也不是可運行的
程序或批處理文件。”。
Q2.3 環境變量怎么設置?
Q2.4 我在javac xxx.java的時候顯示什么“unreported exception java.io.IOExcepti
on;”。
Q2.5 javac xxx.java順利通過了,但是java xxx的時候顯示什么“NoClassDefFoundErr
or”。
Q2.6 我在java xxx的時候顯示“Exception in thread "main" java.lang.NoSuchMetho
dError: main”。
Q2.7 在java xxx的時候顯示“Exception in thread "main" java.lang.NullPointerEx
ception”。
Q2.8 package是什么意思?怎么用?
Q2.9 我沒有聲明任何package會怎么樣?
Q2.10 在一個類中怎么使用其他類?
Q2.11 我用了package的時候顯示"NoClassDefFoundError",但是我把所有package去掉的
時候能正常運行。
Q2.12 我想把java編譯成exe文件,該怎么做?
Q2.13 我在編譯的時候遇到什么"deprecated API",是什么意思?
Q3.1 我怎么給java程序加啟動參數,就像dir /p/w那樣?
Q3.2 我怎么從鍵盤輸入一個int/double/字符串?
Q3.3 我怎么輸出一個int/double/字符串?
Q3.4 我發現有些書上直接用System.in輸入,比你要簡單得多。
Q3.5 我怎么從文件輸入一個int/double/字符串?
Q3.6 我想讀寫文件的指定位置,該怎么辦?
Q3.7 怎么判斷要讀的文件已經到了盡頭?
Q4.1 java里面怎么定義宏?
Q4.2 java里面沒法用const。
Q4.3 java里面也不能用goto。
Q4.4 java里面能不能重載操作符?
Q4.5 我new了一個對象,但是沒法delete掉它。
Q4.6 我想知道為什么main方法必須被聲明為public static?為什么在main方法中不能調
用非static成員?
Q4.7 throw和throws有什么不同?
Q4.8 什么是異常?
Q4.9 final和finally有什么不同?
Q5.1 extends和implements有什么不同?
Q5.2 java怎么實現多繼承?
Q5.3 abstract是什么?
Q5.4 public,protected,private有什么不同?
Q5.5 Override和Overload有什么不同?
Q5.6 我繼承了一個方法,但現在我想調用在父類中定義的方法。
Q5.7 我想在子類的構造方法中調用父類的構造方法,該怎么辦?
Q5.8 我在同一個類中定義了好幾個構造方法并且想在一個構造方法中調用另一個。
Q5.9 我沒有定義構造方法會怎么樣?
Q5.10 我調用無參數的構造方法失敗了。
Q5.11 我該怎么定義類似于C++中的析構方法(destructor)?
Q5.12 我想將一個父類對象轉換成一個子類對象該怎么做?
Q5.13 其實我不確定a是不是B的實例,能不能分情況處理?
Q5.14 我在方法里修改了一個對象的值,但是退出方法后我發現這個對象的值沒變!
Q6.1 java能動態分配數組嗎?
Q6.2 我怎么知道數組的長度?
Q6.3 我還想讓數組的長度能自動改變,能夠增加/刪除元素。
Q 什么是鏈表?為什么要有ArrayList和LinkedList兩種List?
Q6.5 我想用隊列/棧。
Q6.6 我希望不要有重復的元素。
Q6.7 我想遍歷集合/Map。
Q6.8 我還要能夠排序。
Q6.9 但是我想給數組排序。
Q6.10 我想按不同方式排序。
Q6.11 Map有什么用?
Q6.12 set方法沒問題,但是get方法返回的是Object。
Q6.13 ArrayList和Vector有什么不同?HashMap和Hashtable有什么不同?
Q6.14 我要獲得一個隨機數。
Q6.15 我比較兩個String總是false,但是它們明明都是"abc" !
Q6.16 我想修改一個String但是在String類中沒找到編輯方法。
Q6.17 我想處理日期/時間。
一、準備篇
Q1.1 什么是Java、Java2、JDK?JDK后面的1.3、1.4版本號又是怎么回事?
答:Java是一種通用的,并發的,強類型的,面向對象的編程語言(摘自Java規范第二版
)。
JDK是Sun公司分發的免費Java開發工具包,正式名稱為J2SDK(Java2 Software Develop K
it)。
包括基本的java工具包和標準類庫。
到目前(2003年7月)為止,Java有3個主要版本,即1.0,1.1,2.0;
JDK有1.0,1.1,1.2,1.3,1.4五個版本。
從JDK1.2起,Sun公司覺得Java改變足夠大而將java語言版本號提升為2.0。
不同的JDK主要在于提供的類庫不同。作為學習你可以下載最新的JDK1.4.2。
真正開發時則應考慮向前兼容,比如1.3。下載請去http://java.sun.com。
JDK1.5預計將在2004年推出,屆時其中將包含若干嶄新的特性。
Q1.2 什么是JRE/J2RE?
答:J2RE是Java2 Runtime Environment,即Java運行環境,有時簡稱JRE。
如果你只需要運行Java程序或Applet,下載并安裝它即可。
如果你要自行開發Java軟件,請下載JDK。在JDK中附帶有JRE。
注意由于Microsoft對Java的支持不完全,請不要使用IE自帶的虛擬機來運行Applet,務必
安裝一個JRE或JDK。
Q1.3 學習Java用什么工具比較好?
答:作者建議首先使用JDK+文本編輯器,這有助你理解下列幾個基礎概念:path,classp
ath,package
并熟悉基本命令:javac和java。并且下載和你的JDK版本一致的API幫助。
如果你不確定類或函數的用法,請先查閱API而不是發貼求助。
當你熟悉Java之后,你可以考慮開始使用一個IDE。
作者推薦eclipse,下載網址http://www.eclipse.org。因為eclispe是免費的,插件化的
。
eclispe的主要缺點是缺乏一個可視化的桌面程序開發工具,
幸運的是IBM在2003年11月已經將部分代碼捐給eclipse組織,可以預計這個缺點很快就會
得到彌補。
無論如何,請不要使用Microsoft的VJ++!眾所周知Microsoft從來就沒有認真支持過Java
。
最后但并非最不重要,要有一本好的參考書,并且英文要過關。
Q1.4 學習Java有哪些好的參考書?
答:作者首先推薦Thinking in Java,中文名《Java編程思想》,有中文版。
目前的最新版本是第三版。
在http://64.78.49.204可以免費下載英文版。
該書第一章介紹了很多面向對象的編程思想,作為新手應當認真閱讀。
除此以外,O'relly出版社和Wrox出版社的書也不錯。作者本人不喜歡大陸作者的書。
也許你覺得英文太難,但是網上大多數資料都是英文的。另外,你需要經常查閱API,而那
也是英文的。
Q1.5 Java和C++哪個更好?
答:這個問題是一個很不恰當的問題。你應該問:Java和C++哪個更適用于我的項目?
Java的優點和缺點一樣明顯。
跨平臺是Java的主要優點,但代價是運行速度的下降。
VC和Windows平臺有良好的集成和足夠快的速度,但是也只能局限在Windows平臺上。
和C++相比,Java學起來更快,開發人員不會碰到很多容易出錯的特性。
但是VB程序員甚至只需要拼裝模塊就可以了。
Q1.6 什么是J2SE/J2EE/J2ME?
答:J2SE就是一般的Java。
J2ME是針對嵌入式設備的,比如支持Java的手機,它有自己的JRE和SDK。
J2EE是一組用于企業級程序開發的規范和類庫,它使用J2SE的JRE。
二、命令篇
Q2.1 我寫了第一個Java程序,應該如何編譯/運行?
答:首先請將程序保存為xxx.java文件,注意你可能需要修改文件后綴名。
然后在dos窗口下使用javac xxx.java命令,你會發現該目錄下多了一個xxx.class文件,
再使用java xxx命令,你的java程序就開始運行了。
Q2.2 我照你說的做了,但是出現什么“'javac' 不是內部或外部命令,也不是可運行的
程序或批處理文件。”。
答:你遇到了path問題。操作系統在一定的范圍(path)內搜索javac.exe,但是沒能找到。
請編輯你的操作系統環境變量,新增一個JAVA_HOME變量,設為你JDK的安裝目錄,
再編輯Path變量,加上一項 %JAVA_HOME%\bin。
然后保存并新開一個dos窗口,你就可以使用javac和java命令了。
Q2.3 環境變量怎么設置?
答:請向身邊會設的人咨詢。
Q2.4 我在javac xxx.java的時候顯示什么“unreported exception java.io.IOExcepti
on;”。
答:參見Q4.8以了解java中的異常機制。
Q2.5 javac xxx.java順利通過了,但是java xxx的時候顯示什么“NoClassDefFoundErr
or”。
答:1. 你遇到了classpath問題。java命令在一定的范圍(classpath)內搜索你直接或間接
使用的class文件,但是未能找到。
首先請確認你沒有錯敲成java xxx.class,
其次,檢查你的CLASSPATH環境變量,其實你并不需要設置該變量,
但如果你設置了該變量又沒有包含.(代表當前目錄)的項,
你就會遇到這個問題。請在你的CLASSPATH環境變量中加入一項. 或干脆刪掉這個變量。
2. 如果你使用了并非JDK自帶的標準包,比如javax.servlet.*包,也會遇到這個問題,請
將相應的jar文件加入classpath。
3. 如果你在java源文件中定義了package,請參見Q2.11。
Q2.6 我在java xxx的時候顯示“Exception in thread "main" java.lang.NoSuchMetho
dError: main”。
答:首先,在你的程序中每個java文件有且只能有一個public類,
這個類的類名必須和文件名的大小寫完全一樣。
其次,在你要運行的類中有且只能有一個public static void main(String[] args)方法
,
這個方法就是你的主程序。
Q2.7 在java xxx的時候顯示“Exception in thread "main" java.lang.NullPointerEx
ception”。
答:在程序中你試圖在值為null的對象變量上調用方法,請檢查你的程序確保你的對象被恰當的初始化。
參見Q4.8以了解java中的異常機制。
Q2.8 package是什么意思?怎么用?
答:為了唯一標識每個類并分組,java使用了package的概念。
每個類都有一個全名,例如String的全名是java.lang.String,其中java.lang是包名,S
tring是短名。按照java命名慣例,包名是全部小寫的,而類名的第一個字母是大寫的。
這樣,如果你自行定義了同樣名字的類String,你可以把它放在mypackage中,
通過使用全名mypackage.String和java.lang.String來區分這兩個類。
同時,將邏輯上相關的類放在同一個包中,可以使程序結構更為清楚。
為了定義包,你要做的就是在java文件開頭加一行“package mypackage;”。
注意包沒有嵌套或包含關系,mypackage包和mypackage.mysubpackage包對JRE來說是并列的兩個包(雖然開發者可
能暗示包含關系)。
Q2.9 我沒有聲明任何package會怎么樣?
答:你的類被認為放在默認包中。這時全名和短名是一致的。
Q2.10 在一個類中怎么使用其他類?
答:如果你使用java.lang包或者默認包中的類,不用做任何事。
如果你的類位于mypackage包中,并且要調用同一包中的其他類,也不用做任何事。
如果你使用其他包中的類,在package聲明之后,類聲明之前使用import otherpackage1.Class
1; 或 import otherpackage2.*;
這里.*表示引入這個包中的所有類。然后在程序中你可以使用其他類的短名。
如果短名間有重名沖突,必須使用全名來區分。
注意在使用其他包中的類時,你只能使用public的類和接口,參見Q5.4。
Q2.11 我用了package的時候顯示"NoClassDefFoundError",但是我把所有package去掉的
時候能正常運行。
答:將你的java文件按包名組織存放。
比如你的工作目錄是/work,你的類是package1.Class1,那么將它存放為/work/package1
/Class1.java。
如果沒有聲明包,那么直接放在/work下。
在/work下執行javac package1/class1.java,再執行java package1.class1,你會發現一
切正常。
另外,如果你的類的個數已經多到了你需要使用包來組織的話,你可以考慮開始使用IDE。
Q2.12 我想把java編譯成exe文件,該怎么做?
答:JDK只能將java源文件編譯為class文件。
class文件是一種跨平臺的字節碼,必須依賴平臺相關的JRE來運行。Java以此來實現跨平
臺性。
有些開發工具可以將java文件編譯為exe文件。作者反對這種做法,因為這樣就取消了跨平
臺性。
如果你確信你的軟件只在Windows平臺上運行,你可以考慮使用C++/C#來編程。
Q2.13 我在編譯的時候遇到什么"deprecated API",是什么意思?
答:所謂deprecated是指已經過時,但是為了向前兼容起見仍然保留的方法。
這些方法可能會在以后取消支持。你應當改用較新的方法。
在API里面會說明你應當用什么方法來代替之。
三、I/O篇
Q3.1 我怎么給java程序加啟動參數,就像dir /p/w那樣?
答:還記得public static void main(String[] args)嗎?這里的args就是你的啟動參數
。
在運行時你輸入java package1.class1 arg1 arg2,args中就會有兩個String,第一個是
arg1,第二個是arg2。
Q3.2 我怎么從鍵盤輸入一個int/double/字符串?
答:java的I/O操作比C++要復雜一點。如果要從鍵盤輸入,樣例代碼如下:
BufferedReader cin = new BufferedReader( new InputStreamReader( System.in ) );
String s = cin.readLine();
這樣你就獲得了一個字符串,如果你需要數字的話再使用:
int n = Integer.parseInt( s ); 或者 double d = Double.parseDouble( s );
來將字符串"534"轉換成int或double。
Q3.3 我怎么輸出一個int/double/字符串?
答:使用System.out.println(n)或者System.out.println("Hello")等等。
Q3.4 我發現有些書上直接用System.in輸入,比你要簡單得多。
答:java使用unicode,是雙字節。而System.in是單字節的stream。
如果你要輸入雙字節文字比如中文,請使用作者的做法。
Q3.5 我怎么從文件輸入/輸出一個int/double/字符串?
答:類似于從鍵盤輸入,只不過換成
BufferedReader fin = new BufferedReader( new FileReader(" myFileName " ) );
PrintWriter fout = new PrintWriter( new FileWriter(" myFileName " ) );
另外如果你還沒下載API,請開始下載并閱讀java.io包中的內容。
Q3.6 我想讀寫文件的指定位置,該怎么辦?
答:java.io.RandomAccessFile可以滿足你的需要。
Q3.7 怎么判斷要讀的文件已經到了盡頭?
答:在Reader的read方法中明確說明返回-1表示流的結尾。
四、 關鍵字篇
Q4.1 java里面怎么定義宏?
答:java不支持宏,因為宏代換不能保證類型安全。
如果你需要定義常量,可以將它定義為某個類的static final成員。參見Q4.2和Q4.6。
Q4.2 java里面沒法用const。
答:你可以用final關鍵字。例如 final int m = 9。被聲明為final的變量不能被再次賦
值。唯一的例外是所謂blank final,如下例所示:
public class MyClass1 {
private final int a = 3;
private final int b; // blank final
public MyClass1() {
a = 5; // 不合法,final變量不能被再次賦值。
b = 4; // 合法,這是b第一次被賦值。
b = 6; // 不合法,b不能被再次賦值。
}
}
final也可以用于聲明方法或類,被聲明為final的方法或類不能被繼承。
注意const是java的保留字以備擴充。
Q4.3 java里面也不能用goto。
答:甚至在面向過程的語言中你也可以完全不用goto。請檢查你的程序流程是否合理。
如果你需要從多層循環中迅速跳出,java增強了(和C++相比)break和continue的功能,
支持label。
例如:
outer :
while( ... )
{
inner :
for( ... )
{
... break inner; ...
... continue outer; ...
}
}
和const一樣,goto也是java的保留字以備擴充。
Q4.4 java里面能不能重載操作符?
答:不能。String的+號是唯一一個內置的重載操作符。你可以通過定義接口和方法來實現
類似功能。
Q4.5 我new了一個對象,但是沒法delete掉它。
答:java有自動內存回收機制,即所謂Garbarge Collection。你不需要刪除對象。你再也
不用擔心指針錯誤,內存溢出了。
Q4.6 我想知道為什么main方法必須被聲明為public static?為什么在main方法中不能調
用非static成員?
答:聲明為public是為了這個方法可以被外部調用,詳情見Q5.4。
static是為了將某個成員變量/方法關聯到類(class)而非實例(instance)。
你不需要創建一個對象就可以直接使用這個類的static成員,因而在static成員中不能調
用非static成員,因為后者是關聯到對象實例(instance)的。
在A類中調用B類的static成員可以使用B.staticMember的寫法。
注意一個類的static成員變量是唯一的,被所有該類對象所共享的,在多線程程序設計中尤其要謹慎小心。
類的static成員是在類第一次被JRE裝載的時候初始化的。
你可以使用如下方法來使用非static成員:
public class A
{
private void someMethod() //非static成員
{}
public static void main(String args)
{
A a = new A(); //創建一個對象實例
a.someMethod(); //現在你可以使用非static方法了
}
}
Q4.7 throw和throws有什么不同?
答:throws用于方法聲明中,聲明一個方法會拋出哪些異常。而throw是在方法體中實際執行拋出異常的
動作。
如果你在方法中throw一個異常,卻沒有在方法聲明中聲明之,編譯器會報錯。
注意Error和RuntimeException的子類是例外,無需特別聲明。
Q4.8 什么是異常?
答:異常最早在Ada語言中引入,用于在程序中動態處理錯誤并恢復。
你可以在方法中攔截底層異常并處理之,也可以拋給更高層的模塊去處理。
你也可以拋出自己的異常指示發生了某些不正常情況。常見的攔截處理代碼如下:
try
{
......//以下是可能發生異常的代碼
...... //異常被你或低層API拋出,執行流程中斷并轉向攔截代碼。
......
}
catch(Exception1 e) //如果Exception1是Exception2的子類并要做特別處理,應排在前
面
{
//發生Exception1時被該段攔截
}
catch(Exception2 e)
{
//發生Exception2時被該段攔截
}
finally //這是可選的
{
//無論異常是否發生,均執行此段代碼
//即使在catch段中又向外拋出了新的exception,finally段也會得到執行。
}
Q4.9 final和finally有什么不同?
答:final請見Q4.2。finally用于異常機制,參見Q4.8。
五、 面向對象篇
Q5.1 extends和implements有什么不同?
答:對于class而言,extends用于(單)繼承一個類(class),而implements用于實現一個接口(interf
ace)。
interface的引入是為了部分地提供多繼承的功能。
在interface中只需聲明方法頭,而將方法體留給實現的class來做。
這些實現的class的實例完全可以當作interface的實例來對待。
在interface之間也可以聲明為extends(多繼承)的關系。
注意一個interface可以extends多個其他interface。
Q5.2 java怎么實現多繼承?
答:java不支持顯式的多繼承。
因為在顯式多繼承的語言例如c++中,會出現子類被迫聲明祖先虛基類構造函數的問題,
而這是違反面向對象的封裝性原則的。
java提供了interface和implements關鍵字來部分地實現多繼承。參見Q5.1。
Q5.3 abstract是什么?
答:被聲明為abstract的方法無需給出方法體,留給子類來實現。
而如果一個類中有abstract方法,那么這個類也必須聲明為abstract。
被聲明為abstract的類無法實例化,盡管它可以定義構造方法供子類使用。
Q5.4 public,protected,private有什么不同?
答:這些關鍵字用于聲明類和成員的可見性。
public成員可以被任何類訪問,
protected成員限于自己和子類訪問,
private成員限于自己訪問。
Java還提供了第四種的默認可見性,一般稱為package private,當沒有任何public,protected,private修飾符時,成員
是同一包內可見。
類可以用public或默認來修飾。
Q5.5 Override和Overload有什么不同?
答:Override是指父類和子類之間方法的繼承關系,這些方法有著相同的名稱和參數類型
。
Overload是指同一個類中不同方法(可以在子類也可以在父類中定義)間的關系,
這些方法有著相同的名稱和不同的參數類型。
Q5.6 我繼承了一個方法,但現在我想調用在父類中定義的方法。
答:用super.xxx()可以在子類中調用父類方法。
Q5.7 我想在子類的構造方法中調用父類的構造方法,該怎么辦?
答:在子類構造方法的第一行調用super(...)即可。
Q5.8 我在同一個類中定義了好幾個構造方法并且想在一個構造方法中調用另一個。
答:在構造方法第一行調用this(...)。
Q5.9 我沒有定義構造方法會怎么樣?
答:自動獲得一個無參數的構造方法。
Q5.10 我調用無參數的構造方法失敗了。
答:如果你至少定義了一個構造方法,就不再有自動提供的無參數的構造方法了。
你需要另外顯式定義一個無參數的構造方法。
另外一種可能是你的構造方法或者類不是public的,參見Q5.4了解java中的可見性。
Q5.11 我該怎么定義類似于C++中的析構方法(destructor)?
答:提供一個void finalize()方法。在Garbarge Collector回收該對象時會調用該方法。
注意實際上你很難判斷一個對象會在什么時候被回收。作者從未感到需要用到該方法。
Q5.12 我想將一個父類對象轉換成一個子類對象該怎么做?
答:強制類型轉換。如
public void meth(A a)
{
B b = (B)a;
}
如果a實際上并不是B的實例,會拋出ClassCastException。所以請確保a確實是B的實例。
Q5.13 其實我不確定a是不是B的實例,能不能分情況處理?
答:可以使用instanceof操作符。例如
if( a instanceof B )
{
B b = (B)a;
}
else
{
...
}
Q5.14 我在方法里修改了一個對象的值,但是退出方法后我發現這個對象的值沒變!
答:很可能你把傳入參數重賦了一個新對象,例如下列代碼就會造成這種錯誤:
public void fun1(A a) //a是局部參數,指向了一個外在對象。
{
a = new A(); //a指向了一個新對象,和外在對象脫鉤了。如果你要讓a作為傳出變量,
不要寫這一句。
a.setAttr(attr);//修改了新對象的值,外在對象沒有被修改。
}
基本類型也會出現這種情況。例如:
public void fun2(int a)
{
a = 10;//只作用于本方法,外面的變量不會變化。
}
六、java.util篇
Q6.1 java能動態分配數組嗎?
答:可以。例如int n = 3; Language[] myLanguages = new Language[n];
Q6.2 我怎么知道數組的長度?
答:用length屬性。如上例中的 myLanguages.length 就為 3。
Q6.3 我還想讓數組的長度能自動改變,能夠增加/刪除元素。
答:用順序表--java.util.List接口。
你可以選擇用ArrayList或是LinkedList,前者是數組實現,后者是鏈表實現。
例如: List list = new ArrayList(); 或是 List list = new LinkedList(); 。
Q 什么是鏈表?為什么要有ArrayList和LinkedList兩種List?
答:請補習數據結構。
Q6.5 我想用隊列/棧。
答:用java.util.LinkedList。
Q6.6 我希望不要有重復的元素。
答:用集合--java.util.Set接口。例如:Set set = new HashSet()。
Q6.7 我想遍歷集合/Map。
答:用java.util.Iterator。參見API。
Q6.8 我還要能夠排序。
答:用java.util.TreeSet。例如:Set set = new TreeSet()。放進去的元素會自動排序
。
你需要為元素實現Comparable接口,還可能需要提供equals()方法,compareTo()方法,h
ashCode()方法。
Q6.9 但是我想給數組排序。
答:java.util.Arrays類包含了sort等實用方法。
Q6.10 我想按不同方式排序。
答:為每種方式定義一個實現了接口Comparator的排序類并和Arrays或TreeSet綜合運用。
Q6.11 Map有什么用?
答:存儲key-value的關鍵字-值對,你可以通過關鍵字來快速存取相應的值。
Q6.12 set方法沒問題,但是get方法返回的是Object。
答:強制類型轉換成你需要的類型。參見Q5.12。
Q6.13 ArrayList和Vector有什么不同?HashMap和Hashtable有什么不同?
答:ArrayList和HashMap是多線程不安全的,在多個線程中訪問同一個ArrayList對象可能
會引起沖突并導致錯誤。
而Vector和Hashtable是多線程安全的,即使在多個線程中同時訪問同一個Vector對象也不
會引起差錯。
看起來我們更應該使用Vector和Hashtable,但是實際上Vector和Hashtable的性能太差,
所以如果你不在多線程中使用的話,還是應該用ArrayList和HashMap。
Q6.14 我要獲得一個隨機數。
答:使用java.util.Random類。
Q6.15 我比較兩個String總是false,但是它們明明都是"abc" !
答:比較String一定要使用equals或equalsIgnoreCase方法,不要使用 == !
==比較的是兩個引用(變量)是否指向了同一個對象,而不是比較其內容。
Q6.16 我想修改一個String但是在String類中沒找到編輯方法。
答:使用StringBuffer類。
String str = "......."; //待處理的字符串
StringBuffer buffer = new StringBuffer(str); //使用該字符串初始化一個StringBuf
fer
buffer.append("..."); //調用StringBuffer的相關API來編輯字符串
String str2 = buffer.toString(); //獲得編輯后的字符串。
另外,如果你需要將多個字符串連接起來,請盡量避免使用+號直接連接,而是使用Strin
gBuffer.append()方法。
Q6.17 我想處理日期/時間。
答:使用java.util.Date類。你可以使用java.text.SimpleDateFormat類來在String和Da
te間互相轉換。
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); //規
定日期格式
Date date = formatter.parse("2003-07-26 18:30:35"); //將符合格式的String轉換為
Date
String s = formatter.format(date); //將Date轉換為符合格式的String
關于定義日期格式的詳細信息請參見API。
J2EE FAQ
目錄:
一、準備篇
Q1.1 什么是J2EE?它和普通的Java有什么不同?
Q1.2 J2EE好學嗎?
Q1.3 J2EE有什么用?
Q1.4 學J2EE有前途嗎?
Q1.5 據說J2EE的性能不如.NET好,是真的嗎?
Q1.6 聽你說了這么多,我想學著玩玩。
Q1.7 學習J2EE該怎么開始?
Q1.8 我下了一個J2EE服務器但是不會配置。
Q1.9 我發現你沒有提到Tomcat。
二、 Servlet/JSP篇
Q2.1 什么是Servlet?
Q2.2 我怎么獲得Http請求里的參數?
Q2.3 我怎么返回結果?
Q2.4 sendRedirect()和forward()有什么不同?
Q2.5 我寫了一個Servlet程序,怎么運行它?
Q2.6 EAR和WAR有什么不同?
Q2.7 EAR格式是怎樣的?
Q2.8 WAR格式是怎樣的?
Q2.9 我的普通HTML文件/JSP文件應當放在哪里?
Q2.10 我訪問不到servlet,甚至連HTML文件都訪問不到!
Q2.11 我能訪問HTML但是訪問不到servlet。
Q2.12 什么是JSP?它和Servlet有什么區別?
Q2.13 我的JSP顯示的漢字是亂碼。
Q2.14 為什么使用gb18030而不是gb2312?
Q2.15 在JSP里面怎么引用Java Bean。
Q2.16 我想在servlet間傳遞數據。
Q2.17 怎么調用cookie?
Q2.18 怎么在JSP里面實現文件下載?
Q2.19 怎么實現文件上傳?
Q2.20 我想讓頁面自動刷新,比如聊天室。
Q2.21 我想讓用戶登錄以后才能訪問頁面。
Q2.22 我想要能注冊用戶。
Q2.23 怎么在JSP中訪問數據庫?
Q2.24 什么是JSTL?
一、準備篇
Q1.1 什么是J2EE?它和普通的Java有什么不同?
答:J2EE全稱為Java2 Platform, Enterprise Edition。
“J2EE平臺本質上是一個分布式的服務器應用程序設計環境——一個Java環境,它提供了
:
·宿主應用的一個運行基礎框架環境。
·一套用來創建應用的Java擴展API。”
Q1.2 J2EE好學嗎?
答:J2EE是很多技術的集合體,并且還在成長中。
你會遇到很多專有名詞:比如(X)HTML,Servlet/JSP,JDBC,JMS,JNDI,EJB,XML,Web
Service……。
尤其是XML和Web Service正在快速成長。幸運的是,你不需要等到學會所有技術后再開始
編程。
大體上J2EE可以分成3個主要應用方式:Servlet/JSP,EJB,Web Service 和一些支撐技術
例如JDBC和JNDI。
你可以一個一個的學。
Q1.3 J2EE有什么用?
答:用來建設大型的分布式企業級應用程序。或者用更時髦的名詞說就是“電子商務”應
用程序。
這些企業可能大到擁有中心數據庫服務器,Web服務器集群和遍布全國的辦公終端,也可能
小到只不過想做一個網站。但是你肯定聽過“殺雞焉用牛刀”的古訓。
Q1.4 學J2EE有前途嗎?
答:在這一市場目前只有一種技術可以和J2EE競爭,那就是Microsoft的.NET。
相對來說.NET要“新”一些而J2EE要“老”一些。這也意味著.NET更易用一點而J2EE更成
熟一點。
但是.NET只能用于Windows平臺(Microsoft聲稱要開發C#在Linux上的虛擬機但是尚未兌現
該諾言)。
在過去幾年,.NET的市場份額并不理想。不過Microsoft還有Longhorn這一殺手锏,鹿死誰
手還很難說。
Q1.5 據說J2EE的性能不如.NET好,是真的嗎?
答:在Sun公司提供的樣例程序Pet Store上,Microsoft聲稱不如相同的.NET程序好。
而Sun公司反駁說這一程序不能真正體現J2EE的性能,并且指責Microsoft在數據庫上做了
優化。
作者沒有學習過.NET因而不能妄下斷言。
無論如何,大型分布式程序中的性能瓶頸通常首先來自于錯誤的設計。
Q1.6 聽你說了這么多,我想學著玩玩。
答:除非你想靠它當飯吃或者作為技術儲備,否則請不要浪費你的時間。
Flash要好玩得多。計算機游戲就更加好玩了。
Q1.7 學習J2EE該怎么開始?
答:首先,下載一個免費的J2EE服務器。其次,去java.sun.com下載J2EE的API。第三,找
一本好的參考書。最后,找一個順手的IDE。
J2EE服務器。你可以用Sun的J2EE SDK(免費),或者Weblogic(性能最好,但是太大,而
且作者不推薦盜版行為),
或者JBoss(免費,就是文檔太少),或者JRun(開發版免費,作者用這個)。
參考書作者感覺Wrox的《J2EE服務器端高級編程》不錯,但是太老(作者手頭的是2001年
中文版)。
(似乎很多人不喜歡這本書......所以你得自己判斷它是否適合你。)
你還需要去下載一些最新的技術資料(當然肯定是英文的)。
IDE如果你的機器配置夠好(內存至少512M以上,256M或以下請勿考慮),可以用IBM的WS
AD,不然就繼續用Eclipse或者其他。
你也可以經常去水木清華的Java版逛逛,但是在發貼前先看看精華區里有沒有你要的答案
。
Q1.8 我下了一個J2EE服務器但是不會配置。
答:請認真閱讀隨機指導文檔,不同的服務器的配置都不一樣,作者愛莫能助。
Q1.9 我發現你沒有提到Tomcat。
答:Tomcat只是一個Web服務器,更準確地說主要只是一個Web Container。
如果你想要學習EJB的話,Tomcat無法滿足你的需要。
二、 Servlet/JSP篇
Q2.1 什么是Servlet?
答:一個Servlet是一個Java類。它處理Http(s)請求并作出響應,包括返回一個HTML頁面
或轉交給其他URL處理。
Servlet必須運行在一個Web Container例如Tomcat中。
Servlet必須是javax.servlet.http.HttpServlet的子類,
你可以繼承doGet()或者doPost()方法,兩者分別對應于Http(s)中的Get請求和Post請求。
Q2.2 我怎么獲得Http請求里的參數?
答:HttpRequest的getParameter()方法。例如:String paramValue = request.getPara
meter("paramName");
Q2.3 我怎么返回結果?
答:你可以利用相關API打開一個輸出流,并向流中直接寫入一個HTML頁面。
但是作者完全不贊成這樣做。一方面這樣做會很羅嗦。
另一方面從Model-View-Controller模式(在《J2EE核心模式》中被歸為Front Controlle
r模式)的觀點來看,
你應當提供一些HTML或者JSP作為視圖(view),而Servlet則根據請求參數決定轉到哪一
個視圖。
你可以利用response.sendRedirect(...)方法或request.getDispatcher(...).forward()
方法來實現。
Q2.4 sendRedirect()和forward()有什么不同?
答:sendRedirect()是向瀏覽器發送一個redirect通知,瀏覽器向新的URL發送一個新的請
求。
而forward是在服務器端直接將請求轉到新的URL,對于瀏覽器是透明的。
換而言之,sendRedirect()應當將共享數據放在session中,forward應當將共享數據放在
request中(當然你也可以放在session中,但放在request中可以有效減小session中的數
據量,從而改善性能)。
前者瀏覽器的地址欄顯示的是新的URL,后者瀏覽器的地址欄顯示的是Servlet的URL。
因而當刷新目標URL時,兩者會造成一些差別。
Q2.5 我寫了一個Servlet程序,怎么運行它?
答:開發J2EE程序有一個部署(deploy)的概念,實際上是開發——部署——運行的三部
曲。
大多數服務器支持Hot deploy。你只需要在相應的Application目錄(具體路徑依賴于服務
器)下面
建立一個符合WAR或EAR格式(參見Q2.7,Q2.8)的目錄,啟動服務器,就可以通過瀏覽器
訪問了。
特別的,你的Servlet的class文件應當放在/WEB-INF/classes目錄中。
注意J2EE SDK不支持Hot deploy,你需要通過它的deploy tool來部署。
Tomcat只支持WAR格式。
Q2.6 EAR和WAR有什么不同?
答:EAR是一個完整的J2EE應用程序,包括Web部分和EJB部分。
WAR只是其中的Web部分。
Q2.7 EAR格式是怎樣的?
答:一個EAR可以包含任意多個WAR或EJB JAR,并且包含一個META-INF的目錄。
在/META-INF中包含了一個application.xml,其中描述了這個EAR包含哪些模塊,以及安全
性配置。
細節請看參考書。
Q2.8 WAR格式是怎樣的?
答:一個WAR包含一個WEB-INF的目錄,這個目錄下包含classes目錄,lib目錄和web.xml。
/WEB-INF/classes存放按package組織的class文件,/WEB-INF/lib目錄存放jar文件,
web.xml描述了很多東西,請讀參考書。
Q2.9 我的普通HTML文件/JSP文件應當放在哪里?
答:放在除了/WEB-INF以外的其他地方。
感謝antegg網友對于安全性的提醒:
如果你想直接用http://url/***.jsp的方式來訪問,就要像上面說得那樣放。
但是這樣的做法是不安全的,安全的做法是把所有的JSP頁面放在/WEB-INF目錄下面,并且
通過WEB-CONTAINER來訪問。
作者意見:
我更喜歡用filter來做安全性檢查。
在MVC模式中,JSP只是一個視圖而已,一般無需特別擔憂安全性。和普通的html放在一起
也利于維護。
Q2.10 我訪問不到servlet,甚至連HTML文件都訪問不到!
答:
第一你沒啟動服務器。
第二你敲錯了端口。
第三你沒有正確配置context-path。
第四你的服務器不支持auto reload或者你關閉了這一選項,你得重啟服務器或重新部署W
AR。
第五確認你沒有把HTML放在/WEB-INF目錄下,那是訪問不到的。
Q2.11 我能訪問HTML但是訪問不到servlet。
答:請檢查你的web.xml文件。確保你正確定義了<servlet>和<servlet-mapping>元素。
前者標識了一個servlet,后者將一個相對于context-path的URL映射到一個servlet。
在Tomcat中你可以通過/context-path/servlet/package/servletname的形式訪問servlet
,
但是這只是Tomcat的便捷訪問方式,并不是正式規范。
細節請看參考書。
Q2.12 什么是JSP?它和Servlet有什么區別?
答:你可以將JSP當做一個可擴充的HTML來對待。
雖然在本質上JSP文件會被服務器自動翻譯為相應的Servlet來執行。
可以說Servlet是面向Java程序員而JSP是面向HTML程序員的,除此之外兩者功能完全等價
。
Q2.13 我的JSP顯示的漢字是亂碼。
答:在你的JSP開頭加上一行 <%@ page contentType="text/html; charset=gb18030"%>
如果你已經聲明了page我想你知道該怎么修改。
Q2.14 為什么使用gb18030而不是gb2312?
答:gb18030是繼gb2312之后的下一代漢字編碼標準,最終將過渡到Unicode。
Q2.15 在JSP里面怎么引用Java Bean。
答:首先,確認你要引用的類在/WEB-INF/classes下或在/WEB-INF/lib的某個jar內。
其次,在JSP里加一行 <jsp:useBean id="..." scope="..." class="..."/>
具體解釋請看參考書。
Q2.16 我想在servlet間傳遞數據。
答:利用session。在Servlet/JSP中,你可以在4個地方保存數據。
1) page,本頁面。
2) session,用來存放客戶相關的信息,比如購物車,對應接口為javax.servlet.http.H
ttpSession。
session機制實際上是cookie和URL Rewriting的抽象,服務器會自動使用cookie或URL Re
writing來實現。
3) request,可以在forward()時傳遞信息,對應接口為javax.servlet.http.HttpReques
t。
4) application,或稱context,存放全局信息,對應接口為javax.servlet.ServletCont
ext。
Q2.17 怎么調用cookie?
答:作者建議使用session,你總是會遇到某些禁用cookie的用戶。這時session會自動使
用URL重寫來實現。
Q2.18 怎么在JSP里面實現文件下載?
答:實際上這是一個HTML的問題。答案是一個超鏈接<a>。
Q2.19 怎么實現文件上傳?
答:客戶端是HTML問題,在form中設置method為post,enctype為multi-part/form-data,
加一個<input type="file">。
而在接收的servlet中只是一個I/O問題,你可以使用jakarta的file-upload庫。
Q2.20 我想讓頁面自動刷新,比如聊天室。
答:這是一個HTML問題,在<head>部分中加一條<meta http-equiv="refresh" content="
5" url="...">。
這是所謂的Client-pull,客戶端刷新技術。
相對的還有Server-push,服務器端刷新技術,但是這一技術由于要占用服務器端資源而會
在大量訪問時出現瓶頸現象,參見http://216.239.33.104/search?q=cache:autUfoakirY
J:www.kfunigraz.ac.at/edvndwww/books/books/javaenterprise/servlet/ch06_03.htm+
server-push+servlet&hl=zh-CN&ie=UTF-8
Q2.21 我想讓用戶登錄以后才能訪問頁面。
答:使用聲明式安全措施。
你只需要在web.xml中定義安全角色(Role),并定義受保護的URL集合只能由特定Role訪
問。
大多數服務器支持基于數據庫的用戶映射,你只要在相應數據庫中建立兩張表并配置服務
器就可以了。
注意J2EE SDK不支持基于數據庫的用戶映射。
細節請看參考書和服務器文檔。
不過在商業環境中,J2EE所提供的聲明式安全措施仍然偏弱。一般商業程序會使用數據庫
存儲user-role-privilege模型來達到安全性要求,細節請詢問你的構架設計師。
Q2.22 我想要能注冊用戶。
答:參看Q2.21。在接受注冊請求的Servlet中執行寫入數據庫操作即可。
Q2.23 怎么在JSP中訪問數據庫?
答:標準做法是使用DAO模式,定義一個Java bean來訪問數據庫并在JSP中使用。
然而,當你的數據庫模式很簡單時,你可以使用JSTL中的<sql:query>標簽來快速訪問。
在一般的J2EE項目中,JSP處于表示層(展現層),需要先后通過業務層和集成層才會訪問
到數據庫,所以這個問題確實只會在很小的程序中才會遇到。
Q2.24 什么是JSTL?
答:JSTL是Jsp Standard Tag Library的縮寫。這是一組通用標簽并將成為JSP 2.0的一部
分。
其中包含賦值<c:set>,分支<c:if>,循環<c:forEach>,查詢數據庫<sql:query>,更新數
據庫<sql:update>
等。目前你需要像添加自定義標簽庫一樣來添加JSTL,但是可以預計JSP 2.0會將JSTL作為
組成部分。
標簽庫可以在http://jakarta.apache.org下載。注意JSTL需要在支持JSP 1.2或更高版本
的容器下運行。
幫助文件可以閱讀sun的JSTL正式規范。