??xml version="1.0" encoding="utf-8" standalone="yes"?> q是一程序员写给E序员的味ȝ。所谓趣x指可以比较轻村֜了解一些原来不清楚的概念,增进知识Q类g打RPG游戏的升U。整理这文章的动机是两个问题: 使用WindowsC本的“另存ؓ”,可以在GBK、Unicode、Unicode big endian和UTF-8q几U编码方式间怺转换。同htxt文gQWindows是怎样识别~码方式的呢Q?/P>
我很早前发现Unicode、Unicode big endian和UTF-8~码的txt文g的开头会多出几个字节Q分别是FF、FEQUnicodeQ?FE、FFQUnicode big endianQ?EF、BB、BFQUTF-8Q。但q些标记是基于什么标准呢Q?/P> 查了查相兌料,ȝ这些问题弄清楚了,带也了解了一些Unicode的细节。写成一文章,送给有过cM疑问的朋友。本文在写作时尽量做到通俗易懂Q但要求读者知道什么是字节Q什么是十六q制?/P>
big endian和little endian是CPU处理多字节数的不同方式。例如“汉”字的Unicode~码?C49。那么写到文仉ӞI竟是将6C写在前面Q还是将49写在前面Q如果将6C写在前面Q就是big endian。如果将49写在前面Q就是little endian?/P>
“endian”这个词《格列佛游记》。小人国的内战就源于吃鸡蛋时是究竟从大头(Big-Endian)敲开q是从小?Little-Endian)敲开Q由此曾发生q六ơ叛乱,一个皇帝送了命,另一个丢了王位?/P>
我们一般将endian译成“字节序”,big endian和little endianUC“大䏀和“小䏀?/P>
字符必须~码后才能被计算机处理。计机使用的缺省编码方式就是计机的内码。早期的计算Z?位的ASCII~码Qؓ了处理汉字,E序员设计了用于体中文的GB2312和用于繁体中文的big5?/P>
GB2312(1980q?一共收录了7445个字W,包括6763个汉字和682个其它符受汉字区的内码范围高字节从B0-F7Q低字节从A1-FEQ占用的码位?2*94=6768。其中有5个空位是D7FA-D7FE?/P>
GB2312支持的汉字太?995q的汉字扩展规范GBK1.0收录?1886个符P它分为汉字区和图形符号区。汉字区包括21003个字W?/P>
从ASCII、GB2312到GBKQ这些编码方法是向下兼容的,卛_一个字W在q些Ҏ中L有相同的~码Q后面的标准支持更多的字W。在q些~码中,英文和中文可以统一地处理。区分中文编码的Ҏ是高字节的最高位不ؓ0。按照程序员的称|GB2312、GBK都属于双字节字符?(DBCS)?/P>
2000q的GB18030是取代GBK1.0的正式国家标准。该标准收录?7484个汉字,同时q收录了藏文、蒙文、维向ְ文等主要的少数民族文字。从汉字字汇上说QGB18030在GB13000.1?0902个汉字的基础上增加了CJK扩展A?582个汉字(Unicode?0x3400-0x4db5Q,一共收录了27484个汉字?/P>
CJK是中日韩的意思。UnicodeZ节省码位Q将中日韩三国语a中的文字l一~码。GB13000.1是ISO/IEC 10646-1的中文版Q相当于Unicode 1.1?/P>
GB18030的编码采用单字节、双字节?字节Ҏ。其中单字节、双字节和GBK是完全兼容的?字节~码的码位就是收录了CJK扩展A?582个汉字?例如QUCS?x3400在GB18030中的~码应该?139EF30QUCS?x3401在GB18030中的~码应该?139EF31?/P>
微Y提供了GB18030的升U包Q但q个升包只是提供了一套支持CJK扩展A?582个汉字的新字体:新宋?18030Qƈ不改变内码。Windows 的内码仍然是GBK?/P>
q里q有一些细节: GB2312的原文还是区位码Q从Z码到内码Q需要在高字节和低字节上分别加上A0?/P> 对于M字符~码Q编码单元的序是由~码Ҏ指定的,与endian无关。例如GBK的编码单元是字节Q用两个字节表示一个汉字?q两个字节的序是固定的Q不受CPU字节序的影响。UTF-16的编码单元是wordQ双字节Q,word之间的顺序是~码Ҏ指定的,word内部的字节排列才会受到endian的媄响。后面还会介lUTF-16?/P> GB2312 的两个字节的最高位都是1。但W合q个条g的码位只?28*128=16384个。所以GBK和GB18030的低字节最高位都可能不?。不q这不媄响DBCS字符的解析Q在dDBCS字符时Q只要遇到高位ؓ1的字节,可以将下两个字节作Z个双字节~码Q而不用管低字节的高位是什么?/P> 前面提到从ASCII、GB2312、GBK到GB18030的编码方法是向下兼容的。而Unicode只与ASCII兼容Q更准确地说Q是与ISO-8859-1兼容Q,与GB码不兼容。例如“汉”字的Unicode~码?C49Q而GB码是BABA?/P>
Unicode也是一U字W编码方法,不过它是由国际组l设计,可以容纳全世界所有语a文字的编码方案。Unicode的学名是"Universal Multiple-Octet Coded Character Set"Q简UCؓUCS。UCS可以看作?Unicode Character Set"的羃写?/P>
Ҏl基癄全书(http://zh.wikipedia.org/wiki/)的记载:历史上存在两个试囄立设计Unicode的组l,卛_际标准化l织QISOQ和一个Y件制造商的协会(unicode.orgQ。ISO开发了ISO 10646目QUnicode协会开发了Unicode目?/P>
?991q前后,双方都认识到世界不需要两个不兼容的字W集。于是它们开始合q双方的工作成果Qƈ为创立一个单一~码表而协同工作。从Unicode2.0开始,Unicode目采用了与ISO 10646-1相同的字库和字码?/P>
目前两个目仍都存在Qƈ独立地公布各自的标准。Unicode协会现在的最新版本是2005q的Unicode 4.1.0。ISO的最新标准是ISO 10646-3:2003?/P>
UCS只是规定如何~码Qƈ没有规定如何传输、保存这个编码。例如“汉”字的UCS~码?C49Q我可以?个ascii数字来传输、保存这个编码;也可以用utf-8~码:3个连l的字节E6 B1 89来表C它。关键在于通信双方都要认可。UTF-8、UTF-7、UTF-16都是被广泛接受的Ҏ。UTF-8的一个特别的好处是它与ISO-8859-1完全兼容。UTF是“UCS Transformation Format”的~写?/P>
IETF的RFC2781和RFC3629以RFC的一贯风|清晰、明快又不失严}地描qCUTF-16和UTF-8的编码方法。我LC得IETF是Internet Engineering Task Force的羃写。但IETF负责l护的RFC是Internet上一切规范的基础?/P>
目前Windows的内核已l支持Unicode字符集,q样在内怸可以支持全世界所有的语言文字。但是由于现有的大量E序和文档都采用了某U特定语a的编码,例如GBKQWindows不可能不支持现有的编码,而全部改用Unicode?/P>
Windows使用代码?code page)来适应各个国家和地区。code page可以被理解ؓ前面提到的内码。GBK对应的code page是CP936?/P>
微Y也ؓGB18030定义了code pageQCP54936。但是由于GB18030有一部分4字节~码Q而Windows的代码页只支持单字节和双字节~码Q所以这个code page是无法真正用的?/P>
UCS有两U格式:UCS-2和UCS-4。顾名思义QUCS-2是用两个字节编码,UCS-4是?个字节(实际上只用了31位,最高位必须?Q编码。下面让我们做一些简单的数学游戏Q?/P>
UCS-2?^16=65536个码位,UCS-4?^31=2147483648个码位?/P>
UCS-4Ҏ最高位?的最高字节分?^7=128个group。每个group再根据次高字节分?56个plane。每个planeҎW?个字节分?56?(rows)Q每行包?56个cells。当然同一行的cells只是最后一个字节不同,其余都相同?/P>
group 0的plane 0被称作Basic Multilingual Plane, 即BMP。或者说UCS-4中,高两个字节ؓ0的码位被UCBMP?/P>
UCS-4的BMPL前面的两个零字节得CUCS-2。在UCS-2的两个字节前加上两个零字节,得CUCS-4的BMP。而目前的UCS-4规范中还没有M字符被分配在BMP之外?/P>
UTF-8是?位ؓ单元对UCSq行~码。从UCS-2到UTF-8的编码方式如下: 例如“汉”字的Unicode~码?C49?C49?800-FFFF之间Q所以肯定要?字节模板了:1110xxxx 10xxxxxx 10xxxxxx。将6C49写成二进制是Q?110 110001 001001Q?用这个比Ҏ依次代替模板中的xQ得刎ͼ11100110 10110001 10001001Q即E6 B1 89?/P>
读者可以用C本测试一下我们的~码是否正确。需要注意,UltraEdit在打开utf-8~码的文本文件时会自动{换ؓUTF-16Q可能生淆。你可以在设|中xq个选项。更好的工具是Hex Workshop?/P>
UTF-16?6位ؓ单元对UCSq行~码。对于小?x10000的UCS码,UTF-16~码q于UCS码对应的16位无W号整数。对于不于0x10000的UCS码,定义了一个算法。不q由于实际用的UCS2Q或者UCS4的BMP必然于0x10000Q所以就目前而言Q可以认?UTF-16和UCS-2基本相同。但UCS-2只是一个编码方案,UTF-16却要用于实际的传输,所以就不得不考虑字节序的问题?/P>
UTF-8以字节ؓ~码单元Q没有字节序的问题。UTF-16以两个字节ؓ~码单元Q在解释一个UTF-16文本前,首先要弄清楚每个~码单元的字节序。例如“奎”的Unicode~码?94EQ“乙”的Unicode~码?E59。如果我们收到UTF-16字节?94E”,那么q是“奎?q是“乙”? Unicode规范中推荐的标记字节序的方法是BOM。BOM不是“Bill Of Material”的BOM表,而是Byte Order Mark。BOM是一个有点小聪明的想法: 在UCS~码中有一个叫?ZERO WIDTH NO-BREAK SPACE"的字W,它的~码是FEFF。而FFFE在UCS中是不存在的字符Q所以不应该出现在实际传输中。UCS规范我们在传输字节流前,先传输字W?ZERO WIDTH NO-BREAK SPACE"?/P>
q样如果接收者收到FEFFQ就表明q个字节是Big-Endian的;如果收到FFFEQ就表明q个字节是Little-Endian的。因此字W?ZERO WIDTH NO-BREAK SPACE"又被UCBOM?/P>
UTF-8不需要BOM来表明字节顺序,但可以用BOM来表明编码方式。字W?ZERO WIDTH NO-BREAK SPACE"的UTF-8~码是EF BB BFQ读者可以用我们前面介绍的编码方法验证一下)。所以如果接收者收CEF BB BF开头的字节,q道这是UTF-8~码了?/P>
Windows是使用BOM来标记文本文件的~码方式的?/P>
本文主要参考的资料?"Short overview of ISO-IEC 10646 and Unicode" (http://www.nada.kth.se/i18n/ucs/unicode-iso10646-oview.html)?/P>
我还找了两篇看上M错的资料Q不q因为我开始的疑问都找C{案Q所以就没有看: 我写qUTF-8、UCS-2、GBK怺转换的Y件包Q包括用Windows API和不使用Windows API的版本。以后有旉的话Q我会整理一下放到我的个Z上(http://fmddlmyy.home4u.china.com)?/P>
我是x楚所有问题后才开始写q篇文章的,原以Z会儿p写好。没惛_考虑措辞和查证细节花费了很长旉Q竟然从下午1:30写到9:00。希望有读者能从中受益?/P>
有的朋友Ҏ章中q句话还有疑问: 我再详细解释一下: “GB2312的原文”是指国?980q的一个标准《中华h民共和国国家标准 信息交换用汉字编码字W集 基本?GB 2312-80》。这个标准用两个数来~码汉字和中文符受第一个数UCؓ“区”,W二个数UCؓ“位”。所以也UCؓZ码?-9区是中文W号Q?6-55 区是一U汉字,56-87区是二汉字。现在Windows也还有区位输入法Q例如输?601得到“啊”。(q个Z输入法可以自动识?6q制?GB2312?0q制的区位码Q也是说输入B0A1同样会得到“啊”。) 内码是指操作pȝ内部的字W编码。早期操作系l的内码是与语言相关的。现在的Windows在系l内部支持UnicodeQ然后用代码适应各种语言Q“内码”的概念比较模p了。微软一般将~省代码|定的~码说成是内码?/P>
内码q个词汇Qƈ没有什么官方的定义Q代码页也只是微软这个公司的叫法。作为程序员Q我们只要知道它们是什么东西,没有必要q多地考证q些名词?/P>
所谓代码页(code page)是针对一U语a文字的字W编码。例如GBK的code page是CP936QBIG5的code page是CP950QGB2312的code page是CP20936?/P>
Windows中有~省代码늚概念Q即~省用什么编码来解释字符。例如Windows的记事本打开了一个文本文Ӟ里面的内Ҏ字节:BA、BA、D7、D6。Windows应该L么解释它呢Q?/P>
是按照Unicode~码解释、还是按照GBK解释、还是按照BIG5解释Q还是按照ISO8859-1去解释?如果按GBK去解释,׃得到“汉字”两个字。按照其它编码解释,可能找不到对应的字符Q也可能扑ֈ错误的字W。所谓“错误”是指与文本作者的本意不符Q这时就产生了ؕ码?/P>
{案是Windows按照当前的缺省代码页去解释文本文仉的字节流。缺省代码页可以通过控制面板的区域选项讄。记事本的另存ؓ中有一ANSIQ其实就是按照缺省代码页的编码方法保存?/P>
Windows的内码是UnicodeQ它在技术上可以同时支持多个代码c只要文件能说明自己使用什么编码,用户又安装了对应的代码页QWindowsp正确昄Q例如在HTML文g中就可以指定charset?/P>
有的HTML文g作者,特别是英文作者,认ؓ世界上所有h都用英文,在文件中不指定charset。如果他使用?x80-0xff之间的字W,中文Windows又按照缺省的GBK去解释,׃出现q。这时只要在q个html文g中加上指定charset的语句,例如Q?BR><meta http-equiv="Content-Type" content="text/html; charset=ISO8859-1"> 再说Z码,啊的Z码是1601Q写?6q制?x10,0x01。这和计机q泛使用的ASCII~码冲突。ؓ了兼?0-7f的ASCII ~码Q我们在Z码的高、低字节上分别加上A0。这样“啊”的~码成为B0A1。我们将加过两个A0的编码也UCؓGB2312~码Q虽然GB2312的原文根本没提到q一炏V?时标和历?/H2>
1、时?/H3>时标QTime ScaleQ就是标度时间的Ҏ。在旉的标度上Q存在着两个怺独立的需求:一斚wQ我们希望时间标度能与地球的自{相吻合,可以UC天文学需求;另一斚wQ我们要求时间标度的单位是精的Q便于大家获得准的旉。由于地球自转的不均匀性,从这两个需求出发制定的时标会有l微的差异?BR>世界ӞUT1Q是Z地球自{的时标,下文会详l介l。国际原子时QTAIQ是Z单位旉的时标,它以“铯-133原子基态两个超_能间跃q辐?9,192,631,770周所持箋的时间”ؓ一U,可以UC原子时标。原子时标的准确度ؓ每日数纳U,而世界时的准度只有数毫U?
1.1 本初子午U?/H4>对于Z天文观测的时标,地球上位于不同经度的观测者,在同一瞬间得的结果是不同的。因此需要统一的地理经度基准?BR>1884q在华盛D行的国际子午U会议决定,采用英国伦敦格林威治QGreenwichQ天文台埃里中星仪所在的子午U作为时间和l度计量的标准参考子午线Q称为本初子午线Q又U格林威d午线。格林威d文台?948q迁到苏塞克斯郡QSussexQ的Herstmonceux CastleQ但旧址l箋被用?度经U的位置?BR>1957q国际上以若q天文测时结果长期稳定性较好的天文台数据ؓ参考,求得q_天文台经度原炏V?968q国际上把通过地极原点和^均天文台l度原点的子午线UCؓ本初子午Uѝ可见,本初子午U的定义已经不依赖于格林威治天文台旧址?
1.2 世界?/H4>世界时的制定基准是太阳的周日视运动。视q动是我们看到的运动。本来是地球l着地up向东转动。但如果观测者以׃动,可以认为太阛_׃向西转动Q这是太阳的周日视q动?BR>地球在自转的同时q围l太阛_转,因ؓ地球公{轨道是椭圆的Q所以太阳的周日视运动是不均匀的。天文学家制定了以太阛_日视q动的^均速度为基的^太阳Ӟq_x的基本单位是q_x。国际天文学联合会于1928q决定,由格林威治q_夜v的q_xUCؓ世界ӞUUT?BR>UT0是天文台观测到的原始数据。UT1在UT0的基上,消除了地轴摆动的影响。还有一个修正了地球自{速度季节性变动的UT2Q现在已l不用了。其实UT0、UT1、UT2的差异很,不超q?.03U。现在提到的世界时一般指UT1?
1.3 时区
世界时区的划?是以本初子午Uؓ标准Q从西经7?分到东经7?分ؓ零时区;从零时区的边界分别向东和向西Q每隔经?5度划一个时区。东、西各划?12个时区,东十二时Z西十二时区相重合。全球共划分?4个时区。各时区都以中央l线的地Ҏ为本区的区时Q相M时区的区时相差一时?BR>在太qx中靠q?80l线附近有一条国际规定的国际日期变更U?U日界线)。此U两侧的日期不同。由东向西过日界U,日期要增加一天(即略M天不)Q由西向东过日界U,日期要减一?x期重复一??
1.4 协调世界ӞUTCQ和闰秒
Z调和天文学需求和单位旉需求的差异Q一U称为协调世界时QUTCQ的折衷时标?972q面世。UTC的秒长与国际原子ӞTAIQ相同。但在必要时QUTC会增?U或L1U,使UTC和世界时(UT1)的时M差保持在u0.9U以内。这一技术措施被UCؓ闰秒QLeap SecondQ?BR>因此QUTC与TAI之间会出现若q整数秒的差别。位于巴黎的国际地球自{事务中央局(IERS)负责军_何时加入闰秒。TAI是从1958q??? ??U开始计时的。在本文写作Ӟ2005q?月)QUTC旉比TAI旉?2U。最q一ơ闰U调整是1999q??日。下ơ闰U调整是 2006q??日?BR>我们提到的地区标准时是在UTC上加上时差得到的本地旉?
1.5 格林威治旉QGMTQ?/H4>格林威治旉QGMTQ是一个比较模p的概念。在1928q_GMT是世界时。在UTC被广泛采用后Q我们提到的GMT实际上是UTC旉Q或者说零时区的标准时?
1.6 GPS旉
GPS旉可以看作没有闰秒调整的UTC旉Qƈ?980q?????UؓL。目前GPS旉比UTC旉?3U?BR>协调世界ӞUTCQ将?005q底实施一个正闰秒。届Ӟ所有的旉拨?U。GPS旉不做闰秒调整Q所以将比UTC旉?4U。从GPS旉计算本地旉Q需要减ȝ前篏计的闰秒Q再加上本地的时差?
1.7 结
在所有时标中Q日和秒的关p都是固定的Q每?6400U。确定了U的长度Q就定了日的长度,反之亦然。原子时标以Uؓ基准Q秒和日的长度都是固定的。世界时以日为基本单位,每日的长度会有毫U的差异。UTC既保证了单位旉的精,又通过闰秒调整与天文观的旉保持不大于?.9U的误差。我们日常生zM使用的时间都以UTC旉为标准?BR>时标作ؓ旉的刻度,为时间长沛_立了一根以U或日ؓ单位的坐标u。虽Ӟ“GPS旉280948U”可以标志一个唯一的时刻,但用于日常生zL免不太方ѝ在日常生活中,我们需要更方便的标记时间的ҎQ这是下面要谈到的历法?
2、历?/H3>所谓历法,是通过合理地安排年、月、日q三个基本量的关p,为时间徏立标记的Ҏ?
2.1 回归q和朔望?/H4>前面说过Q地球自转可以看作太阳的周日视运动。同理,地球l太阳的公{Q可以被看作太阳的周q视q动。周q视q动的轨道被UC黄道Q黄道面和赤道面的夹角是2327Ӏ随着太阳在黄道上的位|不同,地球上的季节也由春到夏,以至U冬?BR>黄道和赤道的两个交点分别被称作春分点和秋分点Q这两点在黄道上的两个中点分别被UC夏至点和冬至炏V太阳从春分点出发,l黄道一周,又回到春分点所q旉被称为回归年。目前测量的回归q长度是365.242189日?BR>月亮的盈亏变化,产生了月。月亮绕地球旋{Q当转到正对着太阳的位|,我们׃观测到满月,q就是望Q当转到背对太阳的位|,我们会完全看不到Q这是朔。月亮从朔到朔,或从望到望所q旉被称作朔望月。目前测量的朔望月长度是29.530588853000001日?
2.2 历法的分c?/H4>仅以太阳q动Z据的历法被称作阳历或太阳历。例如我们现在用的公历。阳历以回归qؓ基本周期Q与月亮q动没有M关系?BR>仅以月亮q动Z据的历法被称作阴历或太阴历。例如伊斯兰教国家和地区使用的回历。阴历以朔望月ؓ基本周期Q与太阳q动没有M关系?BR>同时考虑太阳和月亮运动的历法被称作阴阛_Q例如我国的农历。在我国Q农历习惯上也被UC阴历。阴阛_把回归年和朔望月q列为制历的基本周期?BR>׃回归q、朔望月的长度都不是日的整数倍,所以各U历法都要通过增加闰日或闰月,来调整自׃基本周期的差异。下面介l几U常用的历法?
2.3 儒略?/H4>公元?6q_|马执政官儒略·凯撒颁布了儒略历。儒略历每年12个月Q^q?65天,闰年366天。除2月外Q单数月?1天,偶数月䆾30天?月䆾q_29天,闰年30天。每?q置一闰年?BR>儒略历是U太阛_Q每q的q_长度?65.25天。每400q_儒略历与回归q大U相?天,卻I
(365.25-365.242189)*400 = 3.1244
凯撒ZU念改历成功Q将他出生的7月从QuintilisҎ自己的名字Julius?
2.4 奥古斯都?/H4>奥古斯都是“神圣”的意思,q是当时Z对罗马统治者屋大维的尊U?BR>从公元前42q到公元?q_儒略历被错误地执行ؓ“每3q置一闰年”。儒略·凯撒的侄子屋大l纠正了q个错误Q同时将自己出生?月从Sextilis Ҏ自己的称号AugustusQ将8月改?1天,??0?1?2月的大小月对换,q从2月䆾扣去一天,成ؓq_28天,闰年29天?BR>奥古斯都历的月䆾讄和现在的公历已经完全相同了?
2.5 格里高利历——公?/H4>公元1582q??日,|马教皇格里高利十三世颁布了格里高利历,不能被4整除的世U年作q_Q这是我们现在使用的公历?BR>在公历中Q每400q有97个闰q_q_每年的长度是Q?BR>(365*400+97)/400 = 365.2425 ?BR>?00q_公历与回归年大约相差0.1244天,卻I
(365.2425-365.242189)*400 = 0.1244
2.6 儒略日和化儒略日
在天文学有一U连l纪日的儒略日(JDQ,它以儒略历公元前4713q??日的GMT正午为第0日的开始。还有一U简化儒略日QMJDQ:
MJD=JD-2400000.5
MJD的第0日是从公?858q?1?7日的GMT零时开始的。我写完前一个句h的MJD?3583.22260。小数部分是以UTC旉在当天逝去的秒数除?6400得到的?.22260UؓUTC旉?:20Q加上中国的时区是13:20?BR>需要注意:儒略历公元前4713q??日相当于公历公元?713q?1?4日。在香港天文台的|页上,儒略历说成以“公元前4713q??日格林尼d^时正午”v,是错误的?
2.7 农历
2.7.1 月的划分
农历的月是严格按照朔的时ȝ定的Q朔所在日是初一。由于朔望月的长度约?9.A日(小数部分记作AQ,假设朔发生在(30-29.A)日以内的时刻Q两个朔之间只?9天,该月是月Q否则两个朔之间?0天,该月是大月?
2.7.2 设计
我们已经Ҏ月亮的运动规律将旉长u划分Z个个月,下面要做的就是确定将哪些月组合成q。设计要求是Q该设计应四季在每q的位置相对E_?BR>设计思\是这LQ四季变化以回归qؓ周期Q回归年的长度约?65.242189日?2个朔望月的长度约?54.367066236日,13个朔望月的长度约?83.897655089。如果我们让有的q䆾?2个朔望月Q有的年份有13个朔望月Qƈ按照一定周期@环;在一个周期内Q年的^均长度接q回归年的长度,p实现我们的设计目标。例如:我们?9q中Q让7q有13个月Q其它年?2个月Q则?9q的周期里,每年的^均长度是Q?BR>(29.530588853000001*(12*19+7))/19 ?365.246756866 ?BR>q个l果与回归年的长度已l比较接q。包?2个朔望月的年份被UCq_Q包?3个朔望月的年份被UC闰年Q闰q多加的一个月被称作闰月,q就是《尚书·尧典》中所说的“以闰月定四时成岁”?BR>那么Q闰月加在哪里呢Q在介绍|闰的规则前Q必d介绍一下节气?
2.7.3 二十四节?/H5>以春分点为黄l?度,黄道分成二十四{分Q每{分占黄l?5度,太阳通过{分点的时刻是对应节气的时刅R二十四节气只与太阳的运动有养I所以它们在公历中的日期变化不大?BR>二十四节气从立春Q黄l?0度)开始,依次为立春、雨水、惊蛰、春分、清明、谷雨、立夏、小满、芒U、夏臟뀁小暑、大暑、立U、处暑、白霌Ӏ秋分、寒霌Ӏ霜降、立冬、小雪、大雪、冬臟뀁小寒、大寒?BR>立春作为第1个节气,依次~号。偶数编L节气被称为“中气”(major solar termsQ,奇数~号的节气仍UC“节气”(minor solar termsQ。我们在日常生活中将节气和中气统UCؓ节气Qsolar termsQ。中气是|闰的重要依据?
2.7.4 |闰
在农历中Q从前一q正月初一C一q正月初一被称作年。显Ӟ必须先确定了闰月Q才能确定年的范_我们不可能在|闰规则中用到“年”。实际上Q我们用C另一个概念:岁。从前一个冬臛_下一个冬臌UC岁。“岁”的长度是回归q的长度?BR>冬至所在的月被定义?1月。如果在两个11月间?2个完整的月,那么q两?1月间的岁pUC闰岁。因两个11月间只有11个中气,所以闰岁的12个月中至有一个月没有中气?BR>闰岁的第一个不含中气的月,是闰月。至此,我们已经描述了编制农历的完整规则?
2.7.5 闰年和Y2033问题
包含闰月的年被称作闰q。如果闰月出现在11月,可能出现前一q是闰年Q但不是闰岁Q后一q是闰岁Q但不是闰年。一个典型的例子是Y2033问题?BR>?033q的W?个月vQ第8个月没有中气Q第11个月有两个中气,W?2个月没有中气Q第13个月有两个中气,W?4个月没有中气。在2032q的 11月和2033q?1月间只有11个完整的月,不是闰岁。在2033q的11月和2034q?1月间?2个完整的月,是闰岁?BR>按照|闰规则Q第12个月被作为闰月,即闰11月?月没有中气,又不是闰月,被称作伪闰月QFake leap monthQ?034q是闰岁Q但不是闰年?034岁的闰月已经?033q加q了?BR>国内1990q以前的万年历都?033q设为闰7月,q个错误被称作Y2033问题。以后出版的万年历都Ҏ了闰11月。但|上的一些万q历E序现在q在使用错误的农历数据?
2.7 回历
作ؓ太阴历的例子Q简单介l一下回历。回历是伊斯兰教国家和地区采用的历法。它以朔望月为基本周期,每年12个月。^q奇数月30天,偶数?9天,?54天?BR>?0qؓ一周,?1个闰日。在30q@环周期中Q第2???0?3?6?8?1?4?6?9qؓ闰年。闰q在12月底增加一??55天?BR>在回历中Q月的^均长度是Q?BR>(354*30+11)/30/12 ?29.53 ?BR>q和朔望月长度非常接q,很好地符合了月亮的运动规律。年的^均长度是Q?BR>(354*30+11)/30 ?354.366667 ?BR>q和回归q约?1天。因此回历的新年在公历中会逐年提早Q@环周期ؓ
365.242189/(365.242189-354.366667) ?33.5838766176 q?BR>回历的v始历元被UC伊斯兰教U元Q定在穆|默德从麦加q到麦地那的一天,卛_略历公元622q??6日,在公历中是公?22q??9日。例如:伊斯兰教U元1426q??日是公元2005q??0日。伊斯兰教纪?427q??日是公元2006q??1日?
2.8 结
公历和回历的计算都很单。但公历的月不能W合月亮的运动规律。回历的q不能符合太阳的q动规律。农历较好地W合了太阛_月亮的运动规律,但计比较复杂?BR>在网上可以找到计各国历法的E序。我曄其中一个JavaE序库的农历部分改写成C/C++E序Q以提高q算速度。在我的个h主页上有关于农历计算E序的进一步讨?http://fmddlmyy.home4u.china.com/cal.html)。不q这些内容已l超Z本文的范围?BR>在写q篇文章前,我不知道“时标”,对历法的概念也很模糊。通过查资料、写作,我对相关概念的了解越来越清晰。这文章的写作目的是将时标、历法的一些基本概늮单、清晰地描述出来Q希望有更多的读者像我一样从中受益?
谈谈Unicode~码Q简要解释UCS、UTF、BMP、BOM{名?/H2>
0、big endian和little endian
1、字W编码、内码,带介绍汉字~码
2、Unicode、UCS和UTF
2.1、内码和code page
3、UCS-2、UCS-4、BMP
4、UTF~码
UCS-2~码(16q制)
UTF-8 字节?二进?
0000 - 007F
0xxxxxxx
0080 - 07FF
110xxxxx 10xxxxxx
0800 - FFFF
1110xxxx 10xxxxxx 10xxxxxx 5、UTF的字节序和BOM
6、进一步的参考资?/H3>
附录1 再说说区位码、GB2312、内码和代码?/H3>
“GB2312的原文还是区位码Q从Z码到内码Q需要在高字节和低字节上分别加上A0。?/P>
如果原作者用的代码和ISO8859-1兼容Q就不会出现q了?/P>
可以实现点划U的Border.
代码如下Q?BR>
import javax.swing.*;
import javax.swing.border.*;
/**
* DotDashBorder is a java.swing.border.Border
implementation
* that draws a dotted and/or dashed line border. The dot/dash pattern is
* defined as an array of ints, with every two indices defining the number
* of pixels for each dot/dash and space. E.g.:
* { 1, 1 } == 1-pixel-dot, 1-pixel-space, 1-pixel-dot, 1-pixel-space, etc.
* { 4, 2 } == 4-pixel-dash, 2-pixel-space, 4-pixel-dash, 2-pixel-space, etc.
*/
public class DotDashBorder extends AbstractBorder {
/**
* Defines a dotted line pattern: . . . .
*/
public static final int[] DOT = { 1, 1 };
/**
* Defines a dashed line pattern: - - - -
*/
public static final int[] DASH_SHORT = { 4, 4 };
/**
* Defines a long dashed line pattern: --- --- ---
*/
public static final int[] DASH_LONG = { 10, 10 };
/**
* Defines a long/short dashed line pattern: -- - -- - -- -
*/
public static final int[] DASH_LONG_SHORT = { 6, 3, 3, 3 };
/**
* Defines a long/short/short dashed line pattern: -- - - -- - - -- - -
*/
public static final int[] DASH_LONG_SHORT_SHORT = { 6, 3, 3, 3, 3, 3 };
/**
* The dot/dash pattern.
*/
private int[] pattern = DOT;
/**
* The border thickness
*/
private int thickness = 1;
/**
* The foreground color. If not specified, the component's foreground
* color is used.
*/
private Color colorFG = null;
/**
* The background color. If not specified, the component's background
* color is used.
*/
private Color colorBG = null;
/**
* Thicken border pattern relative to thickness flag.
*/
private boolean thicken = false;
/**
* Create a new 1-pixel thick DotDashBorder using the component's
* background color.
* @param pattern int[]: the dot/dash-space pattern
* @param fg Color: the foreground (dot/dash) color
*/
public DotDashBorder(int[] pattern, Color fg) {
this(pattern, 1, fg, null);
}
/**
* Create a new DotDashBorder using the component's foreground and
* background colors.
* @param pattern int[]: the dot/dash-space pattern
* @param thickness int: the border thickness
*/
public DotDashBorder(int[] pattern, int thickness) {
this(pattern, thickness, null, null);
}
/**
* Create a new DotDashBorder using the component's
* background color.
* @param pattern int[]: the dot/dash-space pattern
* @param thickness int: the border thickness
* @param fg Color: the foreground (dot/dash) color
*/
public DotDashBorder(int[] pattern, int thickness, Color fg) {
this(pattern, thickness, fg, null);
}
/**
* Create a new DotDashBorder.
* @param pattern int[]: the dot/dash-space pattern
* @param thickness int: the border thickness
* @param fg Color: the foreground (dot/dash) color
* @param bg Color: the background (space) color
*/
public DotDashBorder(int[] pattern, int thickness, Color fg, Color bg) {
for(int i = 0; i < pattern.length; i++) {
if(pattern[i] <= 0) {
throw new IllegalArgumentException("Pattern cannot have values <= 0.");
}
}
this.pattern = pattern;
if(thickness <= 0) {
throw new IllegalArgumentException("Thickness cannot be <= 0.");
}
this.thickness = thickness;
this.colorFG = fg;
this.colorBG = bg;
}
/**
* Get the insets for the border.
* @param Component c: the component the border is for
* @return Insets: the insets for the border
* @see #getBorderInsets(Component, Insets)
*/
public Insets getBorderInsets(Component c) {
return new Insets(thickness, thickness, thickness, thickness);
}
/**
* Get the insets for the border.
* @param Component c: the component the border is for
* @param insets Insets: the insets
* @return Insets: the insets for the border
* @see #getBorderInsets(Component)
*/
public Insets getBorderInsets(Component c, Insets insets) {
return new Insets(thickness, thickness, thickness, thickness);
}
/**
* Check if the border is opaque.
* @return boolean: true if the border is opaque
*/
public boolean isBorderOpaque() {
return true;
}
/**
* Check if pattern will be thickened by thickness.
* @return boolean: true if pattern will be thickened by thickness
* @see #setThickenPattern(boolean)
*/
public boolean isThickenPattern() {
return this.thicken;
}
/**
* Set if the pattern should be thickened by thickness. If true, a
* pattern of { 1, 1 } and thickness of 5, the pattern would be expanded
* to { 5, 5 }. This allows setting a pattern based on small pixel
* measurements that grows proportionally with the thickness.
* @param boolean t: true if pattern should be thickened by thickness
* @see #isThickenPattern()
*/
public void setThickenPattern(boolean t) {
this.thicken = t;
}
/**
* Paint the border.
* @param Component c: the component the border is for
* @param Graphics g: the graphics object to draw on
* @param x int: the border y position
* @param y int: the border x position
* @param width int: the border width
* @param height int: the border height
*/
public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
Color colorFGX = c.getBackground();
if(colorFG != null) {
colorFGX = colorFG;
}
Color colorBGX = c.getBackground();
if(colorBG != null) {
colorBGX = colorBG;
}
g.setColor(colorFGX);
g.fillRect(x, x, width, thickness); // top
g.fillRect(x, y+height-thickness, width, thickness); // bottom
g.fillRect(x, y, thickness, height); // left
g.fillRect(x+width-thickness, y, thickness, height); // right
g.setColor(colorBGX);
// top/bottom
int cx = 0;
// get real pattern
int[] realPattern = new int[pattern.length];
for(int i = 0; i < pattern.length; i++) {
if(thicken) {
realPattern[i] = pattern[i]*thickness;
} else {
realPattern[i] = pattern[i];
}
}
for(int i = 0, j = 0; i < width; i++, j+=2) {
if(j >= realPattern.length) {
j = 0;
}
cx += realPattern[j];
g.fillRect(cx, y, realPattern[j+1], thickness); // top
g.fillRect(cx, y+height-thickness, realPattern[j+1], thickness); // bottom
cx += realPattern[j+1];
}
// left/right
int cy = 0;
for(int i = 0, j = 0; i < height; i++, j+=2) {
if(j >= realPattern.length) {
j = 0;
}
cy += realPattern[j];
g.fillRect(x, cy, thickness, realPattern[j+1]); // left
g.fillRect(x+width-thickness, cy, thickness, realPattern[j+1]); // right
cy += realPattern[j+1];
}
}
}
import java.awt.Toolkit;
import java.net.URL;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class SplashScreen extends JFrame {
/**Date 08.17.2005
*
* Splash Screen
* Very Simple
* @author Pudgy
* @version 0.01
*
*
*/
private static final long serialVersionUID = 5124L;
public SplashScreen() {
super("Starting jDicomSee");
Toolkit toolkit = Toolkit.getDefaultToolkit();
Dimension screenSize = toolkit.getScreenSize();
URL imageURL = searchFile("splash.png");
if (imageURL != null) {
getContentPane().add(new JLabel(new ImageIcon(imageURL)));
}
setUndecorated(true);
pack();
setLocation((screenSize.width - getWidth()) / 2,
(screenSize.height - getHeight()) / 2);
setVisible(true);
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private URL searchFile(String fileName) {
URL url = getClass().getClassLoader().getResource(fileName);
if (url == null)
url = getClass().getClassLoader().getResource("images/" + fileName);
return url;
}
}
Java Learning Path Q一Q、工L
一?nbsp;JDK (Java Development Kit)
JDK是整个Java的核心,包括了Javaq行环境QJava Runtime EnvirnmentQ,一堆Java工具和Java基础的类?rt.jar)。不Z么Java应用服务器实质都是内|了某个版本的JDK。因此掌握JDK是学好Java的第一步。最L的JDK是Sun公司发布的JDKQ除了Sun之外Q还有很多公司和l织都开发了自己的JDKQ例如IBM公司开发的JDKQBEA公司的JrocketQ还有GNUl织开发的JDK{等。其中IBM的JDK包含的JVMQJava Virtual MachineQ运行效率要比Sun JDK包含的JVM高出许多。而专门运行在x86q_的Jrocket在服务端q行效率也要比Sun JDK好很多。但不管怎么_我们q是需要先把Sun JDK掌握好?nbsp;
1?nbsp;JDK的下载和安装
JDK又叫做J2SEQJava2 SDK Standard EditionQ,可以从Sun的Java|站上下载到Qhttp://java.sun.com/j2se/downloads.html QJDK当前最新的版本是J2SDK1.4.2Q徏议下载该版本的JDKQ下载页面在q里Qhttp://java.sun.com/j2se/1.4.2/download.html?nbsp;
下蝲好的JDK是一个可执行安装E序Q默认安装完毕后会在C:\Program Files\Java\目录下安装一套JREQ供览器来使用Q,在C:\j2sdk1.4.2下安装一套JDKQ也包括一套JREQ。然后我们需要在环境变量PATH的最前面增加java的\径C:\j2sdk1.4.2\bin。这样JDK安装好了?nbsp;
2?nbsp;JDK的命令工?nbsp;
JDK的最重要命o行工P
javaQ?nbsp;启动JVM执行class
javacQ?nbsp;Java~译?nbsp;
jarQ?nbsp;Java打包工具
javadocQ?nbsp;Java文档生成?nbsp;
q些命o行必要非常非常熟悉Q对于每个参数都要很_N才行。对于这些命令的学习QJDK Documentation上有详细的文档?nbsp;
二?nbsp;JDK Documentation
Documentation在JDK的下载页面也有下载连接,同时下蝲Documentation。Documentation是最最重要的编E手册,늛了整个Java所有方面的内容的描q。可以这栯Q学习Java~程Q大部分旉都是花在看这个Documentation上面的。我是随w携带的Q写Java代码的时候,随时查看Q须臾不L?nbsp;
三?nbsp;应用服务?App Server)
App Server是运行Java企业lg的^収ͼ构成了应用Y件的主要q行环境。当前主的App Server是BEA公司的Weblogic Server和IBM公司的Websphere以及免费的JbossQ选择其中一个进行学习就可以了,个h推荐WeblogicQ因为它的体pȝ构更加干净Q开发和部v更加方便Q是Java企业软g开发h员首选的开发^台。下面简要介l几U常用的App ServerQ?nbsp;
1?nbsp;Tomcat
Tomcat严格意义上ƈ不是一个真正的App ServerQ它只是一个可以支持运行Serlvet/JSP的Web容器Q不qTomcat也扩展了一些App Server的功能,如JNDIQ数据库q接池,用户事务处理{等。Tomcat被非常广泛的应用在中规模的Java Web应用中,因此本文做一点下载、安装和配置Tomcat的介l:
Tomcat是Apachel织下Jakarta目下的一个子目Q它的主|站是:http://jakarta.apache.org/tomcat/ QTomcat最新版本是Tomcat4.1.27QY件下载的q接是:http://www.apache.org/dist/jakarta/tomcat-4/binaries/ ?nbsp;
下蝲Tomcat既可以直接下载zip包,也可以下载exe安装包(个hzip更干净些)Q不哪U情况,下蝲完毕安装好以后(zip直接解压~就可以了)。需要设|两个环境变量:
JAVA_HOME=C:\j2sdk1.4.2
CATALINA_HOME=D:\tomcat4 (你的Tomcat安装目录)
q样安装好了,启动Tomcatq行CATALINA_HOME\bin\startup.batQ关闭Tomcatq行shutdown.bat脚本。Tomcat启动以后Q默认?080端口Q因此可以用览器访问http://localhost:8080来测试Tomcat是否正常启动?nbsp;
Tomcat提供了两个Web界面的管理工PURL分别是:
http://localhost:8080/admin/index.jsp
http://localhost:8080/manager/html
在启用这两个理工具之前Q先需要手工配|一下管理员用户和口令。用一个文本工h开CATALINA_HOME\conf\tomcat-users.xmlq个文gQ加入如下几行:
<role rolename="manager"/>
<role rolename="admin"/>
<user username="robbin" password="12345678" roles="admin,manager,tomcat"/>
q样用户“robbin”就具备了超U管理员权限。重新启动Tomcat以后Q你可以用该用户来登陆如上的两个理工具Q通过Web方式q行Tomcat的配|和理了?nbsp;
2?nbsp;BEA Weblogic
Weblogic可以到BEA的网站上免费注册之后下蝲到最新的Weblogic8.1企业版,License可以免费使用1q时_其实q已l完全够了。Weblogic的下载连接:http://commerce.bea.com/index.jspQWeblogic的在U文档:http://edocs.bea.com/ ?nbsp;
3?nbsp;IBM Webshpere
Websphere同样可以下蝲到免费的试用版本Q到IBM的developerWorks|站可以看到Websphere试用产品的下载和相关的Websphere的资料,developerWorks中文|站的连接是Qhttp://www-900.ibm.com/developerWorks/cn/wsdd/ QWebsphere的下载连接:http://www7b.software.ibm.com/wsdd/downloads/WASsupport.html ?nbsp;
4?nbsp;Jboss
Jboss是免费开源的App ServerQ可以免费的从Jboss|站下蝲Qhttp://www.jboss.org/index.htmlQ然而Jboss的文档是不免费,需要花p乎ͼ所以ؓ我们学习Jboss讄了一定的障碍。在Jdon上有几篇不错的Jboss配置文档Q可以用来参考:http://www.jdon.com/idea.html
四?nbsp;Java应用的运行环?nbsp;
Java的应用可以简单分Z下几个方面:
1?nbsp;Java的桌面应?nbsp;
桌面应用一般仅仅需要JRE的支持就_了?nbsp;
2?nbsp;Java Web应用
Java的Web应用臛_需要安装JDK和一个web容器Q例如TomcatQ,以及一个多用户数据库,Web应用臛_分ؓ三层Q?nbsp;
Browser层:览器显C用户页?nbsp;
Web层:q行Servlet/JSP
DB层:后端数据库,向JavaE序提供数据讉K服务
3?nbsp;Java企业U应?nbsp;
企业U应用比较复杂,可以扩展到n层,最单情况会分ؓ4层:
Browser层:览器显C用户页?nbsp;
Client层:Java客户端图形程序(或者嵌入式讑֤的程序)直接和Web层或者EJB层交?nbsp;
Web层:q行Servlet/JSP
EJB层:q行EJBQ完成业务逻辑q算
DB层:后端数据库,向JavaE序提供数据讉K服务
4?nbsp;Java嵌入式应?nbsp;
Java嵌入式应用是一个方兴未艄领域Q从事嵌入式开发,需要从Sun下蝲J2ME开发包QJ2ME包含了嵌入式讑֤专用虚拟机KVMQ和普通的JDK中包含的JVM有所不同。另外还需要到特定的嵌入式厂商那里下蝲模拟器?nbsp;
Java Learning PathQ二Q、书c篇
学习一门新的知识,不可能指望只看一本,或者两本书p够完全掌握。需要有一个@序渐q的阅读q程。我推荐Oreilly出版的Javapd书籍?nbsp;
在这里我只想补充一点看法,很多人学习Java是从《Thinking in Java》这本书入手的,但是我认本书是不适合初学者的。我认ؓ正确的用这本书的方法应该是作ؓ辅助的读物。《Thinking in Java》ƈ不是在完整的介绍Java的整个体p,而是一U蟩跃式的写作方法,是一U类似tips的方法来对Java很多知识点进行了深入的分析和解释?nbsp;
对于初学者来_最好是找一本Java入门的书c,但是比较完整的@序的介绍Java的语法,面向对象的特性,核心cd{等Q在看这本书的同Ӟ可以同步来看《Thinking in Java》,来加深对Java的理解和原理的运用,同时又可以完整的了解Java的整个体pR?nbsp;
对于Java的入门书c,蔡学镛推荐的是Oreilly的《Exploring Java, 2nd Edition?nbsp;或者《Java in a Nutshell,2nd EditionQ针对C++背景Q》,我ƈ没有看过q两本书。其实我觉得电子工业出版C《Java 2~程详解》或者《Java 2从入门到_N》就很不错?nbsp;
在所有的Java书籍当中Q其实最最有用的,q不是O'reilly?nbsp;Java SerialsQ真正最最有用处是JDK的DocumentationQ几乎你惌得的所有的知识在Documentation里面全部都有Q其中最主要的部分当然是Java基础cd的API文档Q是按照package来组l的Q对于每一个class都有详细的解释,它的l承关系Q是否实C某个接口Q通常用在哪些场合Q还可以查到它所有的public的属性和ҎQ每个属性的解释Q意义,每个Ҏ的用途,调用的参敎ͼ参数的意义,q回值的cdQ以及方法可能抛出的异常{等。可以这h_所有关于Java~程斚w的书c其实都不过是在用比较通俗易懂的语aQ和良好的组l方式来介绍Documentation里面的某个package里面包含的一些类的用法而已。所以万变不d宗,如果你有_的能力来直接通过Documentation来学习Java的类库,那么基本上就不需要看其他的书c了。除此之外,Documentation也是~程必备的手册,我的桌面上有三个Documentation的快h式,分别是J2SDK1.4.1的DocumentationQServlet2.3的Documentation和J2SDKEE1.3.1的Documentation。有了这个三个DocumentationQ什么其他的书籍都不需要了?nbsp;
对于Java Web ~程来说Q最核心的是要熟悉和掌握HTTP协议Q这个就和Java无关了,在熟悉HTTP协议之后Q就需要熟悉Java的实现HTTP协议的类库,也就是Servlet APIQ所以最重要的东西就是Servlet API。当然对于初学者而言Q直接通过Servlet API来学习Web~程有很大的隑ֺQ我推荐O'reilly的《Java Server Pages 》这本书来学习Web ~程?nbsp;
EJB的书c当中,《Enterprise JavaBeans, 2nd Edition》是一本很不错的书Q?nbsp;EJB的学习门槛是比较高,入门很难Q但是这本书完全降低了学习的隑ֺQ特别重要的一ҎQEJB的学习需要结合一UApp Server的具体实玎ͼ所以在学习EJB的同Ӟ必须同步的学习某UApp ServerQ而这本书相关的出了三本书Q分别是Weblogic6.1QWebsphere4.0和JBoss3.0上面部v书中例子的实做。真是既有理论,又有实践。在学习EJB的同Ӟ可以边看边做QEJB的学习会变得很轻松?nbsp;
但是q本书也有一个问题,是版本比较旧,主要讲EJB1.1规范和部分EJB2.0的规范。而Ed Roman写的《Mastering EJB 2.0》这本书完全是根据EJB2.0规范写的Q深入浅出,覆盖了EJB~程的各个方面,q且q有很多~程l验tipsQ也是学习EJB非常推荐的书c之一?nbsp;
如果是结合Weblogic来学习J2EE的话Q《J2EE应用与BEA Weblogic Server》绝Ҏ首选读物,虽然是讲q的Weblogic6.0Q仍然值得购买Q这本书是BEA官方推荐的教材,作者也是BEA公司的工E师。现在中文版已经随处可见了。这本书l合Weblogic介绍了J2EE各个斚w的技术在Weblogicq_上的开发和部vQ实跉|导意义非常强?nbsp;
在掌握了Javaq_基础知识和J2EE斚w的知识以后,更进一步的是学习如何运用OO的方法进行Y件的设计Q那么就一定要学习“设计模式”。Sun公司出版了一本《J2EE核心模式》,是每个开发Java企业q_软g的架构师必备的书c。这本书全面的介l了J2EE体系架构的各U设计模式,是设计师的必Mc?nbsp;
Java Learning PathQ三Q过E篇
每个人的学习Ҏ是不同的Q一个h的方法不见得适合另一个hQ我只能是谈自己的学习方法。因为我学习Java是完全自学的Q从来没有问q别人,所以学习的q程基本上完全是自己摸烦出来的。我也不知道q种Ҏ是否是比较好的方法,只能l大家提供一点参考了?nbsp;
学习Java的第一步是安装好JDKQ写一个Hello WorldQ? 其实JDK的学习没有那么简单,关于JDK有两个问题是很容易一直困扰JavaE序员的地方Q一个是CLASSPATH的问题,其实从原理上来说Q是要搞清楚JRE的ClassLoader是如何加载Class的;另一个问题是package和import问题Q如何来Lcȝ路径问题。把q两个问题摸索清楚了Q就扫除了学习Java和用JDK的最大障。推荐看一下王的《Java深度历险》,对这两个问题q行了深入的探讨?nbsp;
W二步是学习Java的语法。Java的语法是cC++的,基本上主的~程语言不是cCQ就是类C++的,没有什么新东西Q所以语法的学习Q大概就是半天的旉_了。唯一需要注意的是有几个不容易搞清楚的关键字的用法,publicQprotectedQprivateQstaticQ什么时候用Qؓ什么要用,怎么用,q可能需要有人来指点一下,我当初是完全自己琢磨出来的,׃很久的时间。不q后来我看到《Thinking in Java》这本书上面是讲了这些概늚?nbsp;
W三步是学习Java的面向对象的~程语言的特性的地方。比如承,构造器Q抽象类Q接口,Ҏ的多态,重蝲Q覆盖,Java的异常处理机制。对于一个没有面向对象语a背景的h来说Q我觉得q个q程需要花很长很长旉Q因为学习Java之前没有C++的经验,只有C的经验,我是大概׃一个月左右吧,才彻底把q些概念都搞清楚Q把书上面的例子反复的揣摩,修改Q尝试,把那几章内容反复的看q来Q看q去Q看了不?遍,才彻底领悟了。不q我惛_果有C++l验的话Q应该一两天旉_了。那么在q个q程中,可以多看看《Thinking in Java》这本书Q对面向对象的讲解非帔R彻。可惜的是我学习的时候,q没有看到这本书Q所以自p了大量的旉Q通过自己的尝试和揣摩来学会的?nbsp;
W四步就是开始熟悉Java的类库。Java的基cd其实是JDK安装目录下面jre\lib\rt.jarq个包。学习基cd是学习rt.jar。基cd里面的类非常非常多。据说有3000多个Q我没有l计q。但是真正对于我们来说最核心的只?个,分别?nbsp;
java.lang.*;
java.io.*;
java.util.*;
java.sql.*;
q四个包的学习,每个包的学习都可以写成一本厚厚的教材Q而O'reilly也确实是q样做的。我觉得如果旉比较紧,是不可能通过d本书来学习。我觉得比较好的学习Ҏ是这LQ?nbsp;
首先要通读整个package的框Ӟ了解整个package的classQinterfaceQexception的构成,最好是能够扑ֈ介绍整个包框架的文章。这些专门介l包的书c的前几章应该就是这些M的框架内容介l?nbsp;
对包整体框架的把握ƈ不是要熟悉每个类的用法,C它有哪些属性,Ҏ。想CC住的。而是要知道包有哪些方面的cL成的Q这些类的用途是什么,最核心的几个类分别是完成什么功能的。我在给人培训的时候一般是一ơ课讲一个包Q所以不可能详细的介l每个类的用法,但是我反复强调,我给你们讲这些包的不是要告诉你们cȝҎ是怎么调用的,也不要求你们CcȝҎ调用Q而是要你们了解,Javal我们提供了哪些c,每个cL用在什么场合,当我遇到问题的时候,我知道哪个类Q或者哪几个cȝl合可以解决我的问题QThat'allQ,当我们具体写E序的时候,只要你知道该用哪个类来完成你的工作就_了。编码的时候,具体的方法调用,是边写代码,ҎDocumentationQ所有的东西都在Documentation里面Q不要求你一定记住,实际你也C?000多个cȝd近10万个Ҏ调用。所以对每个包的M框架的把握就变得极ؓ重要?nbsp;
W五步,通过上面的学习,如果学的比较扎实的话Q就打好了Java的基了,剩下要做的工作是扫清Documentation里面除了上面4个包之外的其他一些比较有用处的类。相信进展到q一步,Java的自学能力已l被培养出来了,可以C直接学习Documentation的水q了。除了要做GUI~程之外QJDK里面其他会有用处的包是这些:
java.text.*;
java.net.*;
javax.naming.*;
q些包里面真正用的比较多的类其实很少Q只有几个,所以不需要花很多旉?nbsp;
W六步,Java Web ~程
Web~程的核心是HTTP协议QHTTP协议和Java无关Q如果不熟悉HTTP协议的话Q虽然也可以学好Servlet/JSP~程Q但是达不到举一反三Q一通百通的境界。所以HTTP协议的学习是必备的。如果熟悉了HTTP协议的话Q又有了Java~程的良好的基础Q学习Servlet/JSP直易如反掌,我学习Servlet/JSPq了不C周的旉Q然后就开始用JSP来做目了?nbsp;
在Servlet/JSP的学习中Q重头仍然是Servlet Documentation。Servlet API最常用的类很少Q花比较的旉可以掌握了。把q些c都看一遍,多写几个例子试试。Servlet/JSP~程本质是在反复调用这些类来通过HTTP协议在Web Server和Brower之间交谈。另外对JSPQ还需要熟悉几个常用JSP的标讎ͼ具体的写法记不住的话Q时查是了?nbsp;
此外Java Web~程学习的重点要攑֜Web Application的设计模式上Q如何进行业务逻辑的分析,q且q行合理的设计,按照MVC设计模式的要求,q用Servlet和JSP分别完成不同的逻辑层,掌握如何在Servlet和JSP之间q行程的控制和数据的共享,以及Web Application应该如何配置和部|Ӏ?nbsp;
W七步,J2EE~程
以上的学习过E如果是比较利的话Q进行到q一步,隑ֺ又陡然提高。因Z面的知识内容都是只涉及一个方面,而像EJBQJMSQJTA{核心的J2EE规范往往是几UJava技术的l合q用的结Ӟ所以掌握v来难度比较大?nbsp;
首先一定要学习好JNDIQJNDI是App Server定位服务器资源(EJBlgQDatasouceQJMSQ查找方法,如果对JNDI不熟悉的话,EJBQJMSq些东西几乎学不下去。JNDI其实是javax.naming.*q个包,q用h很简单。难点在于服务器资源文g的配|。对于服务器资源文g的配|,需要看看专门的文档规范了,比如web.xml的写法,ejb-jar.xml的写法等{。针ҎU不同的App ServerQ还有自q服务资源配置文gQ也是需要熟悉的?nbsp;
然后可以学习JTAQ主要是要理解JTA对于事务的控制的ҎQ以及该在什么场合用JTA。这里可以简单的举个例子Q我们知道一般情况可以对于一个数据库q接q行事务控制(conn.setAutoCommit(false),....,conn.commit())Q做Z个原子操作,但是假设我的业务需求是要把对两个不同数据库的操作做Z个原子操作,你能做的到吗Q这时候只能用JTA了。假设操作过E是先往A数据库插一条记录,然后删除B数据库另一个记录,我们自己写代码是控制不了把整个操作做Z个原子操作的。用JTA的话Q由App Server来完成控制?nbsp;
在学习EJB之前要学习对象序列化和RMIQRMI是EJB的基。接着学习JMS和EJBQ对于EJB来说Q最关键是要理解EJB是如何通过RMI来实现对q端对象的调用的Q以及在什么情况下要用到EJB?nbsp;
在学习完EJBQJMSq些东西之后Q你可能会意识到要急不可待学习两个领域的知识,一个是UMLQ另一个是Design Pattern。Java企业软g的设计非帔R视框?Framework)的设计,一个好的Y件框架是软g开发成功的必要条g。在q个时候,应该开始把学习的重Ҏ在设计模式和框架的学习上Q通过学习和实际的~程l验来掌握EJB的设计模式和J2EE的核心模式?nbsp;
J2EE规范里面Q除了EJBQJMSQJTAQServlet/JSPQJDBC之外q有很多很多的企业技术,q里不一一q行介绍了?nbsp;
另外q有一个最新领域Web Services。Web Services也完全没有Q何新东西Q它像是一U黏合剂Q可以把不同的服务统一h提供一个统一的调用接口,作ؓ使用者来_我只要获得服务提供者给我的WSDLQ对服务的描qͼQ就够了Q我完全不知道服务器提供者提供的服务I竟是EJBlgQ还?NetlgQ还是什么CORBAlgQ还是其他的什么实玎ͼ我也不需要知道。Web Services最伟大的地方就在于通过l一的服务提供方式和调用方式Q实C整个Internet服务的共享,是一个非o人激动的技术领域。Web Services好像目前q没有什么很好的书籍Q但是可以通过在网l上面查资料的方式来学习?nbsp;
Java Learning PathQ四Q?nbsp;Ҏ?nbsp;
Java作ؓ一门编E语aQ最好的学习Ҏ是写代码。当你学习一个类以后Q你可以自己写个简单的例子E序来运行一下,看看有什么结果,然后再多调用几个cȝҎQ看看运行结果,q样非常直观的把cȝ学会了,而且记忆非常深刻。然后不应该满把代码调通,你应该想想看如果我不q样写,换个方式Q再试试行不行。记得哪个高q学习编E就是个破坏的过E,把书上的例子Q自己学习Documentation~写的例子在q行通过以后Q不断的试着用不同的Ҏ实现Q不断的试破坏代码的结构,看看它会有什么结果。通过q样的方式,你会很彻底的很精通的掌握Java?nbsp;
举个例子Q我们都~过Hello World
很多初学者不是很理解Z么mainҎ一定要q样来定义public static void main(String[] args)Q能不能不这样写Q包括我刚学习Java的时候也有这L疑问。想知道{案吗?很简单,你把main改个名字q行一下,看看报什么错误,然后Ҏ出错信息q行分析Q把main的public取掉Q在试试看,报什么错误;staticLq能不能q行Q不知道mainҎ是否一定要传一个String[]数组的,把String[]ҎQ改成int[]Q或者String试试看;不知道是否必dargs参数名称的,也可以把argsҎ别的名字Q看看运行结果如何?nbsp;
我当初学习Java的时候就是这样做的,把Hello WorldE序反复改了七八ơ,不断q行Q分析运行结果,最后就d明白Z么了mainҎ是这样定义的了?nbsp;
此外Q我对于staicQpublicQprivateQExceptionQtry{ }catch {}finally{}{等{等一开始都不是很懂Q都是把参考书上面的例子运行成功,然后开始破坏它Q不断的Ҏ自己心里面的疑问来重新改写程序,看看能不能运行,q行出来是个什么样子,是否可以得到预期的结果。这栯然比较费旉Q不q一个例子程序这样反复破坏几ơ之后。我对q个相关的知识彻底学通了。有时候甚x意写一些错误的代码来运行,看看能否得到预期的运行错误。这样对于编E的掌握是及其深ȝ?nbsp;
其中特别值得一提的是JDK有一个非常棒的调试功能,-verbose
java -verbose
javac -verbose 以及其它很多JDK工具都有q个选项
-verbose 可以昄在命令执行的q程中,JVM都依ơ加载哪里ClassQ通过q些宝贵的调试信息,可以帮助我们分析出JVM在执行的q程中都q了些什么?nbsp;
另外Q自己在学习q程中,写的很多的这U破坏例E,应该有意识的分门别类的保存下来,在工作中U篏的典型例E也应该定期整理Q日U月累,自己有了一个代码库了。遇到类似的问题Q到代码库里?nbsp;Copy & Paste QSearch & ReplaceQ就好了Q极大提高了开发速度。最理想的情冉|把一些通用的例E自己再抽象一层,形成一个通用的类库,装好。那么可复用性就更强了?nbsp;
所以我觉得其实不是特别需要例E的Q自己写的破坏例E就是最好的例子Q如果你实在对自己写的代码不攑ֿ的话Q我强烈推荐你看看JDK基础cd的Java源代码。在JDK安装目录下面会有一个src.zipQ解开来就可以完整的看到整个JDK基础cdQ也是rt.jar的Java源代码,你可以参考一下Sun是怎么写JavaE序的,规范是什么样子的。我自己在学习Java的类库的时候,当有些地方理解的不是很清楚的时候,或者想更加清晰的理解运作的l节的时候,往往会打开相应的类的源代码Q通过看源代码Q所有的问题都会一扫而空?nbsp;
Java Learning PathQ五Q资源篇
1?nbsp;http://java.sun.com/ (英文)
Sun的Java|站Q是一个应该经常去看的地方。不用多说?nbsp;
2?nbsp;http://www-900.ibm.com/developerWorks/cn/
IBM的developerWorks|站Q英语好的直接去英文ȝ点看。这里不但是一个极好的面向对象的分析设计网站,也是Web ServicesQJavaQLinux极好的网站。强烈推荐!Q!
3?nbsp;http://www.java-cn.com/ (中文)
JAVA中文站,目前国内资料最全、会员最多的JAVA技术网站,人气极高。有《JAVA电子书库》、《JAVA视频库?国内唯一)、《JAVA技术文摘库》、《JAVA源代码库》、《JAVA工具库》、《招聘求职广场》等主要栏目Q还有一些专家栏目。目前会员有5万多QVIP会员q?000人。无论是菜鸟q是老鸟Q都能在此网站中扑ֈ自己所需要的东东Q! 最强烈推荐Q!Q!Q!
4?nbsp;http://www.javaworld.com/ (英文)
关于Java很多新技术的讨论和新闅R想多了解Java的方斚w面的应用Q这里比较好?nbsp;
5?nbsp;http://dev2dev.bea.com.cn/index.jsp
BEA的开发者园圎ͼBEA作ؓ最重要的App Server厂商Q有很多独到的技术,在Weblogic上做开发的朋友不容错过?nbsp;
6?nbsp;http://www.huihoo.com/
灰狐动力|站Q一个专业的中间件网站,虽然不是专业的Java|站Q但是在J2EE企业应用技术方面有深厚的造诣?nbsp;
7?nbsp;http://www.theserverside.com/home/ (英文)
TheServerSide是一个著名的专门面向Java Server端应用的|站?nbsp;
8?nbsp;http://www.javaresearch.org/
Java研究l织Q有很多优秀的Java斚w的文章和教程Q特别是在JDO斚w的文章比较丰富?nbsp;
9?nbsp;http://www.cnjsp.org/
JSP技术网站,有相当多的Java斚w的文章和资源?nbsp;
10?nbsp;http://www.jdon.com/
Jdon论坛Q是一个个人性质的中文J2EE专业技术论坛,在众多的Java的中文论坛中QJdon一个是技术含量非帔RQ帖子质量非常好的论坛?nbsp;
11?nbsp;http://sourceforge.net/
SourgeForge是一个开放源代码软g的大本营Q其中也有非帔R怸富的Java的开放源代码的著名的软g?/P>