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处于表示层(展现层),需要先后通过业务层和集成层才会访问
到数据库,所以这个问题确实只会在很小的程序中才会遇到。
答: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正式规范
|
|