2006年3月14日
摘要:
阅读全文
posted @
2010-02-04 15:30 xnabx 阅读(1598) |
评论 (1) |
编辑 收藏
摘要:
阅读全文
posted @
2010-01-25 11:10 xnabx 阅读(1020) |
评论 (1) |
编辑 收藏
摘要:
阅读全文
posted @
2010-01-21 09:52 xnabx 阅读(1713) |
评论 (0) |
编辑 收藏
摘要:
阅读全文
posted @
2010-01-15 10:10 xnabx 阅读(1398) |
评论 (0) |
编辑 收藏
摘要:
阅读全文
posted @
2010-01-15 09:57 xnabx 阅读(327) |
评论 (0) |
编辑 收藏
摘要:
阅读全文
posted @
2009-12-04 11:45 xnabx 阅读(594) |
评论 (3) |
编辑 收藏
摘要:
阅读全文
posted @
2009-12-03 15:26 xnabx 阅读(302) |
评论 (0) |
编辑 收藏
摘要:
阅读全文
posted @
2009-12-01 16:02 xnabx 阅读(177) |
评论 (0) |
编辑 收藏
摘要:
阅读全文
posted @
2009-12-01 11:05 xnabx 阅读(314) |
评论 (0) |
编辑 收藏
摘要:
阅读全文
posted @
2009-11-10 09:05 xnabx 阅读(740) |
评论 (0) |
编辑 收藏
摘要:
阅读全文
posted @
2009-03-18 14:06 xnabx 阅读(147) |
评论 (0) |
编辑 收藏
摘要:
阅读全文
posted @
2008-10-29 16:34 xnabx 阅读(109) |
评论 (0) |
编辑 收藏
摘要:
阅读全文
posted @
2008-07-30 15:18 xnabx 阅读(232) |
评论 (0) |
编辑 收藏
摘要:
阅读全文
posted @
2008-07-23 11:20 xnabx 阅读(380) |
评论 (0) |
编辑 收藏
出处:http://www.blogjava.net/xmatthew/archive/2008/04/14/192450.html
(转)设计一个Tomcat访问日志分析工具
常使用web服务器的朋友大都了解,一般的web server有两部分日志:
一是运行中的日志,它主要记录运行的一些信息,尤其是一些异常错误日志信息
二是访问日志信息,它记录的访问的时间,IP,访问的资料等相关信息。
现在我来和大家介绍一下利用tomcat产生的访问日志数据,我们能做哪些有效的分析数据?
首先是配置tomcat访问日志数据,默认情况下访问日志没有打开,配置的方式如下:
编辑 ${catalina}/conf/server.xml文件.注:${catalina}是tomcat的安装目录
把以下的注释(<!-- -->)去掉即可。
<!--
<Valve className="org.apache.catalina.valves.AccessLogValve"
directory="logs" prefix="localhost_access_log." suffix=".txt"
pattern="common" resolveHosts="false"/>
-->
其中 directory是产生的目录 tomcat安装${catalina}作为当前目录
pattern表示日志生产的格式,common是tomcat提供的一个标准设置格式。其具体的表达式为 %h %l %u %t "%r" %s %b
但本人建议采用以下具体的配置,因为标准配置有一些重要的日志数据无法生。
%h %l %u %t "%r" %s %b %T
具体的日志产生样式说明如下(从官方文档中摘录):
* %a - Remote IP address
* %A - Local IP address
* %b - Bytes sent, excluding HTTP headers, or '-' if zero
* %B - Bytes sent, excluding HTTP headers
* %h - Remote host name (or IP address if resolveHosts is false)
* %H - Request protocol
* %l - Remote logical username from identd (always returns '-')
* %m - Request method (GET, POST, etc.)
* %p - Local port on which this request was received
* %q - Query string (prepended with a '?' if it exists)
* %r - First line of the request (method and request URI)
* %s - HTTP status code of the response
* %S - User session ID
* %t - Date and time, in Common Log Format
* %u - Remote user that was authenticated (if any), else '-'
* %U - Requested URL path
* %v - Local server name
* %D - Time taken to process the request, in millis
* %T - Time taken to process the request, in seconds
There is also support to write information from the cookie, incoming header, the Session or something else in the ServletRequest. It is modeled after the apache syntax:
* %{xxx}i for incoming headers
* %{xxx}c for a specific cookie
* %{xxx}r xxx is an attribute in the ServletRequest
* %{xxx}s xxx is an attribute in the HttpSession
现在我们回头再来看一下下面这个配置 %h %l %u %t "%r" %s %b %T 生产的访问日志数据,我们可以做哪些事?
先看一下,我们能得到的数据有:
* %h 访问的用户IP地址
* %l 访问逻辑用户名,通常返回'-'
* %u 访问验证用户名,通常返回'-'
* %t 访问日时
* %r 访问的方式(post或者是get),访问的资源和使用的http协议版本
* %s 访问返回的http状态
* %b 访问资源返回的流量
* %T 访问所使用的时间
有了这些数据,我们可以根据时间段做以下的分析处理(图片使用jfreechart工具动态生成):
* 独立IP数统计
* 访问请求数统计
* 访问资料文件数统计
* 访问流量统计
* 访问处理响应时间统计
* 统计所有404错误页面
* 统计所有500错误的页面
* 统计访问最频繁页面
* 统计访问处理时间最久页面
* 统计并发访问频率最高的页面
分析工具包括两大部分,一个是后台解释程序,每天执行一次对后台日志数据进行解析后保存到数据库中。
第二个是显示程序,从数据库中查询数据并生成相应的图表信息。
posted @
2008-04-15 12:06 xnabx 阅读(554) |
评论 (0) |
编辑 收藏
摘要:
阅读全文
posted @
2008-04-09 08:50 xnabx 阅读(36) |
评论 (0) |
编辑 收藏
摘要:
阅读全文
posted @
2008-03-19 13:00 xnabx 阅读(179) |
评论 (0) |
编辑 收藏
如果你觉得你的Eclipse在启动的时候很慢(比如说超过20秒钟),也许你要调整一下你的Eclipse启动参数了,以下是一些``小贴士'':
1. 检查启动Eclipse的JVM设置。 在Help\About Eclipse SDK\Configuration Detail里面,你可以看到启动Eclipse的JVM。 这个JVM和你在Eclipse中设置的Installed JDK是两回事情。 如果启动Eclipse的JVM还是JDK 1.4的话,那最好改为JDK 5,因为JDK 5的性能比1.4更好。
C:\eclipse\eclipse.exe -vm "C:\Program Files\Java\jdk1.5.0_08\ bin\javaw.exe"
2. 检查Eclipse所使用的heap的大小。 在C:\eclipse目录下有一个配置文件eclipse.ini,其中配置了Eclipse启动的默认heap大小
-vmargs
-Xms40M
-Xmx256M
所以你可以把默认值改为:
-vmargs
-Xms256M
-Xmx512M
当然,也可以这样做,把堆的大小改为256 - 512。
C:\eclipse\eclipse.exe -vm "C:\Program Files\Java\jdk1.5.0_08\ bin\javaw.exe" -vmargs -Xms256M -Xmx512M
3. 其他的启动参数。 如果你有一个双核的CPU,也许可以尝试这个参数:
-XX:+UseParallelGC
让GC可以更快的执行。(只是JDK 5里对GC新增加的参数)
posted @
2007-12-25 10:55 xnabx 阅读(482) |
评论 (0) |
编辑 收藏
Java对多线程的支持与同步机制深受大家的喜爱,似乎看起来使用了synchronized关键字就可以轻松地解决多线程共享数据同步问题。到底如何?――还得对synchronized关键字的作用进行深入了解才可定论。
总的说来,synchronized关键字可以作为函数的修饰符,也可作为函数内的语句,也就是平时说的同步方法和同步语句块。如果再细的分类,synchronized可作用于instance变量、object reference(对象引用)、static函数和class literals(类名称字面常量)身上。
在进一步阐述之前,我们需要明确几点:
A.无论synchronized关键字加在方法上还是对象上,它取得的锁都是对象,而不是把一段代码或函数当作锁――而且同步方法很可能还会被其他线程的对象访问。
B.每个对象只有一个锁(lock)与之相关联。
C.实现同步是要很大的系统开销作为代价的,甚至可能造成死锁,所以尽量避免无谓的同步控制。
接着来讨论synchronized用到不同地方对代码产生的影响:
假设P1、P2是同一个类的不同对象,这个类中定义了以下几种情况的同步块或同步方法,P1、P2就都可以调用它们。
1. 把synchronized当作函数修饰符时,示例代码如下:
Public synchronized void methodAAA()
{
//….
}
这也就是同步方法,那这时synchronized锁定的是哪个对象呢?它锁定的是调用这个同步方法对象。也就是说,当一个对象P1在不同的线程中执行这个同步方法时,它们之间会形成互斥,达到同步的效果。但是这个对象所属的Class所产生的另一对象P2却可以任意调用这个被加了synchronized关键字的方法。
上边的示例代码等同于如下代码:
public void methodAAA()
{
synchronized (this) // (1)
{
//…..
}
}
(1)处的this指的是什么呢?它指的就是调用这个方法的对象,如P1。可见同步方法实质是将synchronized作用于object reference。――那个拿到了P1对象锁的线程,才可以调用P1的同步方法,而对P2而言,P1这个锁与它毫不相干,程序也可能在这种情形下摆脱同步机制的控制,造成数据混乱:(
2.同步块,示例代码如下:
public void method3(SomeObject so)
{
synchronized(so)
{
//…..
}
}
这时,锁就是so这个对象,谁拿到这个锁谁就可以运行它所控制的那段代码。当有一个明确的对象作为锁时,就可以这样写程序,但当没有明确的对象作为锁,只是想让一段代码同步时,可以创建一个特殊的instance变量(它得是一个对象)来充当锁:
class Foo implements Runnable
{
private byte[] lock = new byte[0]; // 特殊的instance变量
Public void methodA()
{
synchronized(lock) { //… }
}
//…..
}
注:零长度的byte数组对象创建起来将比任何对象都经济――查看编译后的字节码:生成零长度的byte[]对象只需3条操作码,而Object lock = new Object()则需要7行操作码。
3.将synchronized作用于static 函数,示例代码如下:
Class Foo
{
public synchronized static void methodAAA() // 同步的static 函数
{
//….
}
public void methodBBB()
{
synchronized(Foo.class) // class literal(类名称字面常量)
}
}
代码中的methodBBB()方法是把class literal作为锁的情况,它和同步的static函数产生的效果是一样的,取得的锁很特别,是当前调用这个方法的对象所属的类(Class,而不再是由这个Class产生的某个具体对象了)。
记得在《Effective Java》一书中看到过将 Foo.class和 P1.getClass()用于作同步锁还不一样,不能用P1.getClass()来达到锁这个Class的目的。P1指的是由Foo类产生的对象。
可以推断:如果一个类中定义了一个synchronized的static函数A,也定义了一个synchronized 的instance函数B,那么这个类的同一对象Obj在多线程中分别访问A和B两个方法时,不会构成同步,因为它们的锁都不一样。A方法的锁是Obj这个对象,而B的锁是Obj所属的那个Class。
小结如下:
搞清楚synchronized锁定的是哪个对象,就能帮助我们设计更安全的多线程程序。
还有一些技巧可以让我们对共享资源的同步访问更加安全:
1. 定义private 的instance变量+它的 get方法,而不要定义public/protected的instance变量。如果将变量定义为public,对象在外界可以绕过同步方法的控制而直接取得它,并改动它。这也是JavaBean的标准实现方式之一。
2. 如果instance变量是一个对象,如数组或ArrayList什么的,那上述方法仍然不安全,因为当外界对象通过get方法拿到这个instance对象的引用后,又将其指向另一个对象,那么这个private变量也就变了,岂不是很危险。这个时候就需要将get方法也加上synchronized同步,并且,只返回这个private对象的clone()――这样,调用端得到的就是对象副本的引用了。
posted @
2007-10-11 14:19 xnabx 阅读(262) |
评论 (0) |
编辑 收藏
摘要:
阅读全文
posted @
2007-07-29 09:17 xnabx 阅读(383) |
评论 (0) |
编辑 收藏
这几个学习材料非常短小精悍,可清晰快捷的掌握以下几个概念,方便更深入学习
XML tutorial:
http://www.w3schools.com/xml/default.asp
SOAP tutorial:
http://www.w3schools.com/soap/default.asp
WSDL tutorial:
http://www.w3schools.com/wsdl/default.asp
WEB Service tutorial:
http://www.w3schools.com/webservices/default.asp
posted @
2007-07-13 09:00 xnabx 阅读(170) |
评论 (0) |
编辑 收藏
类-->对象-->实例
人类是类
某个人是对象
你是实例
实例本身也是对象。
表现出来是这样的
String 类
String str str是对象
String str = "abc"; "abc"是实例,也是对象.
这样也能解释instance of object这种说法 str的实例是"abc"
posted @
2007-07-05 08:47 xnabx 阅读(422) |
评论 (1) |
编辑 收藏
1. 概述
本文主要包括以下几个方面:编码基本知识,java,系统软件,url,工具软件等。
在下面的描述中,将以"中文"两个字为例,经查表可以知道其GB2312编码是"d6d0 cec4",Unicode编码为"4e2d 6587",UTF编码就是"e4b8ad e69687"。注意,这两个字没有iso8859-1编码,但可以用iso8859-1编码来"表示"。
2. 编码基本知识
最早的编码是iso8859-1,和ascii编码相似。但为了方便表示各种各样的语言,逐渐出现了很多标准编码,重要的有如下几个。
2.1. iso8859-1
属于单字节编码,最多能表示的字符范围是0-255,应用于英文系列。比如,字母'a'的编码为0x61=97。
很明显,iso8859-1编码表示的字符范围很窄,无法表示中文字符。但是,由于是单字节编码,和计算机最基础的表示单位一致,所以很多时候,仍旧使用iso8859-1编码来表示。而且在很多协议上,默认使用该编码。比如,虽然"中文"两个字不存在iso8859-1编码,以gb2312编码为例,应该是"d6d0 cec4"两个字符,使用iso8859-1编码的时候则将它拆开为4个字节来表示:"d6 d0 ce c4"(事实上,在进行存储的时候,也是以字节为单位处理的)。而如果是UTF编码,则是6个字节"e4 b8 ad e6 96 87"。很明显,这种表示方法还需要以另一种编码为基础。
2.2. GB2312/GBK
这就是汉子的国标码,专门用来表示汉字,是双字节编码,而英文字母和iso8859-1一致(兼容iso8859-1编码)。其中gbk编码能够用来同时表示繁体字和简体字,而gb2312只能表示简体字,gbk是兼容gb2312编码的。
2.3. unicode
这是最统一的编码,可以用来表示所有语言的字符,而且是定长双字节(也有四字节的)编码,包括英文字母在内。所以可以说它是不兼容iso8859-1编码的,也不兼容任何编码。不过,相对于iso8859-1编码来说,uniocode编码只是在前面增加了一个0字节,比如字母'a'为"00 61"。
需要说明的是,定长编码便于计算机处理(注意GB2312/GBK不是定长编码),而unicode又可以用来表示所有字符,所以在很多软件内部是使用unicode编码来处理的,比如java。
2.4. UTF
考虑到unicode编码不兼容iso8859-1编码,而且容易占用更多的空间:因为对于英文字母,unicode也需要两个字节来表示。所以unicode不便于传输和存储。因此而产生了utf编码,utf编码兼容iso8859-1编码,同时也可以用来表示所有语言的字符,不过,utf编码是不定长编码,每一个字符的长度从1-6个字节不等。另外,utf编码自带简单的校验功能。一般来讲,英文字母都是用一个字节表示,而汉字使用三个字节。
注意,虽然说utf是为了使用更少的空间而使用的,但那只是相对于unicode编码来说,如果已经知道是汉字,则使用GB2312/GBK无疑是最节省的。不过另一方面,值得说明的是,虽然utf编码对汉字使用3个字节,但即使对于汉字网页,utf编码也会比unicode编码节省,因为网页中包含了很多的英文字符。
3. java对字符的处理
在java应用软件中,会有多处涉及到字符集编码,有些地方需要进行正确的设置,有些地方需要进行一定程度的处理。
3.1. getBytes(charset)
这是java字符串处理的一个标准函数,其作用是将字符串所表示的字符按照charset编码,并以字节方式表示。注意字符串在java内存中总是按unicode编码存储的。比如"中文",正常情况下(即没有错误的时候)存储为"4e2d 6587",如果charset为"gbk",则被编码为"d6d0 cec4",然后返回字节"d6 d0 ce c4"。如果charset为"utf8"则最后是"e4 b8 ad e6 96 87"。如果是"iso8859-1",则由于无法编码,最后返回 "3f 3f"(两个问号)。
3.2. new String(charset)
这是java字符串处理的另一个标准函数,和上一个函数的作用相反,将字节数组按照charset编码进行组合识别,最后转换为unicode存储。参考上述getBytes的例子,"gbk" 和"utf8"都可以得出正确的结果"4e2d 6587",但iso8859-1最后变成了"003f 003f"(两个问号)。
因为utf8可以用来表示/编码所有字符,所以new String( str.getBytes( "utf8" ), "utf8" ) === str,即完全可逆。
3.3. setCharacterEncoding()
该函数用来设置http请求或者相应的编码。
对于request,是指提交内容的编码,指定后可以通过getParameter()则直接获得正确的字符串,如果不指定,则默认使用iso8859-1编码,需要进一步处理。参见下述"表单输入"。值得注意的是在执行setCharacterEncoding()之前,不能执行任何getParameter()。java doc上说明:This method must be called prior to reading request parameters or reading input using getReader()。而且,该指定只对POST方法有效,对GET方法无效。分析原因,应该是在执行第一个getParameter()的时候,java将会按照编码分析所有的提交内容,而后续的getParameter()不再进行分析,所以setCharacterEncoding()无效。而对于GET方法提交表单是,提交的内容在URL中,一开始就已经按照编码分析所有的提交内容,setCharacterEncoding()自然就无效。
对于response,则是指定输出内容的编码,同时,该设置会传递给浏览器,告诉浏览器输出内容所采用的编码。
3.4. 处理过程
下面分析两个有代表性的例子,说明java对编码有关问题的处理方法。
3.4.1. 表单输入
User input *(gbk:d6d0 cec4) browser *(gbk:d6d0 cec4) web server iso8859-1(00d6 00d 000ce 00c4) class,需要在class中进行处理:getbytes("iso8859-1")为d6 d0 ce c4,new String("gbk")为d6d0 cec4,内存中以unicode编码则为4e2d 6587。
l 用户输入的编码方式和页面指定的编码有关,也和用户的操作系统有关,所以是不确定的,上例以gbk为例。
l 从browser到web server,可以在表单中指定提交内容时使用的字符集,否则会使用页面指定的编码。而如果在url中直接用?的方式输入参数,则其编码往往是操作系统本身的编码,因为这时和页面无关。上述仍旧以gbk编码为例。
l Web server接收到的是字节流,默认时(getParameter)会以iso8859-1编码处理之,结果是不正确的,所以需要进行处理。但如果预先设置了编码(通过request. setCharacterEncoding ()),则能够直接获取到正确的结果。
l 在页面中指定编码是个好习惯,否则可能失去控制,无法指定正确的编码。
3.4.2. 文件编译
假设文件是gbk编码保存的,而编译有两种编码选择:gbk或者iso8859-1,前者是中文windows的默认编码,后者是linux的默认编码,当然也可以在编译时指定编码。
Jsp *(gbk:d6d0 cec4) java file *(gbk:d6d0 cec4) compiler read uincode(gbk: 4e2d 6587; iso8859-1: 00d6 00d 000ce 00c4) compiler write utf(gbk: e4b8ad e69687; iso8859-1: *) compiled file unicode(gbk: 4e2d 6587; iso8859-1: 00d6 00d 000ce 00c4) class。所以用gbk编码保存,而用iso8859-1编译的结果是不正确的。
class unicode(4e2d 6587) system.out / jsp.out gbk(d6d0 cec4) os console / browser。
l 文件可以以多种编码方式保存,中文windows下,默认为ansi/gbk。
l 编译器读取文件时,需要得到文件的编码,如果未指定,则使用系统默认编码。一般class文件,是以系统默认编码保存的,所以编译不会出问题,但对于jsp文件,如果在中文windows下编辑保存,而部署在英文linux下运行/编译,则会出现问题。所以需要在jsp文件中用pageEncoding指定编码。
l Java编译的时候会转换成统一的unicode编码处理,最后保存的时候再转换为utf编码。
l 当系统输出字符的时候,会按指定编码输出,对于中文windows下,System.out将使用gbk编码,而对于response(浏览器),则使用jsp文件头指定的contentType,或者可以直接为response指定编码。同时,会告诉browser网页的编码。如果未指定,则会使用iso8859-1编码。对于中文,应该为browser指定输出字符串的编码。
l browser显示网页的时候,首先使用response中指定的编码(jsp文件头指定的contentType最终也反映在response上),如果未指定,则会使用网页中meta项指定中的contentType。
3.5. 几处设置
对于web应用程序,和编码有关的设置或者函数如下。
3.5.1. jsp编译
指定文件的存储编码,很明显,该设置应该置于文件的开头。例如:<%@page pageEncoding="GBK"%>。另外,对于一般class文件,可以在编译的时候指定编码。
3.5.2. jsp输出
指定文件输出到browser是使用的编码,该设置也应该置于文件的开头。例如:<%@ page contentType="text/html; charset= GBK" %>。该设置和response.setCharacterEncoding("GBK")等效。
3.5.3. meta设置
指定网页使用的编码,该设置对静态网页尤其有作用。因为静态网页无法采用jsp的设置,而且也无法执行response.setCharacterEncoding()。例如:<META http-equiv="Content-Type" content="text/html; charset=GBK" />
如果同时采用了jsp输出和meta设置两种编码指定方式,则jsp指定的优先。因为jsp指定的直接体现在response中。
需要注意的是,apache有一个设置可以给无编码指定的网页指定编码,该指定等同于jsp的编码指定方式,所以会覆盖静态网页中的meta指定。所以有人建议关闭该设置。
3.5.4. form设置
当浏览器提交表单的时候,可以指定相应的编码。例如:<form accept-charset= "gb2312">。一般不必不使用该设置,浏览器会直接使用网页的编码。
4. 系统软件
下面讨论几个相关的系统软件。
4.1. mysql数据库
很明显,要支持多语言,应该将数据库的编码设置成utf或者unicode,而utf更适合与存储。但是,如果中文数据中包含的英文字母很少,其实unicode更为适合。
数据库的编码可以通过mysql的配置文件设置,例如default-character-set=utf8。还可以在数据库链接URL中设置,例如: useUnicode=true&characterEncoding=UTF-8。注意这两者应该保持一致,在新的sql版本里,在数据库链接URL里可以不进行设置,但也不能是错误的设置。
4.2. apache
appache和编码有关的配置在httpd.conf中,例如AddDefaultCharset UTF-8。如前所述,该功能会将所有静态页面的编码设置为UTF-8,最好关闭该功能。
另外,apache还有单独的模块来处理网页响应头,其中也可能对编码进行设置。
4.3. linux默认编码
这里所说的linux默认编码,是指运行时的环境变量。两个重要的环境变量是LC_ALL和LANG,默认编码会影响到java URLEncode的行为,下面有描述。
建议都设置为"zh_CN.UTF-8"。
4.4. 其它
为了支持中文文件名,linux在加载磁盘时应该指定字符集,例如:mount /dev/hda5 /mnt/hda5/ -t ntfs -o iocharset=gb2312。
另外,如前所述,使用GET方法提交的信息不支持request.setCharacterEncoding(),但可以通过tomcat的配置文件指定字符集,在tomcat的server.xml文件中,形如:<Connector ... URIEncoding="GBK"/>。这种方法将统一设置所有请求,而不能针对具体页面进行设置,也不一定和browser使用的编码相同,所以有时候并不是所期望的。
5. URL地址
URL地址中含有中文字符是很麻烦的,前面描述过使用GET方法提交表单的情况,使用GET方法时,参数就是包含在URL中。
5.1. URL编码
对于URL中的一些特殊字符,浏览器会自动进行编码。这些字符除了"/?&"等外,还包括unicode字符,比如汉子。这时的编码比较特殊。
IE有一个选项"总是使用UTF-8发送URL",当该选项有效时,IE将会对特殊字符进行UTF-8编码,同时进行URL编码。如果改选项无效,则使用默认编码"GBK",并且不进行URL编码。但是,对于URL后面的参数,则总是不进行编码,相当于UTF-8选项无效。比如"中文.html?a=中文",当UTF-8选项有效时,将发送链接"%e4%b8%ad%e6%96%87.html?a=\x4e\x2d\x65\x87";而UTF-8选项无效时,将发送链接"\x4e\x2d\x65\x87.html?a=\x4e\x2d\x65\x87"。注意后者前面的"中文"两个字只有4个字节,而前者却有18个字节,这主要时URL编码的原因。
当web server(tomcat)接收到该链接时,将会进行URL解码,即去掉"%",同时按照ISO8859-1编码(上面已经描述,可以使用URLEncoding来设置成其它编码)识别。上述例子的结果分别是"\ue4\ub8\uad\ue6\u96\u87.html?a=\u4e\u2d\u65\u87"和"\u4e\u2d\u65\u87.html?a=\u4e\u2d\u65\u87",注意前者前面的"中文"两个字恢复成了6个字符。这里用"\u",表示是unicode。
所以,由于客户端设置的不同,相同的链接,在服务器上得到了不同结果。这个问题不少人都遇到,却没有很好的解决办法。所以有的网站会建议用户尝试关闭UTF-8选项。不过,下面会描述一个更好的处理办法。
5.2. rewrite
熟悉的人都知道,apache有一个功能强大的rewrite模块,这里不描述其功能。需要说明的是该模块会自动将URL解码(去除%),即完成上述web server(tomcat)的部分功能。有相关文档介绍说可以使用[NE]参数来关闭该功能,但我试验并未成功,可能是因为版本(我使用的是apache 2.0.54)问题。另外,当参数中含有"?& "等符号的时候,该功能将导致系统得不到正常结果。
rewrite本身似乎完全是采用字节处理的方式,而不考虑字符串的编码,所以不会带来编码问题。
5.3. URLEncode.encode()
这是Java本身提供对的URL编码函数,完成的工作和上述UTF-8选项有效时浏览器所做的工作相似。值得说明的是,java已经不赞成不指定编码来使用该方法(deprecated)。应该在使用的时候增加编码指定。
当不指定编码的时候,该方法使用系统默认编码,这会导致软件运行结果得不确定。比如对于"中文",当系统默认编码为"gb2312"时,结果是"%4e%2d%65%87",而默认编码为"UTF-8",结果却是"%e4%b8%ad%e6%96%87",后续程序将难以处理。另外,这儿说的系统默认编码是由运行tomcat时的环境变量LC_ALL和LANG等决定的,曾经出现过tomcat重启后就出现乱码的问题,最后才郁闷的发现是因为修改修改了这两个环境变量。
建议统一指定为"UTF-8"编码,可能需要修改相应的程序。
5.4. 一个解决方案
上面说起过,因为浏览器设置的不同,对于同一个链接,web server收到的是不同内容,而软件系统有无法知道这中间的区别,所以这一协议目前还存在缺陷。
针对具体问题,不应该侥幸认为所有客户的IE设置都是UTF-8有效的,也不应该粗暴的建议用户修改IE设置,要知道,用户不可能去记住每一个web server的设置。所以,接下来的解决办法就只能是让自己的程序多一点智能:根据内容来分析编码是否UTF-8。
比较幸运的是UTF-8编码相当有规律,所以可以通过分析传输过来的链接内容,来判断是否是正确的UTF-8字符,如果是,则以UTF-8处理之,如果不是,则使用客户默认编码(比如"GBK"),下面是一个判断是否UTF-8的例子,如果你了解相应规律,就容易理解。
public static boolean isValidUtf8(byte[] b,int aMaxCount){
int lLen=b.length,lCharCount=0;
for(int i=0;i<lLen && lCharCount<aMaxCount;++lCharCount){
byte lByte=b[i++];//to fast operation, ++ now, ready for the following for(;;)
if(lByte>=0) continue;//>=0 is normal ascii
if(lByte<(byte)0xc0 || lByte>(byte)0xfd) return false;
int lCount=lByte>(byte)0xfc?5:lByte>(byte)0xf8?4
:lByte>(byte)0xf0?3:lByte>(byte)0xe0?2:1;
if(i+lCount>lLen) return false;
for(int j=0;j<lCount;++j,++i) if(b[i]>=(byte)0xc0) return false;
}
return true;
}
相应地,一个使用上述方法的例子如下:
public static String getUrlParam(String aStr,String aDefaultCharset)
throws UnsupportedEncodingException{
if(aStr==null) return null;
byte[] lBytes=aStr.getBytes("ISO-8859-1");
return new String(lBytes,StringUtil.isValidUtf8(lBytes)?"utf8":aDefaultCharset);
}
不过,该方法也存在缺陷,如下两方面:
l 没有包括对用户默认编码的识别,这可以根据请求信息的语言来判断,但不一定正确,因为我们有时候也会输入一些韩文,或者其他文字。
l 可能会错误判断UTF-8字符,一个例子是"学习"两个字,其GBK编码是" \xd1\xa7\xcf\xb0",如果使用上述isValidUtf8方法判断,将返回true。可以考虑使用更严格的判断方法,不过估计效果不大。
有一个例子可以证明google也遇到了上述问题,而且也采用了和上述相似的处理方法,比如,如果在地址栏中输入"http://www.google.com/search?hl=zh-CN&newwindow=1&q=学习",google将无法正确识别,而其他汉字一般能够正常识别。
最后,应该补充说明一下,如果不使用rewrite规则,或者通过表单提交数据,其实并不一定会遇到上述问题,因为这时可以在提交数据时指定希望的编码。另外,中文文件名确实会带来问题,应该谨慎使用。
6. 其它
下面描述一些和编码有关的其他问题。
6.1. SecureCRT
除了浏览器和控制台与编码有关外,一些客户端也很有关系。比如在使用SecureCRT连接linux时,应该让SecureCRT的显示编码(不同的session,可以有不同的编码设置)和linux的编码环境变量保持一致。否则看到的一些帮助信息,就可能是乱码。
另外,mysql有自己的编码设置,也应该保持和SecureCRT的显示编码一致。否则通过SecureCRT执行sql语句的时候,可能无法处理中文字符,查询结果也会出现乱码。
对于Utf-8文件,很多编辑器(比如记事本)会在文件开头增加三个不可见的标志字节,如果作为mysql的输入文件,则必须要去掉这三个字符。(用linux的vi保存可以去掉这三个字符)。一个有趣的现象是,在中文windows下,创建一个新txt文件,用记事本打开,输入"连通"两个字,保存,再打开,你会发现两个字没了,只留下一个小黑点。
6.2. 过滤器
如果需要统一设置编码,则通过filter进行设置是个不错的选择。在filter class中,可以统一为需要的请求或者回应设置编码。参加上述setCharacterEncoding()。这个类apache已经给出了可以直接使用的例子SetCharacterEncodingFilter。
6.3. POST和GET
很明显,以POST提交信息时,URL有更好的可读性,而且可以方便的使用setCharacterEncoding()来处理字符集问题。但GET方法形成的URL能够更容易表达网页的实际内容,也能够用于收藏。
从统一的角度考虑问题,建议采用GET方法,这要求在程序中获得参数是进行特殊处理,而无法使用setCharacterEncoding()的便利,如果不考虑rewrite,就不存在IE的UTF-8问题,可以考虑通过设置URIEncoding来方便获取URL中的参数。
6.4. 简繁体编码转换
GBK同时包含简体和繁体编码,也就是说同一个字,由于编码不同,在GBK编码下属于两个字。有时候,为了正确取得完整的结果,应该将繁体和简体进行统一。可以考虑将UTF、GBK中的所有繁体字,转换为相应的简体字,BIG5编码的数据,也应该转化成相应的简体字。当然,仍旧以UTF编码存储。
例如,对于"语言 ?言",用UTF表示为"\xE8\xAF\xAD\xE8\xA8\x80 \xE8\xAA\x9E\xE8\xA8\x80",进行简繁体编码转换后应该是两个相同的 "\xE8\xAF\xAD\xE8\xA8\x80>"。
posted @
2006-08-30 17:51 xnabx 阅读(173) |
评论 (0) |
编辑 收藏
http://sz.eeju.com/show_rent_99461.htm
http://sz.eeju.com/show_rent_98823.htm
http://sz.eeju.com/show_rent_96082.htm
http://sz.eeju.com/show_rent_99193.htm
http://sz.eeju.com/show_rent_99461.htm
http://sz.eeju.com/show_rent_99181.htm
http://rent.sz.soufun.com/cz/CZ_MLS_17845812.htm
http://rent.sz.soufun.com/cz/CZ_MLS_17940110.htm
http://rent.sz.soufun.com/cz/CZ_MLS_17852140.htm ***
posted @
2006-03-28 15:22 xnabx 阅读(163) |
评论 (0) |
编辑 收藏
|
|
插入排序:
package org.rut.util.algorithm.support;
import org.rut.util.algorithm.SortUtil; /** * @author treeroot * @since 2006-2-2 * @version 1.0 */ public class InsertSort implements SortUtil.Sort{
/* (non-Javadoc) * @see org.rut.util.algorithm.SortUtil.Sort#sort(int[]) */ public void sort(int[] data) { int temp; for(int i=1;i<data.length;i++){ for(int j=i;(j>0)&&(data[j]<data[j-1]);j--){ SortUtil.swap(data,j,j-1); } } }
} 冒泡排序:
package org.rut.util.algorithm.support;
import org.rut.util.algorithm.SortUtil;
/** * @author treeroot * @since 2006-2-2 * @version 1.0 */ public class BubbleSort implements SortUtil.Sort{
/* (non-Javadoc) * @see org.rut.util.algorithm.SortUtil.Sort#sort(int[]) */ public void sort(int[] data) { int temp; for(int i=0;i<data.length;i++){ for(int j=data.length-1;j>i;j--){ if(data[j]<data[j-1]){ SortUtil.swap(data,j,j-1); } } } }
}
选择排序:
package org.rut.util.algorithm.support;
import org.rut.util.algorithm.SortUtil;
/** * @author treeroot * @since 2006-2-2 * @version 1.0 */ public class SelectionSort implements SortUtil.Sort {
/* * (non-Javadoc) * * @see org.rut.util.algorithm.SortUtil.Sort#sort(int[]) */ public void sort(int[] data) { int temp; for (int i = 0; i < data.length; i++) { int lowIndex = i; for (int j = data.length - 1; j > i; j--) { if (data[j] < data[lowIndex]) { lowIndex = j; } } SortUtil.swap(data,i,lowIndex); } }
}
Shell排序:
package org.rut.util.algorithm.support;
import org.rut.util.algorithm.SortUtil;
/** * @author treeroot * @since 2006-2-2 * @version 1.0 */ public class ShellSort implements SortUtil.Sort{
/* (non-Javadoc) * @see org.rut.util.algorithm.SortUtil.Sort#sort(int[]) */ public void sort(int[] data) { for(int i=data.length/2;i>2;i/=2){ for(int j=0;j<i;j++){ insertSort(data,j,i); } } insertSort(data,0,1); }
/** * @param data * @param j * @param i */ private void insertSort(int[] data, int start, int inc) { int temp; for(int i=start+inc;i<data.length;i+=inc){ for(int j=i;(j>=inc)&&(data[j]<data[j-inc]);j-=inc){ SortUtil.swap(data,j,j-inc); } } }
}
快速排序:
package org.rut.util.algorithm.support;
import org.rut.util.algorithm.SortUtil;
/** * @author treeroot * @since 2006-2-2 * @version 1.0 */ public class QuickSort implements SortUtil.Sort{
/* (non-Javadoc) * @see org.rut.util.algorithm.SortUtil.Sort#sort(int[]) */ public void sort(int[] data) { quickSort(data,0,data.length-1); } private void quickSort(int[] data,int i,int j){ int pivotIndex=(i+j)/2; //swap SortUtil.swap(data,pivotIndex,j); int k=partition(data,i-1,j,data[j]); SortUtil.swap(data,k,j); if((k-i)>1) quickSort(data,i,k-1); if((j-k)>1) quickSort(data,k+1,j); } /** * @param data * @param i * @param j * @return */ private int partition(int[] data, int l, int r,int pivot) { do{ while(data[++l]<pivot); while((r!=0)&&data[--r]>pivot); SortUtil.swap(data,l,r); } while(l<r); SortUtil.swap(data,l,r); return l; }
} 改进后的快速排序:
package org.rut.util.algorithm.support;
import org.rut.util.algorithm.SortUtil;
/** * @author treeroot * @since 2006-2-2 * @version 1.0 */ public class ImprovedQuickSort implements SortUtil.Sort {
private static int MAX_STACK_SIZE=4096; private static int THRESHOLD=10; /* (non-Javadoc) * @see org.rut.util.algorithm.SortUtil.Sort#sort(int[]) */ public void sort(int[] data) { int[] stack=new int[MAX_STACK_SIZE]; int top=-1; int pivot; int pivotIndex,l,r; stack[++top]=0; stack[++top]=data.length-1; while(top>0){ int j=stack[top--]; int i=stack[top--]; pivotIndex=(i+j)/2; pivot=data[pivotIndex]; SortUtil.swap(data,pivotIndex,j); //partition l=i-1; r=j; do{ while(data[++l]<pivot); while((r!=0)&&(data[--r]>pivot)); SortUtil.swap(data,l,r); } while(l<r); SortUtil.swap(data,l,r); SortUtil.swap(data,l,j); if((l-i)>THRESHOLD){ stack[++top]=i; stack[++top]=l-1; } if((j-l)>THRESHOLD){ stack[++top]=l+1; stack[++top]=j; } } //new InsertSort().sort(data); insertSort(data); } /** * @param data */ private void insertSort(int[] data) { int temp; for(int i=1;i<data.length;i++){ for(int j=i;(j>0)&&(data[j]<data[j-1]);j--){ SortUtil.swap(data,j,j-1); } } }
}
归并排序:
package org.rut.util.algorithm.support;
import org.rut.util.algorithm.SortUtil;
/** * @author treeroot * @since 2006-2-2 * @version 1.0 */ public class MergeSort implements SortUtil.Sort{
/* (non-Javadoc) * @see org.rut.util.algorithm.SortUtil.Sort#sort(int[]) */ public void sort(int[] data) { int[] temp=new int[data.length]; mergeSort(data,temp,0,data.length-1); } private void mergeSort(int[] data,int[] temp,int l,int r){ int mid=(l+r)/2; if(l==r) return ; mergeSort(data,temp,l,mid); mergeSort(data,temp,mid+1,r); for(int i=l;i<=r;i++){ temp[i]=data[i]; } int i1=l; int i2=mid+1; for(int cur=l;cur<=r;cur++){ if(i1==mid+1) data[cur]=temp[i2++]; else if(i2>r) data[cur]=temp[i1++]; else if(temp[i1]<temp[i2]) data[cur]=temp[i1++]; else data[cur]=temp[i2++]; } }
}
改进后的归并排序:
package org.rut.util.algorithm.support;
import org.rut.util.algorithm.SortUtil;
/** * @author treeroot * @since 2006-2-2 * @version 1.0 */ public class ImprovedMergeSort implements SortUtil.Sort {
private static final int THRESHOLD = 10;
/* * (non-Javadoc) * * @see org.rut.util.algorithm.SortUtil.Sort#sort(int[]) */ public void sort(int[] data) { int[] temp=new int[data.length]; mergeSort(data,temp,0,data.length-1); }
private void mergeSort(int[] data, int[] temp, int l, int r) { int i, j, k; int mid = (l + r) / 2; if (l == r) return; if ((mid - l) >= THRESHOLD) mergeSort(data, temp, l, mid); else insertSort(data, l, mid - l + 1); if ((r - mid) > THRESHOLD) mergeSort(data, temp, mid + 1, r); else insertSort(data, mid + 1, r - mid);
for (i = l; i <= mid; i++) { temp[i] = data[i]; } for (j = 1; j <= r - mid; j++) { temp[r - j + 1] = data[j + mid]; } int a = temp[l]; int b = temp[r]; for (i = l, j = r, k = l; k <= r; k++) { if (a < b) { data[k] = temp[i++]; a = temp[i]; } else { data[k] = temp[j--]; b = temp[j]; } } }
/** * @param data * @param l * @param i */ private void insertSort(int[] data, int start, int len) { for(int i=start+1;i<start+len;i++){ for(int j=i;(j>start) && data[j]<data[j-1];j--){ SortUtil.swap(data,j,j-1); } } }
} 堆排序:
package org.rut.util.algorithm.support;
import org.rut.util.algorithm.SortUtil;
/** * @author treeroot * @since 2006-2-2 * @version 1.0 */ public class HeapSort implements SortUtil.Sort{
/* (non-Javadoc) * @see org.rut.util.algorithm.SortUtil.Sort#sort(int[]) */ public void sort(int[] data) { MaxHeap h=new MaxHeap(); h.init(data); for(int i=0;i<data.length;i++) h.remove(); System.arraycopy(h.queue,1,data,0,data.length); }
private static class MaxHeap{ void init(int[] data){ this.queue=new int[data.length+1]; for(int i=0;i<data.length;i++){ queue[++size]=data[i]; fixUp(size); } } private int size=0;
private int[] queue; public int get() { return queue[1]; }
public void remove() { SortUtil.swap(queue,1,size--); fixDown(1); } //fixdown private void fixDown(int k) { int j; while ((j = k << 1) <= size) { if (j < size && queue[j]<queue[j+1]) j++; if (queue[k]>queue[j]) //不用交换 break; SortUtil.swap(queue,j,k); k = j; } } private void fixUp(int k) { while (k > 1) { int j = k >> 1; if (queue[j]>queue[k]) break; SortUtil.swap(queue,j,k); k = j; } }
}
}
SortUtil:
package org.rut.util.algorithm;
import org.rut.util.algorithm.support.BubbleSort; import org.rut.util.algorithm.support.HeapSort; import org.rut.util.algorithm.support.ImprovedMergeSort; import org.rut.util.algorithm.support.ImprovedQuickSort; import org.rut.util.algorithm.support.InsertSort; import org.rut.util.algorithm.support.MergeSort; import org.rut.util.algorithm.support.QuickSort; import org.rut.util.algorithm.support.SelectionSort; import org.rut.util.algorithm.support.ShellSort;
/** * @author treeroot * @since 2006-2-2 * @version 1.0 */ public class SortUtil { public final static int INSERT = 1;
public final static int BUBBLE = 2;
public final static int SELECTION = 3;
public final static int SHELL = 4;
public final static int QUICK = 5;
public final static int IMPROVED_QUICK = 6;
public final static int MERGE = 7;
public final static int IMPROVED_MERGE = 8;
public final static int HEAP = 9;
public static void sort(int[] data) { sort(data, IMPROVED_QUICK); } private static String[] name={ "insert","bubble","selection","shell","quick","improved_quick","merge","improved_merge","heap" }; private static Sort[] impl=new Sort[]{ new InsertSort(), new BubbleSort(), new SelectionSort(), new ShellSort(), new QuickSort(), new ImprovedQuickSort(), new MergeSort(), new ImprovedMergeSort(), new HeapSort() };
public static String toString(int algorithm){ return name[algorithm-1]; } public static void sort(int[] data, int algorithm) { impl[algorithm-1].sort(data); }
public static interface Sort { public void sort(int[] data); }
public static void swap(int[] data, int i, int j) { int temp = data[i]; data[i] = data[j]; data[j] = temp; } }
|
posted @
2006-03-27 17:58 xnabx 阅读(149) |
评论 (0) |
编辑 收藏
Unicode解决方案
Unicode:宽字节字符集(摘自windows核心编程)
Unicode是Apple和Xerox公司于1988年建立的一个技术标准。1991年,成立了一个集团机构负责Unicode的开发和推广应用。该集团由Apple、Compaq、IBM、Microsoft、Oracle、Silicon Graphics, Inc.、Sybase、Unisys和Xerox等公司组成。该集团负责维护Unicode标准。
Unicode提供了一种简单而又一致的表示字符串的方法。Unicode字符串中的所有字符都是16位的(两个字节)。它没有专门的字节来指明下一个字节是属于同一个字符的组成部分,还是一个新字符。这意味着你只需要对指针进行递增或递减,就可以遍历字符串中的各个字符,不再需要调用CharNext之类的函数。由于Unicode用一个16位的值来表示每个字符,因此总共可以得到65000个字符,这样,它就能够对世界各国的书面文字中的所有字符进行编码,远远超过了单字节字符集的256个字符的数目。
我们面临的基本问题是世界上的书写语言不能简单地用256个8位代码表示。以前的解决方案包括代码页和DBCS已被证明是不能满足需要的,而且也是笨拙的。那什么才是真正的解决方案呢?
身为程序编写者,我们经历过这类问题。如果事情太多,用8位数值已经不能表示,那么我们就试更宽的值,例如16位值。而且这很有趣的,正是Unicode被制定的原因。与混乱的256个字符代码映像,以及含有一些1字节代码和一些2字节代码的双字节字符集不同,Unicode是统一的16位系统,这样就允许表示65,536个字符。这对表示所有字符及世界上使用象形文字的语言,包括一系列的数学、符号和货币单位符号的集合来说是充裕的。
明白Unicode和DBCS之间的区别很重要。Unicode使用(特别在C程序设计语言环境里)“宽字符集”。“Unicode中的每个字符都是16位宽而不是8位宽。”在Unicode中,没有单单使用8位数值的意义存在。相比之下,在双字节字符集中我们仍然处理8位数值。有些字节自身定义字符,而某些字节则显示需要和另一个字节共同定义一个字符。
处理DBCS字符串非常杂乱,但是处理Unicode文字则像处理有秩序的文字。您也许会高兴地知道前128个Unicode字符(16位代码从0x0000到0x007F)就是ASCII字符,而接下来的128个Unicode字符(代码从0x0080到0x00FF)是ISO 8859-1对ASCII的扩展。Unicode中不同部分的字符都同样基于现有的标准。这是为了便于转换。希腊字母表使用从0x0370到0x03FF的代码,斯拉夫语使用从0x0400到0x04FF的代码,美国使用从0x0530到0x058F的代码,希伯来语使用从0x0590到0x05FF的代码。中国、日本和韩国的象形文字(总称为CJK)占用了从0x3000到0x9FFF的代码。
Unicode的最大好处是这里只有一个字符集,没有一点含糊。Unicode实际上是个人计算机行业中几乎每个重要公司共同合作的结果,并且它与ISO 10646-1标准中的代码是一一对应的。Unicode的重要参考文献是《The Unicode Standard,Version 2.0》(Addison-Wesley出版社,1996年)。这是一本特别的书,它以其它文件少有的方式显示了世界上书写语言的丰富性和多样性。此外,该书还提供了开发Unicode的基本原理和细节。
Unicode有缺点吗?当然有。Unicode字符串占用的内存是ASCII字符串的两倍。(然而压缩文件有助于极大地减少文件所占的磁盘空间。)但也许最糟的缺点是:人们相对来说还不习惯使用Unicode。身为程序编写者,这就是我们的工作
posted @
2006-03-27 17:49 xnabx 阅读(144) |
评论 (0) |
编辑 收藏
插件下载地址:
http://www.delphibbs.com/keylife/images/u88173/csdnkantie.rar
下载后解压到myIE的plugin目录即可。
例如我的解压后的目录:
D:\programs\Maxthon\Plugin\csdnkantie\
效果图:
http://blog.csdn.net/images/blog_csdn_net/pigo/36738/o_casdnkanite001.gif
http://blog.csdn.net/images/blog_csdn_net/pigo/36738/o_casdnkanite001.gif
posted @
2006-03-27 17:20 xnabx 阅读(119) |
评论 (0) |
编辑 收藏
pop-ent.21cn.com
@shareinfo.com.cn
posted @
2006-03-27 16:51 xnabx 阅读(139) |
评论 (0) |
编辑 收藏
在Connection上调用close方法会关闭Statement和ResultSet吗?
级联的关闭这听起来好像很有道理,而且在很多地方这样做也是正确的,通常这样写
Connection con = getConnection();//getConnection is your method
PreparedStatement ps = con.prepareStatement(sql);
ResultSet rs = ps.executeQuery();
……
///rs.close();
///ps.close();
con.close(); // NO!
这样做的问题在于Connection是个接口,它的close实现可能是多种多样的。在普通情况下,你用 DriverManager.getConnection()得到一个Connection实例,调用它的close方法会关闭Statement和 ResultSet。但是在很多时候,你需要使用数据库连接池,在连接池中的得到的Connection上调用close方法的时候,Connection可能并没有被释放,而是回到了连接池中。它以后可能被其它代码取出来用。如果没有释放Statement和ResultSet,那么在Connection上没有关闭的Statement和ResultSet可能会越来越多,那么……
相反,我看到过这样的说法,有人把Connection关闭了,却继续使用ResultSet,认为这样是可以的,引发了激烈的讨论,到底是怎么回事就不用我多说了吧。
所以我们必须很小心的释放数据库资源,下面的代码片断展示了这个过程
Connection con = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
con = getConnection();//getConnection is your method
ps = con.prepareStatement(sql);
rs = ps.executeQuery();
///...........
}
catch (SQLException ex) {
///错误处理
}
finally{
try {
if(ps!=null)
ps.close();
}
catch (SQLException ex) {
///错误处理
}
try{
if(con!=null)
con.close();
}
catch (SQLException ex) {
///错误处理
}
}
posted @
2006-03-23 22:27 xnabx 阅读(501) |
评论 (0) |
编辑 收藏
1. Open: Internet Options --> Content --> AutoComplete
2. Click button: 'Clear Forms' and 'Clear Passwords'
posted @
2006-03-23 22:07 xnabx 阅读(341) |
评论 (0) |
编辑 收藏
public class TranCharset {
private static final String PRE_FIX_UTF = "&#x";
private static final String POS_FIX_UTF = ";";
public TranCharset() {
}
/**
* Translate charset encoding to unicode
*
* @param sTemp charset encoding is gb2312
* @return charset encoding is unicode
*/
public static String XmlFormalize(String sTemp) {
StringBuffer sb = new StringBuffer();
if (sTemp == null || sTemp.equals("")) {
return "";
}
String s = TranCharset.TranEncodeTOGB(sTemp);
for (int i = 0; i < s.length(); i++) {
char cChar = s.charAt(i);
if (TranCharset.isGB2312(cChar)) {
sb.append(PRE_FIX_UTF);
sb.append(Integer.toHexString(cChar));
sb.append(POS_FIX_UTF);
} else {
switch ((int) cChar) {
case 32:
sb.append(" ");
break;
case 34:
sb.append(""");
break;
case 38:
sb.append("&");
break;
case 60:
sb.append("<");
break;
case 62:
sb.append(">");
break;
default:
sb.append(cChar);
}
}
}
return sb.toString();
}
/**
* 将字符串编码格式转成GB2312
*
* @param str
* @return
*/
public static String TranEncodeTOGB(String str) {
try {
String strEncode = TranCharset.getEncoding(str);
String temp = new String(str.getBytes(strEncode), "GB2312");
return temp;
} catch (java.io.IOException ex) {
return null;
}
}
/**
* 判断输入字符是否为gb2312的编码格式
*
* @param c 输入字符
* @return 如果是gb2312返回真,否则返回假
*/
public static boolean isGB2312(char c) {
Character ch = new Character(c);
String sCh = ch.toString();
try {
byte[] bb = sCh.getBytes("gb2312");
if (bb.length > 1) {
return true;
}
} catch (java.io.UnsupportedEncodingException ex) {
return false;
}
return false;
}
/**
* 判断字符串的编码
*
* @param str
* @return
*/
public static String getEncoding(String str) {
String encode = "GB2312";
try {
if (str.equals(new String(str.getBytes(encode), encode))) {
String s = encode;
return s;
}
} catch (Exception exception) {
}
encode = "ISO-8859-1";
try {
if (str.equals(new String(str.getBytes(encode), encode))) {
String s1 = encode;
return s1;
}
} catch (Exception exception1) {
}
encode = "UTF-8";
try {
if (str.equals(new String(str.getBytes(encode), encode))) {
String s2 = encode;
return s2;
}
} catch (Exception exception2) {
}
encode = "GBK";
try {
if (str.equals(new String(str.getBytes(encode), encode))) {
String s3 = encode;
return s3;
}
} catch (Exception exception3) {
}
encode = "BIG5";
try {
if (str.equals(new String(str.getBytes(encode), encode))) {
String s4 = encode;
return s4;
}
} catch (Exception exception3) {
}
return "";
}
public static void main(String args[]) {
System.out.println(XmlFormalize("下载"));
}
}
posted @
2006-03-23 09:16 xnabx 阅读(148) |
评论 (0) |
编辑 收藏
问题:
如何在文本框中只允许输入汉字,字母数字或者其他符号文字都不可以呢?
处理:
//javascript
var re=/[^\x00-\xff]/g;
if(re.test(你要测试的值))
{
//是汉字
}
注:用ascII码控制。好像汉字都是负数
System.out.println(Pattern.compile("[\u4e00-\u9fa5]").matcher("a").find());
//[\u4e00-\u9fa5] 中文的正则表达式
//"a" 你想判断的字符
posted @
2006-03-22 22:39 xnabx 阅读(503) |
评论 (1) |
编辑 收藏
问题:
在ArrayList 应用中有这样的代码:
ArrayList a=new ArrayList();
a.add(...);
Iterator i=a.iterator();
理解:Iterator i=a.iterator();
Iterator 是一个接口,在上面a.iterator()方法的作用是返回一个接口
hasmore(),next()是怎么被实现的?
处理:
迭代模式
ArrayList内部有一个实现了Iterator 接口的类,a.iterator就是返回它内部类的一个实例,即返回一个实现了的iterator接口的类。
接口是一个类型,相当于一个父类型(supertype),可以用一个接口引用一个实现了此接口的类的实例。这样只能用接口提供的方法来访问此对象,可以限制访问,隐藏具体实现。
posted @
2006-03-22 22:35 xnabx 阅读(241) |
评论 (0) |
编辑 收藏
我想遍历所有key为username的值,比如:
每一个登陆用户都有一个username的session,我如何判断有多少个这样的session及其值呢?
处理:
HttpSessionBindingListener进行监听,维护一个全局变量
posted @
2006-03-22 17:13 xnabx 阅读(1093) |
评论 (0) |
编辑 收藏
首先明确一下,楼主的问题应该是比较 JDK 和 JRE (而不是 JVM,因为 JDK 和 JRE 里面都包含 JVM)。
顾名思义,JDK 比 JRE 多出来的东西,就是在开发过程中要用到的一些东西,比如 javac、javadoc、keytool 等工具,还有其它的一些东西(比如 API 文档)。一般来说,这些东西在软件开发完成交付运行之后就用不到了。不过也有例外,比如要在 Tomcat 里跑 JSP 的话,就需要 javac。
posted @
2006-03-22 16:14 xnabx 阅读(129) |
评论 (0) |
编辑 收藏
public:公有的,说明该类成员可被所有的对象使用
protected:保护的,说明该类成员能被同一类中的其他成员,或其子类成员,或同一包中的其他类访问,不能被其他包的非子类访问
无:默认的.当修饰符默认时,说明该类成员能被同一类中的其他成员,或同一包中的其他类访问,不能被其他包的类访问
private:私有的,说明该类成员只能被同一类中的其他成员访问,不能被其他类的成员访问,也不能被子类成员访问.
posted @
2006-03-22 15:57 xnabx 阅读(166) |
评论 (0) |
编辑 收藏
1. 有一个ArrayList,里面包含N个Integer,其中的Integer都是由1至N+1的数字构成,并且不重复,但是有一个1至N+1的数字对应的Integer
不存在ArrayList中,求该数。
public static void main(String[] args){
ArrayList list= new ArrayList();
list.add(Integet(7));
list.add(Integet(8));
list.add(Integet(1));
list.add(Integet(2));
list.add(Integet(3));
list.add(Integet(4));
list.add(Integet(5));
}
public int getMissing(ArrayList list){
int len = list.size();
for (int i = 1; i <= len; i++) {
int j = 0;
while (j < len) {
Integer Val = (Integer) list.get(j);
int value = Val.intValue();
if (i == value)
break;
j++;
}
if (j == len) {
return j;
}
}
return -1;
}
2. 有一个二叉树类如下。然后写出遍历二叉树的方法printTree。
class BinaryTree{
class Node{
String value;
Node leftNode;
Node rightNode;
}
public void printTree(Node root){
reDo(root,0);
}
public void reDo(Node node,int depth){
if(node != null) {
System.out.println(space()+node.value);
reDo(node.leftNode,depth+1);
reDo(node.rightNode,depth+1);
}
}
public String space(int len){
StringBuffer bs = new StringBuffer();
for(int i=0; i<bs.length();i++){
bs.append(" ");
}
}
}
3. 有int型数字如下,123,1234,12345,123456,1234567,12345678,123456789
求一个方法,输出123 1,234 12,345 123,456 1,234,567 12,345,678 123,456,789
public String printComma(int input){
StringBuffer bs = new StringBuffer(input + "");
int index = bs.length() - 3;
while (index > 0) {
bs.insert(index, ",");
index = index - 3;
}
return bs.toString();
}
4.equals(),hasCode()的作用。
5.Object对象有哪些方法?
equals(),clone(),notify(),notifyAll(),wait(),wait(long time),wait(long time,int nanos)
hasCode(),toString(),getClass()。
6.RuntimeException,非RuntimeException的区别和例子。
7.Singleton模式
8.共享数据在web中的范围
page,request,seesion,application
9.Servlet的生命周期。
servlet有良好的生存期定义,包括加载,实例化,初始化,处理请求,服务结束。由javax.servlet.Servlet接口以下方法表达
init(),service(),destroy()。
10.abstract和interface的区别。
abstract中可以有自己方法的定义和说明,interface只是存在变量和方法的定义。当需要的时候,我们可以inplements多个接口,但是只能
extends一个类。
11.实现多线程有哪几种方法。
第一种,class MyThread extends Thread{..} MyThread t = new MyThread(); t.start();
第二中,class UrThread implements Runnable{...} Thread t = new Thread(new UrThread()); t.start();
12.ArrayList和Vector的区别。
Vector中的方法是synchronized的,性能上较ArrayList差点。
当增长时,Vector默认增长原来的一倍,ArrayList默认增长原来的一半。
13.java实现序列化的方法是实现serializable接口,具体怎么做。
14.String a = "test"; String b = new String("test"); a==b (false)
String c = "te"+"st"; a==c (true)
15.
public synchronized void aMethod1(){
}
public void b aMethod(){
synchronized("test"){
}
}
A a1 = new A();
A a2 = new A();
a1.aMethod1();
a2.aMethod1();//不需要等待
a1.aMethod2();
a2.aMethod2();//需要等待
16.编程性能方法的讨论,ArrayList,HashMap,StringBuffer。
17.Struts的DispatchAction,Action的区别。RequestProcessor的作用。
posted @
2006-03-22 15:53 xnabx 阅读(218) |
评论 (0) |
编辑 收藏
问题一:
有int型数字如下,123,1234,12345,123456,1234567,12345678,123456789
求一个方法,输出123 1,234 12,345 123,456 1,234,567 12,345,678 123,456,789
处理:
public void testPrint(int num) {
DecimalFormat format = new DecimalFormat("#,###");
System.out.println(format.format(num));
}
问题二、
double类型如何正确的转换为字符串类型
处理:
double d = 0.001;
DecimalFormat df1 = new DecimalFormat("#.####");
String result = df1.format(d);
System.out.println(result);
posted @
2006-03-22 15:53 xnabx 阅读(895) |
评论 (2) |
编辑 收藏
Singleton模式主要作用是保证在Java应用程序中,一个类只有一个实例存在。解释下面的代码是怎么保证只有一个实例的?
public class Singleton {
private Singleton(){}
private static Singleton instance = new Singleton();
public static Singleton getInstance() {
return instance;
}
}
处理:
因为构造函数是私有的,用户不能自己实例对象 private Singleton(){}
而且指向这个唯一的对象的引用也是私有,只能通过getInstance方法返回对象的引用
getInstance方法正实现了保证唯一对象的功能
posted @
2006-03-22 14:19 xnabx 阅读(191) |
评论 (0) |
编辑 收藏
上一周的周一和周日
Calendar cl = Calendar.getInstance();
cl.getTime();
cl.add(cl.DAY_OF_YEAR, -cl.get(cl.DAY_OF_WEEK)+1);//get previous Sunday
System.out.println(cl.get(cl.YEAR) + "-" + (cl.get(cl.MONTH)+1) + "-"
+ cl.get(cl.DAY_OF_MONTH) +"week:"+(cl.get(cl.DAY_OF_WEEK)-1));
cl.add(cl.DAY_OF_YEAR, -6 ); //get previous Monday
System.out.println(cl.get(cl.YEAR) + "-" + (cl.get(cl.MONTH)+1) + "-"
+ cl.get(cl.DAY_OF_MONTH) +"week:"+(cl.get(cl.DAY_OF_WEEK)-1));
posted @
2006-03-22 14:08 xnabx 阅读(156) |
评论 (0) |
编辑 收藏
用户登陆,登陆成功后将用户名和密码保存到session中,然后转到登陆成功后的页面。
现在有一个问题,如果有人看到了某一个页面的url,可以直接在地址栏直接输入url进去,由于session中有用户名和密码,所以系统认为他也是合法的用户,如何解决?
处理:
一、 session是存在服务器上面的
session有两种方式一个是cookies一个就是url重写
但是不管是哪种 都是向服务器传达的是session的ID
所以解决的方法就是
为session设置一个存活期:session.setMaxInactiveInterval(10);
二、让浏览器不再缓存
<%
response.setHeader("Pragma","No-cache");
response.setHeader("Cache-Control","no-cache");
response.setDateHeader("Expires", 0);
%>
posted @
2006-03-22 09:31 xnabx 阅读(156) |
评论 (0) |
编辑 收藏
<%@ taglib uri="http://www.opensymphony.com/oscache" prefix="oscache" %>
<%
try{
session.invalidate();
}catch(Exception e){}
String scope = "application";
if (request.getParameter("scope") != null)
{
scope = request.getParameter("scope");
}
boolean refresh = false;
if (request.getParameter("refresh") != null)
{
refresh = true;
}
boolean forceCacheUse = false;
if (request.getParameter("forceCacheUse") != null)
{
forceCacheUse = true ;
}
%>
<oscache:cache duration="40s" refresh="<%= request.getParameter("refresh") == null ? false : true %>" scope="<%= scope %>">
// *****************************页面部分*********************************//
</oscache:cache>
posted @
2006-03-21 12:02 xnabx 阅读(159) |
评论 (0) |
编辑 收藏
如interface A{..}
这是你提供个某个部分的一个接口,然后
public class B implements A{...}
B是实现接口的一个类
A a=new B();
对象a的形式类型为A,实际指向一个B,可是你只能使用接口中已经规定的方法,以后你无论怎么修改B,都不会影响到其他部分对对象a的使用
这样可以实现多态,如果B和C都实现了接口A,那么我可以声明一个A的对象变量,而实际的实例可能是B也可能是C
多态----对同一个方法的调用,不同的实现类,有不同的响应结果
posted @
2006-03-21 09:26 xnabx 阅读(118) |
评论 (0) |
编辑 收藏
new String(str.getBytes("gbk"),"utf-8")
java中的字符串都是用unicode编码来表示的,GBK编码的汉字应该是从程序外面获得的(如数据库中,或文本文件中), 例如从本地文本文件1.txt以字节流方式读取,得到的字节数组buf就是以GBK编码的字节数组,然后用GBK解码成Unicode字符串str = new String(buf,"GBK"); 然后再编码成
UTF-8的字节数组str.getBytes("UTF-8"),这样才算真正的转换
posted @
2006-03-20 22:13 xnabx 阅读(1287) |
评论 (1) |
编辑 收藏
问题:
<iframe name="I1" src="cs7.jsp" height="300" width="200"></iframe><br>
<iframe name="I2" id="I2" src="cs8.jsp" height="300" width="200">iframe>
如何把I1的值传到I2里的一个input里?
处理:
document.getElementById("I2").src="cs8.jsp?param=p"
然后再cs8.jsp中接受param值放到input中
posted @
2006-03-20 13:50 xnabx 阅读(327) |
评论 (0) |
编辑 收藏
问题:
A.JSP如下:
……
<iframe src="B.jsp" id="B" frameborder="0" border="0"></iframe>
……
B.JSP如下,里面有一个C的JS方法
……
<script type="text/javascript">
function C()
{
}
</script>
……
请问如何在A.jsp里调用该C方法?
处理:
用b.document.script.c()
跨域脚本访问可能造成严重的安全问题。一些用户禁用了跨域脚本访问。
posted @
2006-03-20 13:43 xnabx 阅读(992) |
评论 (0) |
编辑 收藏
问题:<html>
<iframe frameborder=0 width=600 height=50 marginheight=0 marginwidth=0 scrolling=no src="applytest.jsp" id="applytest"></iframe>
<FORM name="form1" METHOD="POST" ACTION="customer.do?command=addapplystudent" onsubmit="return check_data()">
<table>
<tr>
<TD align="left">姓名 </TD>
<td><input type="text" name="cname">
<font color="#FF0000">*</font>
</td>
</tr>
</table>
</html>
///////////////////////////////////////////////////////////
现在在Action里取到的学生所在地区的id总是空,我现在请教各位------怎么取到iframe中的某个参数的值?
处理:
可以通过iframe的id="applytest"来访问其页面的标签,如document.all.applytest.all.xxx来访问其中的名为xxx的标签.通过再在主页面设置hidden将其值拷贝一下就行.
posted @
2006-03-20 13:09 xnabx 阅读(1243) |
评论 (0) |
编辑 收藏
问题一、
<table width="99%" border="0" align="center" cellpadding="0" cellspacing="0">
<tr>
<td colspan="2"><iframe frameborder=no
marginheight=0 marginwidth=0 name=schistory scrolling=no
src="frame2.htm" width=100%> </iframe></td>
</tr>
</table>
现在的问题是当frame2.htm显示的内容很长时,有些内容看不到;如何做到该网页随iframe中嵌入的网页内容长度自动出现滚动条,并且这滚动条不是出现在iframe中
处理:
你这个属于让iframe的子页面决定父页面的高度。
写javascript吧。
<script language="Javascript">
function window.onload()
{
parent.document.all("mainFrame").style.height=document.body.scrollHeight+670;
}
</script>
写在iframe调用的子页面里面
后面的670是父页面比子页面高的高度
问题二、如何动态控制IFrame的长和宽
主页面要放置一个IFrame用于嵌套显示子页面的信息,但是子页面的数据多少不一,导致子页面可能会很长或很短,要动态控制IFrame的高低随子页面的长短而变化。
主页面如下:
<HTML>
<HEAD>
<TITLE> New Document </TITLE>
</HEAD>
<BODY >
<TABLE>
<TR>
<TD>
<iframe id="frmTest" height="100px" name="frmTest" src="in.html"></iframe>
</TD>
</TR>
</TABLE>
</BODY>
</HTML>
子页面只需要做如下处理即可:
在页面的最下端添加如下JS脚本:
<script language=javascript>
window.parent.document.all("frmTest").style.height = document.body.scrollHeight + 10;
</script>
其中frmTest即为Main页面的IFrame的ID。
posted @
2006-03-20 13:03 xnabx 阅读(2375) |
评论 (3) |
编辑 收藏
2.下面代码的输出是什么?一共在内存中生成了几个String对象?为什么?
String s1 = “aaa”;
String s2 = “aaa”;
String s3 = new String(“aaa”);
String s4 = new String(“AAA”);
System.out.println(s1 == s2);
System.out.println(s1 == s3);
System.out.println(s1.equals(s3));
3.下列程序在1处是否会有异常,如果没有,输出是什么?是否会运行到2处,如果会,输出是什么?为什么会有这样的结果?
public class TestClass {
public void test1() {
List list = new ArrayList();
test2(list);
System.out.println(list.size()); // 1处
test3(list);
System.out.println(list.size()); // 2处
}
public void test2(List list) {
list = null;
}
public void test3(List list) {
list.add(“aaaa”);
}
}
4.请选出下面哪些描述是正确的。
public class ClassA {
public synchronized void a(){
}
public synchronized void b(){
}
}
2 instances of ClassA had been instantiated obj1 and obj2.
Which statements about thread are true?
1)One thread is calling obj1.a(), another thread can call obj1.b(). .
2)One thread is calling obj1.a(), another thread cannot call obj1.b().
3)One thread is calling obj1.a(), another thread can call obj2.b(). .
4)One thread is calling obj1.a(), another thread cannot call obj2.b().
5.下面的程序输出是什么?为什么?
public class Parent {
public void test(ArrayList list) {
System.out.println("invoke parent's test method");
}
public static void main(String[] args) {
Child a = new Child();
ArrayList list = new ArrayList();
a.test(list);
}
}
class Child extends Parent {
public void test(List list) {
System.out.println("invoke child's test method");
}
}
6.下面的程序输出是什么?为什么?
public class Parent {
public void test(List list) {
System.out.println("invoke parent's test method");
}
public static void main(String[] args) {
Child a = new Child();
ArrayList list = new ArrayList();
a.test(list);
}
}
class Child extends Parent {
public void test(List list) {
System.out.println("invoke child's test method");
}
}
7.仔细分析下面的程序,写出程序的输出结果。
public class Parent {
{
System.out.println("parent instance block");
}
public void test() {
System.out.println("parent test method");
}
static {
System.out.println("parent static block");
}
public Parent() {
System.out.println("parent constructor");
test();
}
public static void main(String[] args) {
new Child();
}
}
class Child extends Parent {
private static int staticValue = 20;
private int instanceValue = 20;
{
System.out.println("child instance block");
}
public void test() {
System.out.println("child test method");
System.out.println("static value is: " + staticValue);
System.out.println("instance value is: " + instanceValue);
}
static {
System.out.println("child static block");
}
public Child() {
System.out.println("child constructor");
}
}
8.下面程序的输出是什么?
public class TestException {
public void test1() {
int result = test2();
System.out.println(result);
}
public int test2() {
try{
String s = null;
s.substring(0, 1);
return 1;
} catch(Exception e) {
return 2;
} finally {
return 3;
}
}
public static void main(String[] args) {
(new TestException()).test1();
}
}
9.请写出数据库查询操作的伪代码,程序不需要通过编译,只要思路正确,关键步骤不丢失就可以了。注意异常的捕获,IO流的关闭。可能用到的类或接口有(Connection,DriverManager, Statement, PreparedStatement, ResultSet, SQLException)。
posted @
2006-03-19 23:12 xnabx 阅读(138) |
评论 (0) |
编辑 收藏
5.1.1·介绍
什么是异常?在Java编程语言中,异常类定义程序中可能遇到的轻微 的错误条件。可以写代码来处理异常并继续程序执行,而不是让程序 中断。在程序执行中,任何中断正常程序流程的异常条件就是错误或 ]异常。例如,发生下列情况时,会出现异常: - 想打开的文件不存在 - 网络连接中断 - 受控操作数超出预定范围 - 非常感兴趣地正在装载的类文件丢失
在Java编程语言中,错误类定义被认为是不能恢复的严重错误条件。在 大多数情况下,当遇到这样的错误时,建议让程序中断。Java编程语言 实现C++异常来帮助建立弹性代码。在程序中发生错误时,发现错误的 方法能抛出一个异常到其调用程序,发出已经发生问题的信号。然后, 调用方法捕获抛出的异常,在可能时,再恢复回来。这个方案给程序员 一个写处理程序的选择,来处理异常。通过浏览API,可以决定方法抛出 的是什么样的异常。
5.1.2·实例
考虑一下HelloWorld.java程序版本的简单扩展,它通过信息来循环: 1. public class HelloWorld { 2. public static void main (String args[]) { 3. int i = 0; 4. 5. String greetings [] = { 6. "Hello world!", 7. "No, I mean it!", 8. "HELLO WORLD!!" 9. }; 10. 11. while (i < 4) { 12. System.out.println (greetings[i]); 13. i++; 14. } 15. } 16. }
正常情况下,当异常被抛出时,在其循环被执行四次之后,程序终止,并带有 错误信息,就象前面所示的程序那样。 1. c:\student\> java HelloWorld 2. Hello world! 3. No, I mean it! 4. HELLO WORLD!! 5. java.lang.ArrayIndexOutOfBoundsException: 3 6. at HelloWorld.main(HelloWorld.java:12)
异常处理允许程序捕获异常,处理它们,然后继续程序执行。它是分层把关, 因此,错误情况不会介入到程序的正常流程中。特殊情况发生时,在与正常 执行的代码分离的代码块中被处理。这就产生了更易识别和管理的代码。
5.2·异常处理
Java编程语言提供了一个来考虑哪个异常被抛出以及如何来恢复它的机制。
·try和catch语句
要处理特殊的异常,将能够抛出异常的代码放入try块中,然后创建相应的 catch块的列表,每个可以被抛出异常都有一个。如果生成的异常与catch 中提到的相匹配,那么catch条件的块语句就被执行。在try块之后,可能 有许多catch块,每一个都处理不同的异常。 1. try { 2. // code that might throw a particular exception 3. } catch (MyExceptionType e) { 4. // code to execute if a MyExceptionType exception is thrown 5. } catch (Exception e) { 6. // code to execute if a general Exception exception is thrown 7. }
5.2.1·调用栈机制
如果方法中的一个语句抛出一个没有在相应的try/catch块中处理的异常, 那么这个异常就被抛出到调用方法中。如果异常也没有在调用方法中被处理, 它就被抛出到该方法的调用程序。这个过程要一直延续到异常被处理。 如果异常到这时还没被处理,它便回到main(),而且,即使main()不处理它, 那么,该异常就异常地中断程序。考虑这样一种情况,在该情况中main() 方法调用另一个方法(比如,first()),然后它调用另一个 (比如,second())。如果在second()中发生异常,那么必须做一个检查 来看看该异常是否有一个catch;如果没有,那么对调用栈(first())中的 下一个方法进行检查,然后检查下一个(main())。如果这个异常在该 调用栈上没有被最后一个方法处理,那么就会发生一个运行时错误, 程序终止执行。
5.2.2·finally语句
finally语句定义一个总是执行的代码块,而不考虑异常是否被捕获。 下述样板代码来自Frank Yellin弗兰克叶林的白皮书《Java中的低级安全》: 1. try { 2. startFaucet(); 3. waterLawn(); 4. } 5. finally { 6. stopFaucet(); 7. }
在前面的例子中,即使异常在打开开关或给草地浇水时发生,开关也能被关掉。 try 后面的括号中的代码被称做保护码。如果终止程序的System.exit() 方法在保护码内被执行,那么,这是finally语句不被执行的唯一情况。 这就暗示,控制流程能偏离正常执行顺序,比如,如果一个return语句 被嵌入try块内的代码中,那么,finally块中的代码应在return前执行。
5.2.3·重访前例
下面的例子是第169页main()方法的重写。本程序以前的版本中产生的 异常被捕获,数组索引重新设定,使下述程序继续运行。 1. public static void main (String args[]) { 2. int i = 0; 3. String greetings [] = { 4. "Hello world!", 5. "No, I mean it!", 6. "HELLO WORLD!!" 7. }; 8. while (i < 4) { 9. try { 10. System.out.println (greetings[i]); 11. } catch (ArrayIndexOutOfBoundsException e){ 12. System.out.println( "Re-setting Index Value"); 13. i = -1; 14. } finally { 15. System.out.println("This is always printed"); 16. } 17. i++; 18. } // end while() 19. } // end main()
当循环被执行时,下述在屏幕上出现的信息将改变。
1. Hello world! 2. This is always printed 3. No, I mean it! 4. This is always printed 5. HELLO WORLD!! 6. This is always printed 7. Re-setting Index Value 8. This is always printed
5.3·异常分类
在Java编程语言中,异常有三种分类。Java.lang.Throwable类充当所有 对象的父类,可以使用异常处理机制将这些对象抛出并捕获。在Throwable 类中定义方法来检索与异常相关的错误信息,并打印显示异常发生的栈 跟踪信息。它有Error和Exception两个基本子类. Throwable类不能使用,而使用子类异常中的一个来描述任何特殊异常。 每个异常的目的描述如下: - Error表示恢复不是不可能但很困难的情况下的一种严重问题。比如说 内存溢出。不可能指望程序能处理这样的情况。 - RuntimeException表示一种设计或实现问题。也就是说,它表示如果 程序运行正常,从不会发生的情况。比如,如果数组索引扩展不超出 数组界限,那么,ArrayIndexOutOfBoundsException异常从不会抛出。 比如,这也适用于取消引用一个空值对象变量。因为一个正确设计和 实现的程序从不出现这种异常,通常对它不做处理。这会导致一个 运行时信息,应确保能采取措施更正问题,而不是将它藏到谁也不 注意的地方。 - 其它异常表示一种运行时的困难,它通常由环境效果引起,可以进行 处理。例子包括文件未找到或无效URL异常(用户打了一个错误的URL), 如果用户误打了什么东西,两者都容易出现。这两者都可能因为用户 错误而出现,这就鼓励程序员去处理它们。
5.4·共同异常
Java编程语言提供几种预定义的异常。下面是可能遇到的更具共同性的 异常中的几种:
- ArithmeticException—整数被0除,运算得出的结果。 - int I =12 / 0; - NullPointerException—当对象没被实例化时,访问对象的属性或 方法的尝试: - Date d= null; - System.out.println(d.toString()); - NegativeArraySizeException—创建带负维数大小的数组的尝试。 - ArrayIndexoutofBoundsException—访问超过数组大小范围的一个元 素的尝试。 - SecurityException—典型地被抛出到浏览器中,SecurityManager类将 抛出applets的一个异常,该异常企图做下述工作(除非明显地得到允许): - 访问一个本地文件 - 打开主机的一个socket,这个主机与服务于applet的主机不是同一个。 - 在运行时环境中执行另一个程序
5.5·处理或声明规则
为了写出健壮的代码,Java编程语言要求,当一个方法在栈(即,它已经被 调用)上发生Exception(它与Error或RuntimeException不同)时,那么, 该方法必须决定如果出现问题该采取什么措施。程序员可以做满足该要求 的两件事:
第一,通过将Try{}catch(){}块纳入其代码中,在这里捕获给被 命名为属于某个超类的异常,并调用方法处理它。即使catch块是空的, 这也算是处理情况。 第二,让被调用的方法表示它将不处理异常,而且该异常将被抛回到它所 遇到的调用方法中。它是按如下所示通过用throws子句标记的该调用方法 的声明来实现的: public void troublesome() throws IOException 关键字throws之后是所有异常的列表,方法可以抛回到它的调用程序中。 尽管这里只显示了一个异常,如果有成倍的可能的异常可以通过该方法 被抛出,那么,可以使用逗号分开的列表。
是选择处理还是选择声明一个异常取决于是否给你自己或你的调用程序一个 更合适的候选的办法来处理异常。注—由于异常类象其它类一样被组编到 层次中,而且由于无论何时想要使用超类都必须使用子类, 因此,可以 捕获异常“组”并以相同的捕获代码来处理它们。例如,尽管 IOExceptions(EOFException,FileNotFoundException等等) 有几种不同的类型,通过俘获IOException,也可以捕获 IOException任何子类的实例。
5.6·创建自己的异常
5.6.1·介绍
用户定义异常是通过扩展Exception类来创建的。这种异常类可以包含 一个“普通”类所包含的任何东西。下面就是一个用户定义异常类例子, 它包含一个构造函数、几个变量以及方法:
1. public class ServerTimedOutException extends Exception { 2. private String reason; 3. private int port; 4. public ServerTimedOutException (String reason,int port){ 5. this.reason = reason; 6. this.port = port; 7. } 8. public String getReason() { 9. return reason; 10. } 11. public int getPort() { 12. return port; 13. } 14. }
使用语句来抛出已经创建的异常: throw new ServerTimedOutException ("Could not connect", 80);
5.6.2·实例
考虑一个客户服务器程序。在客户代码中,要与服务器连接,并希望 服务器在5秒钟内响应。如果服务器没有响应,那么,代码就如下所述 抛出一个异常(如一个用户定义的ServerTimedOutException)。
1. public void connectMe(String serverName) throws ServerTimedOutException { 2. int success; 3. int portToConnect = 80; 4. success = open(serverName, portToConnect); 5. if (success == -1) { 6. throw new ServerTimedOutException( 7. "Could not connect", 80); 8. } 9. }
要捕获异常,使用try语句: 1. public void findServer() { 2. . . . 3. try { 4. connectMe(defaultServer); 5. } catch(ServerTimedOutException e) { 6. System.out.println("Server timed out, trying alternate"); 7. try { 8. connectMe(alternateServer); 9. } catch (ServerTimedOutException e1) { 10. System.out.println("No server currently available"); 11. } 12. } 13. .. . 注—try和catch块可以如前例所述那样被嵌套。
也可能部分地处理一个异常然后也将它抛出。如: try { ..... ..... } catch (ServerTimedOutException e) { System.out.println("Error caught "); throw e; }
|
posted @
2006-03-19 22:56 xnabx 阅读(229) |
评论 (0) |
编辑 收藏
private static void getMaxdays(int year,int mon){
Calendar ca = Calendar.getInstance();
ca.clear();
ca.set(Calendar.YEAR,year);
ca.set(Calendar.MONTH,mon+1);
int max = ca.getActualMaximum(Calendar.DAY_OF_MONTH);
System.out.println(max);
}
posted @
2006-03-19 22:48 xnabx 阅读(313) |
评论 (0) |
编辑 收藏
abstract class和interface是Java语言中对于抽象类定义进行支持的两种机制,正是由于这两种机制的存在,才赋予了Java强大的面向对象能力。
接口:没有提供任何具体实现,可以说是一个极度抽象的类,他允许你创建一个能够被向上转型为不止一种基类型的类,以此来实现多重继承。
抽象类:包含一种或多种抽象方法的类,且可以提供具体的实现。定义抽象类后,其他类可以对他进行扩充并且通过实现其中的抽象方法,使用抽象类具体话。
Java中的接口和抽象类的区别:接口中没有属性,而且所有的方法都是抽象的,而抽象类可以有属性,而且可以有抽象方法,也可以有实现的方法。但两者都不能被实例话。
使用的时候,一个类可以继承多个接口,但只能继承一个抽象类。
一、理解抽象类
abstract class和interface在Java语言中都是用来进行抽象类(本文中的抽象类并非从abstract class翻译而来,它表示的是一个抽象体,而abstract class为Java语言中用于定义抽象类的一种方法,请读者注意区分)定义的,那么什么是抽象类,使用抽象类能为我们带来什么好处呢?
在面向对象的概念中,我们知道所有的对象都是通过类来描绘的,但是反过来却不是这样。并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。抽象类往往用来表征我们在对问题领域进行分析、设计中得出的抽象概念,是对一系列看上去不同,但是本质上相同的具体概念的抽象。
比如:如果我们进行一个图形编辑软件的开发,就会发现问题领域存在着圆、三角形这样一些具体概念,它们是不同的,但是它们又都属于形状这样一个概念,形状这个概念在问题领域是不存在的,它就是一个抽象概念。正是因为抽象的概念在问题领域没有对应的具体概念,所以用以表征抽象概念的抽象类是不能够实例化的。
在面向对象领域,抽象类主要用来进行类型隐藏。我们可以构造出一个固定的一组行为的抽象描述,但是这组行为却能够有任意个可能的具体实现方式。这个抽象描述就是抽象类,而这一组任意个可能的具体实现则表现为所有可能的派生类。模块可以操作一个抽象体。由于模块依赖于一个固定的抽象体,因此它可以是不允许修改的;同时,通过从这个抽象体派生,也可扩展此模块的行为功能。熟悉OCP的读者一定知道,为了能够实现面向对象设计的一个最核心的原则OCP(Open-Closed Principle),抽象类是其中的关键所在。
二、从语法定义层面看abstract class和interface
在语法层面,Java语言对于abstract class和interface给出了不同的定义方式,下面以定义一个名为Demo的抽象类为例来说明这种不同。使用abstract class的方式定义Demo抽象类的方式如下:
abstract class Demo {
abstract void method1();
abstract void method2();
…
}
使用interface的方式定义Demo抽象类的方式如下:
interface Demo {
void method1();
void method2();
…
}
在abstract class方式中,Demo可以有自己的数据成员,也可以有非abstarct的成员方法,而在interface方式的实现中,Demo只能够有静态的不能被修改的数据成员(也就是必须是static final的,不过在interface中一般不定义数据成员),所有的成员方法都是abstract的。从某种意义上说,interface是一种特殊形式的abstract class。
从编程的角度来看,abstract class和interface都可以用来实现"design by contract"的思想。但是在具体的使用上面还是有一些区别的。
首先,abstract class在Java语言中表示的是一种继承关系,一个类只能使用一次继承关系。但是,一个类却可以实现多个interface。也许,这是Java语言的设计者在考虑Java对于多重继承的支持方面的一种折中考虑吧。
其次,在abstract class的定义中,我们可以赋予方法的默认行为。但是在interface的定义中,方法却不能拥有默认行为,为了绕过这个限制,必须使用委托,但是这会 增加一些复杂性,有时会造成很大的麻烦。
在抽象类中不能定义默认行为还存在另一个比较严重的问题,那就是可能会造成维护上的麻烦。因为如果后来想修改类的界面(一般通过abstract class或者interface来表示)以适应新的情况(比如,添加新的方法或者给已用的方法中添加新的参数)时,就会非常的麻烦,可能要花费很多的时间(对于派生类很多的情况,尤为如此)。但是如果界面是通过abstract class来实现的,那么可能就只需要修改定义在abstract class中的默认行为就可以了。
同样,如果不能在抽象类中定义默认行为,就会导致同样的方法实现出现在该抽象类的每一个派生类中,违反了"one rule,one place"原则,造成代码重复,同样不利于以后的维护。因此,在abstract class和interface间进行选择时要非常的小心。
三、从设计理念层面看abstract class和interface
上面主要从语法定义和编程的角度论述了abstract class和interface的区别,这些层面的区别是比较低层次的、非本质的。本文将从另一个层面:abstract class和interface所反映出的设计理念,来分析一下二者的区别。作者认为,从这个层面进行分析才能理解二者概念的本质所在。
前面已经提到过,abstarct class在Java语言中体现了一种继承关系,要想使得继承关系合理,父类和派生类之间必须存在"is a"关系,即父类和派生类在概念本质上应该是相同的。对于interface 来说则不然,并不要求interface的实现者和interface定义在概念本质上是一致的,仅仅是实现了interface定义的契约而已。为了使论述便于理解,下面将通过一个简单的实例进行说明。
考虑这样一个例子,假设在我们的问题领域中有一个关于Door的抽象概念,该Door具有执行两个动作open和close,此时我们可以通过abstract class或者interface来定义一个表示该抽象概念的类型,定义方式分别如下所示:
使用abstract class方式定义Door:
abstract class Door {
abstract void open();
abstract void close();
}
使用interface方式定义Door:
interface Door {
void open();
void close();
}
其他具体的Door类型可以extends使用abstract class方式定义的Door或者implements使用interface方式定义的Door。看起来好像使用abstract class和interface没有大的区别。
如果现在要求Door还要具有报警的功能。我们该如何设计针对该例子的类结构呢(在本例中,主要是为了展示abstract class和interface反映在设计理念上的区别,其他方面无关的问题都做了简化或者忽略)下面将罗列出可能的解决方案,并从设计理念层面对这些不同的方案进行分析。
解决方案一:
简单的在Door的定义中增加一个alarm方法,如下:
abstract class Door {
abstract void open();
abstract void close();
abstract void alarm();
}
或者
interface Door {
void open();
void close();
void alarm();
}
那么具有报警功能的AlarmDoor的定义方式如下:
class AlarmDoor extends Door {
void open() { … }
void close() { … }
void alarm() { … }
}
或者
class AlarmDoor implements Door {
void open() { … }
void close() { … }
void alarm() { … }
}
这种方法违反了面向对象设计中的一个核心原则ISP(Interface Segregation Priciple),在Door的定义中把Door概念本身固有的行为方法和另外一个概念"报警器"的行为方法混在了一起。这样引起的一个问题是那些仅仅依赖于Door这个概念的模块会因为"报警器"这个概念的改变(比如:修改alarm方法的参数)而改变,反之依然。
解决方案二:
既然open、close和alarm属于两个不同的概念,根据ISP原则应该把它们分别定义在代表这两个概念的抽象类中。定义方式有:这两个概念都使用abstract class方式定义;两个概念都使用interface方式定义;一个概念使用abstract class方式定义,另一个概念使用interface方式定义。
显然,由于Java语言不支持多重继承,所以两个概念都使用abstract class方式定义是不可行的。后面两种方式都是可行的,但是对于它们的选择却反映出对于问题领域中的概念本质的理解、对于设计意图的反映是否正确、合理。我们一一来分析、说明。
如果两个概念都使用interface方式来定义,那么就反映出两个问题:
1、我们可能没有理解清楚问题领域,AlarmDoor在概念本质上到底是Door还是报警器?
2、如果我们对于问题领域的理解没有问题,比如:我们通过对于问题领域的分析发现AlarmDoor在概念本质上和Door是一致的,那么我们在实现时就没有能够正确的揭示我们的设计意图,因为在这两个概念的定义上(均使用interface方式定义)反映不出上述含义。
如果我们对于问题领域的理解是:AlarmDoor在概念本质上是Door,同时它有具有报警的功能。我们该如何来设计、实现来明确的反映出我们的意思呢?前面已经说过,abstract class在Java语言中表示一种继承关系,而继承关系在本质上是"is a"关系。所以对于Door这个概念,我们应该使用abstarct class方式来定义。另外,AlarmDoor又具有报警功能,说明它又能够完成报警概念中定义的行为,所以报警概念可以通过interface方式定义。如下所示:
abstract class Door {
abstract void open();
abstract void close();
}
interface Alarm {
void alarm();
}
class AlarmDoor extends Door implements Alarm {
void open() { … }
void close() { … }
void alarm() { … }
}
这种实现方式基本上能够明确的反映出我们对于问题领域的理解,正确的揭示我们的设计意图。其实abstract class表示的是"is a"关系,interface表示的是"like a"关系,大家在选择时可以作为一个依据,当然这是建立在对问题领域的理解上的,比如:如果我们认为AlarmDoor在概念本质上是报警器,同时又具有Door的功能,那么上述的定义方式就要反过来了。
abstract class和interface是Java语言中的两种定义抽象类的方式,它们之间有很大的相似性。但是对于它们的选择却又往往反映出对于问题领域中的概念本质的理解、对于设计意图的反映是否正确、合理,因为它们表现了概念间的不同的关系(虽然都能够实现需求的功能)。这其实也是语言的一种的惯用法,希望读者朋友能够细细体会
posted @
2006-03-19 15:41 xnabx 阅读(200) |
评论 (0) |
编辑 收藏
WebServices 是部署在WEB上的组件和对象!
它具有以下几点特征:
1. 高度的耦合性.就是移植性还不错,相互依赖不强 .
2. 高度的集成性.
3. 完好的封状性. 就是我们只可以看到他想让你看到的东西 呵呵!
4. 使用标准协议规范.
posted @
2006-03-19 12:05 xnabx 阅读(206) |
评论 (0) |
编辑 收藏
对synchronized(this)的一些理解
|
|
|
|
一、当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。
二、然而,当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。
三、尤其关键的是,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞。
四、第三个例子同样适用其它同步代码块。也就是说,当一个线程访问object的一个synchronized(this)同步代码块时,它就获得了这个object的对象锁。结果,其它线程对该object对象所有同步代码部分的访问都被暂时阻塞。
五、以上规则对其它对象锁同样适用.
|
|
posted @
2006-03-18 00:32 xnabx 阅读(189) |
评论 (0) |
编辑 收藏
全面认识JAVA
|
作者:unknown 更新时间:2005-04-07 |
|
|
作SCJP培训已经有一段时间了,到我这学习的有在校的大学生,也有在职的开发人员。通常这些学员此前都对Java已有一些了解,但普遍对Java缺乏总体的认识。于是学员总是问,Java应该怎么学?Java能做什么?什么是Applet?什么是Servlet、Jsp、EJB?还有Webspere、Weblogic又是做什么的等等。之所以学员会有这些疑问,是因为大家普遍对Java相关概念听说的太多而了解的又相对少的缘故。
学通Java语言需要一个过程,所有Java相关的概念都会在学习的过程中逐渐变得清昕。这个过程的开始就是要先学会标准的Java技术(J2SE),然后是学Java的简单Web运用,然后分布式运用,再以后对Java的移动技术运用就很容易理解了。
以下是Java标准技术的一些要点:
一、Java的跨平台性,即一次编译到处运行
简单地说Java的跨平台性就是指,编译后的Java程序可直接在不同的平台上运行而不用重新编译,这一特性使得Java随着Web应用的普及而迅速普及起来。而Java的跨平台性是如何实现的呢?这就要理解Java虚拟机和字节码的概念。
实际上,编译后的Java代码并不是传统的二进制代码(如Windows下的.exe文件),而是Java字节码,这种字节码文件是不能直接在操作系统上执行的。要想在一个操作系统上运行一个Java程序必须有一个中间环节来负责将Java字节码解释成二进制码,这个中间环节就是Java虚拟机(简称JVM)。由于目前大多数操作系统已经实现了JVM,所以Java轻松实现跨平台性。
二、面象对象技术
Java全面支持面象对象技术,这体现在Class(类)是Java程序构成的基本单元,一个Java程序通常由许多Class组成,而且这些Class还会有一定的继承关系,Java支持Class的单继承,从而使类之间的继承关系更明确。继承的结果产生类的多态性,类的多态本质上讲就是可以用父类的引用访问继承类的实现(子类对象),类的这种多态性最终形成了组件对象模型的基础,即通过接口(父类)访问实现(子类)。
三、Java中的I/O操作
Java中以字节流(InputStream和OutputStream)、节符流(Reader和Writer)来分别读写二进制数据和字符数据,使用非常简单有效。Java类库中的File类不仅提供文件操作而且还包含文件夹操作,如下面这几行代码可以列出C盘根目录下的所有文件:
File f=new File("c://"); String [] m_dir= f.list(); for(int i=0;i<m_dir.length;i++) System.out.println(m_dir[i]);
四、Java中的图形及事件处理
可以用awt包或swing包的Java类来进行大部分的Java图形界面设计,下面的几行代码将产生一个200*200像素的窗体:
Frame f=new Frame("Welcome"); f.setSize(200,200); f.setVisible(true);
默认情况下,Frame窗体的关闭按钮不起作用,这也是Java初学者迷惑的地方。为了使用户按下关闭按钮时能关闭Frame窗体,需要让这个窗体响应一个WindowEvent事件,具体的做法就是给这个窗体添加一个事件监听器对象,这个事件监听器就是WindowListener接口的实现。在上面的代码中插入如下代码就可以关闭窗体:
f.addWindowListener(new WindowAdapter(){ ??public void windowClosing(WindowEvent e){ System.exit(0); ??} }
这里用到一个无名内部类,无名内部类是Java中内部类的一种灵活运用方式。
五、Java中线程及同步控制
线程概念的引入是为了实现并行处理,从而提高程序的效率。Java中的线程实现非常简单,可以用两种方式来创建线程,一种是实现Runnable接口,另一种是继承Thread类重写run()方法。两种方式唯一的不同就是前者保留了继承一个类的可能(因为Java只支持类的单继承,但接口没有此限制)。
永远都用start()方法来启动一个线程,线程类中的run()可以被直接调用,但决不是启动一个线程,二者有着本质的区别。
用同步控制关键字synchronized来保护线程敏感数据,synchronized块中的内容可以保证同一时刻只能被一个线程访问,所以其中的数据是线程安全的。
用Object类中的wait()和notify()方法可以实现线程间交互,但要记住wait()和notify()方法只有发生在同一个对象上才能真正实现线程间交互。被某一对象wait()方法阻塞的线程需要另外一个调用了同一对象notify()的线程干预才能恢复运行。notify()方法一次唤醒一个被wait()方法阻塞的线程,notifyAll()方法可以一次唤醒所有被wait()方法阻塞的线程。
六、Java本地方法(native方法)的实现
Java不是完美的,Java的不足除了体现在运行速度上要比传统的C++慢许多之外,Java无法直接访问到操作系统底层(如系统硬件等),为此Java使用native方法来扩展Java程序的功能。
可以将native方法比作Java程序同C程序的接口,其实现步骤:
1、在Java中声明native()方法,然后编译; 2、用javah产生一个.h文件; 3、写一个.cpp文件实现native导出方法,其中需要包含第二步产生的.h文件(注意其中又包含了JDK带的jni.h文件); 4、将第三步的.cpp文件编译成动态链接库文件; 5、在Java中用System.loadLibrary()方法加载第四步产生的动态链接库文件,这个native()方法就可以在Java中被访问了。
上述所提及的一些Java技术具有一定的普遍性,它们基本上是在Java各个方面的运用中都需要掌握的术。实际上Java的运用非常广泛,而且每个方面都需要遵循不同的规范。以下是对Java应用的简要介绍。
(一)理解Java SDK的三个版本:
Java SDK Micro Edition (J2ME)
用于开发掌上电脑、手机等移动通信设备上使用的应用程序。并不是所有的移动设备都支持Java,只有具备J2ME运行环境(JVM+J2ME API)的设备才能运行Java程序。J2ME的集成开发工具(通常都有带有一些访真器)有 Sun 的J2ME Wireless Toolkit 、IBM的Visul Age Micro Edition 等。
Java SDK Standard Edition(J2SE)
主要用于开发一般台式机应用程序。我们平时所说的JDK就指J2SE,而我们学Java就是从学习J2SE开始的。
Java SDK Enterprise Edition (J2EE)
用于开发分布式的企业级大型应用程序。其中的核心是Entetprise Java Beans(EJB,分布式Java组件)的开发。
(二)Java小程序 (Applet)
Java小程序是一个继承了Applet类并重写了init()、paint()、stop()等方法的的Java类,它被布署在Web服务器(如IIS)上,当客户端请求Web页时,浏览器从Web服务器上将其下载到本地客户端,然后,浏览器创建该Applet类的实例并调用其init()方法,从安全角度考虑,Applet没有访问本地文件的权限。由于Applet是被浏览器执行的,所以Applet不需要一个main()方法。实际上,除了Java Application之外,所有其它Java应用都不需要一个main()方法。
(三)服务器端Java小程序 (Servlet)
Servlet也是一个Java类,和Applet形成对比,Servlet是运行于服务器端的Java小程序,而且Servlet需要一个单独的Web服务器(如Tomcat)做容器。除此之外,Servlet中用到的一些类(如HttpServlet)并不包含在J2SE API中,所以需要将Servlet.jar(在Tomcat的common\lib文件夹下)加到环境变量中去。下面是一个简单的Servlet例子:
public class Myservlet extends HttpServlet{
??public void doGet(HttpServletRequest request,HttpServletResponse response) { ??try{ response.setContentType("text/html"); PrintWriter out=response.getWriter(); out.println("<html>"); out.println("<body>"); out.println("Hello world"); out.println("</body>"); out.println("</html>"); ??}catch(IOException e){} } }
将这个Class文件编译后放至Tomcat\webapps\examples\WEB-INF\classes下,然后在浏览器地址栏里输入http://127.0.0.1:8080/examples/servlet/Myservlet即可看到 Hello world出现在浏览器中。
(四)Java Server Page (JSP)
同Servlet相似的是,JSP运行于Web服务器端,并且也需要Tomcat之类的容器。不同的是,由于JSP是将Java代码嵌在html标记里(同ASP一样用<% ...%>),JSP的界面设计同后台开发人员的工作可以有效分离。可以想像让开发人员用Servlet写一个花捎的Web页面有多困难,所以JSP+Servlet混合Web应用是比较理想的选择。
看起来JSP同ASP的实现机制大同小异,其实也存在着本质的区别。所有的ASP页面都是解释运行的,而JSP页在第一次被请求时会被编译,再以后的客户请求都是直接运行服务器上的.class文件(在Tomcat的Work文件夹下),所以JSP要比ASP速度上快许多。
(五)Java Beans
Java Bean 是可复用的组件,对Java Bean并没有严格的规范,理论上讲,任何一个Java类都可以是一个Bean。但通常情况下,由于Java Bean是被容器所创建(如Tomcat)的,所以Java Bean应具有一个无参的构造器,另外,通常Java Bean还要实现Serializable接口用于实现Bean的持久性。
(六)Enterprise Java Beans (EJB)
Java Bean实际上相当于微软COM模型中的本地进程内COM组件,它是不能被跨进程访问的。Enterprise Java Bean 相当于DCOM,即分布式组件。它是基于Java的远程方法调用(RMI)技术的,所以EJB可以被远程访问(跨进程、跨计算机)。但EJB必须被布署在诸如Webspere、WebLogic这样的容器中,EJB客户从不直接访问真正的EJB组件,而是通过其容器访问。EJB容器是EJB组件的代理,EJB组件由容器所创建和管理。客户通过容器来访问真正的EJB组件。
这种模型很像COM+管理器,其实EJB容器正是起到COM+管理器的作用,只是EJB组件相对COM组件来说更易用、更安全。
总的说来,Java作为面象对象技术的一个代表,在当今商业应用中更容易开发出高效的、多层的分布式应用程序,而且,由于Java技术有很强的健壮性和易用性,加上同UML应用的结合,开发一个商业应用软件的周期会大大缩短,所以Java会有不错的前景。 |
|
posted @
2006-03-18 00:29 xnabx 阅读(128) |
评论 (0) |
编辑 收藏
Java学习过程的一些重点
|
|
|
|
Java学习过程的一些重点
主要说说Java的几大块吧,无法说得很细,因为其实每一块拿出来都能说很多,我就说一下这几块学习的时候的重点或者应该注意的东西。
数值类型:
虽然是面向对象的语言,但是在使用上数值类型还是必不可少的,如果在C的学习中已经掌握了C的数值计算和转换规则,那我想这里应该没有什么问题,只有两点需要注意:1、14.0这样的浮点常量被认为是double型,只有加上f后缀才是float型的;2、整数常量说起来被认为是int型,但是在编译时,可以认为编译器将其看作能表示该数的最小数值,因此byte b = 100;不会报错。
引用类型:
我也是从C/C++转过来的,其实所谓引用类型在C++中已有体现,就是传参的时候有一种引用类型,从C来考虑,它就是一个指针,只不过,我们不能对它进行指针上的硬操作。所以这里的重点是:1、Java里所有的对象都是在堆中生成的,所以需要类似指针的东西指向它,那就是引用;2、我们通过引用操作的是引用所指向的对象,除了赋值操作外,应该就没有什么操作是针对引用本身的了,这一点是C的指针与Java的引用区别所在。
类和对象:
这是一个大块,有很多东西,不展开讲了,就说几个重点:1、类方法、类属性与成员方法、成员属性在加载、初始化、使用上的异同;2、在构造函数中,this()和super()的用法;3、子类的加载过程、初始化过程和构造过程;4、方法的重载和覆写;5、覆写所引出的多态问题。(注意:多态之应用在方法上,对属性没有作用)
函数调用的参数传递:
如果把引用类型所记录的地址值,就看作是引用类型变量的值的话,那么,Java的所有方法调用的时候,都是采用的值传递??数值类型传数值,引用类型传地址。
IO流:
与C比起来,Java的输入输出,尤其是输入是非常麻烦的,也许是因为出于面向对象的考虑吧?不知道。Java提供了很多的IO流,但是我们并不必将各种IO都搞清楚,我们只需要了解字节流与字符流各有什么功能,字符流是如何在字节流之上构造的,几乎所有的字符流构造的时候都是建立在一个已有的字节流的基础上的,并且它的这种设计使得我们可以像套管子一样,将IO流一节一节套起来,直到得到我们想使用的IO对象(例:BufferedReader的使用)。在我们以后使用的时候,我们可以再去查API,我觉得主要要看的几个类是:FileReader、FileWriter、BufferedReader,再配合上System.out对象,对于文本的输入、输出来说,就足够用了,至于其他的,我觉得不考试的话,没有必要看那么多,用的时候再看了。(我使用Java一年半来,基本上就在使用BufferedReader和System.out)
容器:
个人认为,这是Java编程的一大利器,我最爱用的类是:ArrayList(List)作为可变长数组、HashMap(Map)用来建立查找表,Set我很少用,只在HashMap的使用中连带用过一些。通过对这两个类的熟悉,能够将List、Set和Map三大类的基本用法掌握。另外它的几个辅助类要掌握:Iterator和Collections。Collections类提供容器的一些通用工具,比如排序。而说到排序,就牵扯出了比较器:Comparator。能够熟练使用Comparator类,可以让你为自己的需求和自己的类定制排序方案。
AWT和SWING:
个人认为,Java在图形界面的制作上有着非常好的封装性,我以前曾经试图学过MFC,MFC在生成图形界面的时候会帮助你生成一些代码,然后让你在这些代码的指定位置添加代码以实现功能,我这个人有个习惯,如果让我看到了一些东西,那么我不搞清除为什么这么写,就不会往下走,看到那许多代码,自然就想弄清楚那些是什么,结果引出来好多知识,后来我才知道其中有些是调用WinAPI,结果我到现在还是不会用MFC。这里并不是贬低MFC,我相信MFC有其过人之处,只不过个人认为它的封装性做得不好,暴露出了太多东西,也许能够提高灵活性,不过,可能我跟它无缘:(。在这方面Java就做得不错,给你一个类,你用就是了,它将图形界面的低层实现隐藏的很好,将其作为一个对象给你,而你只需要在这个对象上修修改改,挺方便的。
作为初学者,我觉得AWT的重点在于它的几个Listener的用法,还有布局格式,然后就是那许多的Component的用处和用法。(不过,我觉得,等到用的时候再去找合适的Component进行学习应该也不算太迟 ^_^)
不过,因为我个人使用的原因,所以至今AWT和SWING都用得很少,所以这方面也就不便多说了,抱歉。写这些并不是告诉大家怎么解决问题,因为每一个都有很多可写,只是希望能给初学者一点参考,希望能够帮助初学者们有的放矢地看书。 |
|
posted @
2006-03-18 00:26 xnabx 阅读(161) |
评论 (0) |
编辑 收藏
JBuilder 9 常见快捷键
|
|
|
|
1.工作区: (显隐)
项目面板:ctrl + Alt + p (Project) 设计面板: ctrl + Alt + c (content) 结构面板: ctrl + Alt + s (Structure) 信息面板: ctrl + Alt + M (Message) 状态面板: ctrl + Alt + Z
2.主面板:(代码面板和设计面板)
激活代码模块: ctrl + J (@1) 参数提示信息的激活: ctrl + shift + H 打开查询、替换窗口: ctrl + F 类的查询: ctrl + -
3.F 键的用法
F1: 帮助快捷 F4: 运行多行 F5: 加入断点 F7: 当遇到方法时会运行方法内的代码 F8: 逐步运行代码 F12: 代码面板和设计面板切换
4. Shift 键的用法
添加多个相同组件: 按shift键在选项上选取组件,把组件添加到窗口即可 调整组件间间隔和对齐: 假设有组件JPanel 1/2/3;(要达到3个组件宽度相同,组件间隔相等,并且都是依据JPanel1左对齐),按shift键,用鼠标选中需要调整的组件,(第一个选中的组件是其他的基准)然后右键。
5: codeInsight 和 Codetemplates MemberInsight -- 根据当前的代码提示可用的类成员或方法(说明) ParameterInsight -- 提示当前的方法需要使用的参数 SymbolInsigh -- 查看当前的变量、方法或者类的愿代码。
MemberInsight: ctrl + space 或 ctrl + H ParameterInsight: ctrl + shift + space 或 ctrl + shift + H SymbolInsight: ctrl + Enter 或 Alt + shift + H ClassInsight : ctrl + alt + space 或 ctrl + alt + H
注: (@1):使用代码功能:(ctrl + J) 1、 在想要输入代码的位置输入代码摸板名,然后按 ctrl + J(开发人员可以用主菜单上的Tools/Editor/Templates命令来查看代码摸板的名字) 2、把光标定位于想要输入代码的位置,然后按ctrl + J
|
|
posted @
2006-03-18 00:23 xnabx 阅读(171) |
评论 (0) |
编辑 收藏
1.得到当前程序文件的绝对路径:this.getClass().getResource(this.getClass().getName()+".java").getPath()
posted @
2006-03-17 23:59 xnabx 阅读(195) |
评论 (0) |
编辑 收藏
关于软件优化,硬件升级方面的:
至强64位双CPU
2G内存 DDR2 533
tomcat5.5默认配置
java5.0默认配置
mysql5.0默认配置
带宽为10M独享.
如何改变软件方面的配置要求。优化方面的资料。硬件方面要升级哪些? 以达到支持大约在线用户为最高2000人。
处理:
2000 人在线,每秒钟请求数应该在几百次或者更低些的程度,并发数不会超过100(平均10妙请求一次),使用普通的 PC 机,每秒钟也能够处理上百次的请求;
缓存优化:解决性能问题首先想到的就是缓存,在 Web 应用中有很多缓存的方式,可以缓存到 Web 层的 servletContext 中,也可以缓存到业务层中,甚至可以在数据库中建立冗余。而生成静态页面是一种极端的做法,一般来说会增加复杂性,同时可能会对灵活性和可维护性造成很大伤害。缓存的要点在于命中率,命中率低的东西不应该缓存,除非对内存的价格不做考虑。总结起来设计上就两句话,使用 N 层结构,合理缓存。根据程序的需要,适当是使用缓存机制;
程序进行优化方法,比如:每次查找部分记录,而不是全部查出来,这样既可以减轻服务器的负担,也可以减少网络传输量; 对于系统中的数据库连接一定要进行妥善的处理; 对需要用 scrchrnozied 的地方要用,但是有些地方可以不用同步化的,这个对速度影响也很大;从代码入手,优化程序,在数据持久化上进行改进,采用成熟的库访问对象(Data Access Object)设计模式也会节省你的服务器开销。
硬件升级:硬件方面还不行,硬盘最好搞阵列,还可以再来一个服务器,弄个负载均衡,由两个服务器来处理用户的请求,apache必然是要用到的,他将挡在tomcat前处理http请求。
注意:在硬件足够强大的时候,将 web 与 db 分两台服务器来做,只会降低效率,因为网络编组的成本要比本地内存中的复制高几个数量级。同样道理,负载均衡也只会导致更复杂的结构,会引起更多的问题,并产生更低于下的效率。将一个应用分布于多台机器的唯一理由,就是由于一台机器根本顶不住,不得不分。
环境优化:调Tomcat、JVM的Heap大小等参数做一些优化, Tomcat的虚拟内存管理有最大值限制,可以并发运行多个Tomcat来均衡负载,tomcat5.5默认配置 ==>改了JAVA_OPTS没有?开大内存 既java_opts= -Xms1024m -Xmx1024m ; java5.0默认配置 ==>升级一下到最大的小版本6.0 升级处理
系统内存测试:
(1)自己测试:参考tomcat,jvm,mysql优化方面的资料。测试如下操作出错:
C:\>java -Xms536870932 -Xmx536870912
Error occurred during initialization of VM
Incompatible initial and maximum heap sizes specified至强64位双CPU,原则上面来说64位的CPU应当可以用到无限大的内存了,也还是理论上的了。可以java -Xmx2000M -version这样一路加上去试试看你的可以加到多大。
(2)工具测试: 压力测试:对应用系统进行性能采样于监控,(Wily有一套产品可以在运行期进行调优,但我没有用过),我用的P6Spy,加MS的那个压力测试工具,也有D用LoadRunner来跑一跑,在SQL语句这个地方有太多的名堂可做了。
建议软件方面:
a、软件配置 Apache2.2.0 + mod_ajp + jrockit-R26.0.0-jdk1.5.0_04+ Tomcat5.5.15 (启多个)+apr1.2.2 .
b、内存建议4g以上 。 tomcat的内存参数使用 set JAVA_OPTS=%JAVA_OPTS%-Xms1024m -Xmx1024m (内存2g的话,建议set JAVA_OPTS=%JAVA_OPTS%-Xms512m -Xmx512m).
c、tomcat5.5版本的性能已经大幅度提高了。
posted @
2006-03-17 23:29 xnabx 阅读(429) |
评论 (0) |
编辑 收藏
今天遇到个以前使用Struts没有注意的地方。
现象:
在actionForward配置文件里面定义
<forward name="success" path="/Catalog.jsp" redirect="true"/>
当在提交页面里面request.setAttbriute("msg","处理成功");
提交后在Catalog.jsp 用request.getAttbriute("msg");居然为空,原因是设置了redirect="true"
下例举例说明了redirect属性的用法:
<forward name="success" path="/Catalog.jsp" redirect="true"/>
如果
redirect=true, URL
建立如
/
contextPath
/
path
因为
HttpServletResponse.sendRedirect(…)
中解释
URL
采用
”/”
开头相对于
servlet
容器根目录。
如果
redirect=false, URI
建立如
/
path
因为
ServletContext.getRequestDisptacher(…)
采用虚拟目录相关
URL
。
posted @
2006-03-14 18:04 xnabx 阅读(1346) |
评论 (0) |
编辑 收藏
繁重
posted @
2006-03-14 15:37 xnabx 阅读(165) |
评论 (0) |
编辑 收藏