﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>语源科技BlogJava-赵建伟资源(资料均为转载)</title><link>http://www.blogjava.net/zjw-albert/</link><description /><language>zh-cn</language><lastBuildDate>Thu, 30 Apr 2026 09:58:13 GMT</lastBuildDate><pubDate>Thu, 30 Apr 2026 09:58:13 GMT</pubDate><ttl>60</ttl><item><title>oracle blob数据类型存储读取的小例子(转载)</title><link>http://www.blogjava.net/zjw-albert/archive/2007/10/27/156391.html</link><dc:creator>zjw_albert</dc:creator><author>zjw_albert</author><pubDate>Sat, 27 Oct 2007 12:33:00 GMT</pubDate><guid>http://www.blogjava.net/zjw-albert/archive/2007/10/27/156391.html</guid><wfw:comment>http://www.blogjava.net/zjw-albert/comments/156391.html</wfw:comment><comments>http://www.blogjava.net/zjw-albert/archive/2007/10/27/156391.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/zjw-albert/comments/commentRss/156391.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zjw-albert/services/trackbacks/156391.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: package&nbsp;com.hbky.bo;import&nbsp;java.io.BufferedInputStream;import&nbsp;java.io.BufferedOutputStream;import&nbsp;java.io.File;import&nbsp;java.io.FileInputStream;import&nbsp;java.io.F...&nbsp;&nbsp;<a href='http://www.blogjava.net/zjw-albert/archive/2007/10/27/156391.html'>阅读全文</a><img src ="http://www.blogjava.net/zjw-albert/aggbug/156391.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zjw-albert/" target="_blank">zjw_albert</a> 2007-10-27 20:33 <a href="http://www.blogjava.net/zjw-albert/archive/2007/10/27/156391.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>oracle 日期处理</title><link>http://www.blogjava.net/zjw-albert/archive/2007/07/24/132084.html</link><dc:creator>zjw_albert</dc:creator><author>zjw_albert</author><pubDate>Tue, 24 Jul 2007 08:43:00 GMT</pubDate><guid>http://www.blogjava.net/zjw-albert/archive/2007/07/24/132084.html</guid><wfw:comment>http://www.blogjava.net/zjw-albert/comments/132084.html</wfw:comment><comments>http://www.blogjava.net/zjw-albert/archive/2007/07/24/132084.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/zjw-albert/comments/commentRss/132084.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zjw-albert/services/trackbacks/132084.html</trackback:ping><description><![CDATA[create or replace function TF_ISSUE_DATE(ISSUE IN VARCHAR2,DATE_TYPE IN VARCHAR2) return DATE&nbsp; --参数DATE_TYPE 返回日期类型&nbsp; 0起始日期 1中止日期<br>is<br>&nbsp; V_RETURN DATE;<br>&nbsp; V_ISSUE VARCHAR2(20) :=ISSUE;<br>&nbsp; V_DATE_TYPE VARCHAR2(20) := DATE_TYPE;<br>&nbsp; V_ISSUE_TYPE VARCHAR2(20) :=SUBSTR(ISSUE,1,1);<br>begin<br>&nbsp; IF V_DATE_TYPE = '0' THEN<br>&nbsp;&nbsp;&nbsp; CASE<br>&nbsp;&nbsp;&nbsp; WHEN V_ISSUE_TYPE = '1'&nbsp; －－年<br>&nbsp;&nbsp;&nbsp; THEN V_RETURN := TO_DATE(SUBSTR(V_ISSUE,2,4)||'0101','YYYY-MM-DD');<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; WHEN V_ISSUE_TYPE = '2'&nbsp; －－季<br>&nbsp;&nbsp;&nbsp; THEN SELECT DECODE( SUBSTR(V_ISSUE,6,2),<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; '01',TO_DATE(SUBSTR(V_ISSUE,2,4)||'0101','YYYY-MM-DD'),<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; '02',TO_DATE(SUBSTR(V_ISSUE,2,4)||'0401','YYYY-MM-DD'),<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; '03',TO_DATE(SUBSTR(V_ISSUE,2,4)||'0701','YYYY-MM-DD'), <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; '04',TO_DATE(SUBSTR(V_ISSUE,2,4)||'1001','YYYY-MM-DD'),TO_DATE(SUBSTR(V_ISSUE,2,4)||'0101','YYYY-MM-DD'))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; INTO V_RETURN <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FROM DUAL;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; WHEN V_ISSUE_TYPE = '3' －－月<br>&nbsp;&nbsp;&nbsp; THEN V_RETURN := TO_DATE(SUBSTR(V_ISSUE,2,6)||'01','YYYY-MM-DD');<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; WHEN V_ISSUE_TYPE = '4' －－旬<br>&nbsp;&nbsp;&nbsp; THEN SELECT AA INTO V_RETURN FROM (<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SELECT aa ,ROWNUM BB<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FROM (<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SELECT (TO_DATE (SUBSTR(V_ISSUE,2,6)||'01', 'yyyy-mm-dd') + ROWNUM - 1) aa&nbsp; ,rownum cc<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FROM all_objects <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WHERE ROWNUM &lt; TO_DATE(TO_CHAR(last_day(TO_DATE (SUBSTR(V_ISSUE,2,6)||'01', 'yyyy-mm-dd')),'YYYYMMDD'),'YYYY-MM-DD') - TO_DATE (SUBSTR(V_ISSUE,2,6)||'01', 'yyyy-mm-dd') + 1) bb&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WHERE MOD (TO_CHAR (aa, 'dd'), 10) = 1 and to_char(aa,'dd') &lt;&gt; 31 )<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WHERE BB = TO_NUMBER(SUBSTR(V_ISSUE,8,2));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; WHEN V_ISSUE_TYPE = '5' －－周<br>&nbsp;&nbsp;&nbsp; THEN SELECT MONDAY INTO V_RETURN FROM (<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; select <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MONDAY.the_week,decode(sign(MONDAY.the_day-SUNDAY.the_day),-1,MONDAY.the_day,MONDAY.the_day-7) MONDAY,SUNDAY.the_day SUNDAY <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; from <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (select to_char(wwm,'WW') the_week,to_char(wwm,'D') the_daynum,wwm the_day <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; from (<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; select trunc(TO_DATE(SUBSTR(V_ISSUE,2,4)||'0101','YYYY-MM-DD'), 'MM')+rownum-1 as wwm <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; from user_objects <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; where rownum &lt; 366<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; where to_char(wwm,'D')=2 ) MONDAY,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (select to_char(wwm,'WW') the_week,to_char(wwm,'D') the_daynum,wwm the_day&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; from (<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; select trunc(TO_DATE(SUBSTR(V_ISSUE,2,4)||'0101','YYYY-MM-DD'), 'MM')+rownum-1 as wwm <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; from user_objects <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; where rownum &lt; 366<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; where to_char(wwm,'D')=1 ) SUNDAY<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; where MONDAY.the_week=SUNDAY.the_week)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WHERE THE_WEEK = SUBSTR(V_ISSUE,6,2);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; WHEN V_ISSUE_TYPE = '6' －－日<br>&nbsp;&nbsp;&nbsp; THEN V_RETURN := TO_DATE(SUBSTR(V_ISSUE,2,8),'YYYY-MM-DD');<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; ELSE<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; V_RETURN := TO_DATE(SUBSTR(V_ISSUE,2,4)||'0101','YYYY-MM-DD');<br>&nbsp;&nbsp;&nbsp; END CASE;<br>&nbsp; ELSE<br>&nbsp;&nbsp;&nbsp; CASE<br>&nbsp;&nbsp;&nbsp; WHEN V_ISSUE_TYPE = '1'<br>&nbsp;&nbsp;&nbsp; THEN V_RETURN := TO_DATE(SUBSTR(V_ISSUE,2,4)||'1231','YYYY-MM-DD');<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; WHEN V_ISSUE_TYPE = '2'<br>&nbsp;&nbsp;&nbsp; THEN SELECT DECODE( SUBSTR(V_ISSUE,6,2),<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; '01',TO_DATE(SUBSTR(V_ISSUE,2,4)||'0331','YYYY-MM-DD'),<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; '02',TO_DATE(SUBSTR(V_ISSUE,2,4)||'0630','YYYY-MM-DD'),<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; '03',TO_DATE(SUBSTR(V_ISSUE,2,4)||'0930','YYYY-MM-DD'), <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; '04',TO_DATE(SUBSTR(V_ISSUE,2,4)||'1231','YYYY-MM-DD'),<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TO_DATE(SUBSTR(V_ISSUE,2,4)||'0101','YYYY-MM-DD'))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; INTO V_RETURN <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FROM DUAL;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; WHEN V_ISSUE_TYPE = '3'<br>&nbsp;&nbsp;&nbsp; THEN V_RETURN := TO_DATE(TO_CHAR(last_day(TO_DATE(SUBSTR(V_ISSUE,2,6)||'01','YYYY-MM-DD')),'YYYYMMDD'),'YYYY-MM-DD');<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; WHEN V_ISSUE_TYPE = '4'<br>&nbsp;&nbsp;&nbsp; THEN SELECT DECODE( SUBSTR(V_ISSUE,8,2),<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; '01',TO_DATE(SUBSTR(V_ISSUE,2,6)||'10','YYYY-MM-DD'),<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; '02',TO_DATE(SUBSTR(V_ISSUE,2,6)||'20','YYYY-MM-DD'),<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; '03',TO_DATE(TO_CHAR(last_day(TO_DATE(SUBSTR(V_ISSUE,2,6)||'01','YYYY-MM-DD')),'YYYYMMDD'),'YYYY-MM-DD'),<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TO_DATE(TO_CHAR(last_day(TO_DATE(SUBSTR(V_ISSUE,2,6)||'01','YYYY-MM-DD')),'YYYYMMDD'),'YYYY-MM-DD'))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; INTO V_RETURN <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FROM DUAL;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; WHEN V_ISSUE_TYPE = '5'<br>&nbsp;&nbsp;&nbsp; THEN SELECT SUNDAY INTO V_RETURN FROM (<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; select <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MONDAY.the_week,decode(sign(MONDAY.the_day-SUNDAY.the_day),-1,MONDAY.the_day,MONDAY.the_day-7) MONDAY,SUNDAY.the_day SUNDAY <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; from <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (select to_char(wwm,'WW') the_week,to_char(wwm,'D') the_daynum,wwm the_day <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; from (<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; select trunc(TO_DATE(SUBSTR(V_ISSUE,2,4)||'0101','YYYY-MM-DD'), 'MM')+rownum-1 as wwm <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; from user_objects <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; where rownum &lt; 366<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; where to_char(wwm,'D')=2 ) MONDAY,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (select to_char(wwm,'WW') the_week,to_char(wwm,'D') the_daynum,wwm the_day&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; from (<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; select trunc(TO_DATE(SUBSTR(V_ISSUE,2,4)||'0101','YYYY-MM-DD'), 'MM')+rownum-1 as wwm <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; from user_objects <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; where rownum &lt; 366<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; where to_char(wwm,'D')=1 ) SUNDAY<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; where MONDAY.the_week=SUNDAY.the_week)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WHERE THE_WEEK = SUBSTR(V_ISSUE,6,2);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; WHEN V_ISSUE_TYPE = '6'<br>&nbsp;&nbsp;&nbsp; THEN V_RETURN := TO_DATE(SUBSTR(V_ISSUE,2,8),'YYYY-MM-DD');<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; ELSE<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; V_RETURN := TO_DATE(SUBSTR(V_ISSUE,2,4)||'0101','YYYY-MM-DD');<br>&nbsp;&nbsp;&nbsp; END CASE;<br>&nbsp; END IF;<br>&nbsp; return(V_RETURN);<br>end TF_ISSUE_DATE;<br>
<img src ="http://www.blogjava.net/zjw-albert/aggbug/132084.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zjw-albert/" target="_blank">zjw_albert</a> 2007-07-24 16:43 <a href="http://www.blogjava.net/zjw-albert/archive/2007/07/24/132084.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>转：Oracle日期函数</title><link>http://www.blogjava.net/zjw-albert/archive/2007/04/04/108427.html</link><dc:creator>zjw_albert</dc:creator><author>zjw_albert</author><pubDate>Wed, 04 Apr 2007 06:39:00 GMT</pubDate><guid>http://www.blogjava.net/zjw-albert/archive/2007/04/04/108427.html</guid><wfw:comment>http://www.blogjava.net/zjw-albert/comments/108427.html</wfw:comment><comments>http://www.blogjava.net/zjw-albert/archive/2007/04/04/108427.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/zjw-albert/comments/commentRss/108427.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zjw-albert/services/trackbacks/108427.html</trackback:ping><description><![CDATA[TO_DATE格式 <br>　　Day: <br>　　dd number 12 <br>　　dy abbreviated fri <br>　　day spelled out friday <br>　　ddspth spelled out, ordinal twelfth <br>　　Month: <br>　　mm number 03 <br>　　mon abbreviated mar <br>　　month spelled out march <br>　　Year: <br>　　yy two digits 98 <br>　　yyyy four digits 1998 <br>　　<br>　　24小时格式下时间范围为： 0:00:00 - 23:59:59.... <br>　　12小时格式下时间范围为： 1:00:00 - 12:59:59 .... <br>　　1. <br>　　日期和字符转换函数用法（to_date,to_char） <br>　　<br>　　2. <br>　　select to_char( to_date(222,'J'),'Jsp') from dual <br>　　<br>　　显示Two Hundred Twenty-Two <br>　　<br>　　3. <br>　　求某天是星期几 <br>　　select to_char(to_date('2002-08-26','yyyy-mm-dd'),'day') from dual; <br>　　星期一 <br>　　select to_char(to_date('2002-08-26','yyyy-mm-dd'),'day','NLS_DATE_LANGUAGE = American') from dual; <br>　　monday <br>　　设置日期语言 <br>　　ALTER SESSION SET NLS_DATE_LANGUAGE='AMERICAN'; <br>　　也可以这样 <br>　　TO_DATE ('2002-08-26', 'YYYY-mm-dd', 'NLS_DATE_LANGUAGE = American') <br>　　<br>　　4. <br>　　两个日期间的天数 <br>　　select floor(sysdate - to_date('20020405','yyyymmdd')) from dual; <br>　　<br>　　5. 时间为null的用法 <br>　　select id, active_date from table1 <br>　　UNION <br>　　select 1, TO_DATE(null) from dual; <br>　　<br>　　注意要用TO_DATE(null) <br>　　<br>　　6. <br>　　a_date between to_date('20011201','yyyymmdd') and to_date('20011231','yyyymmdd') <br>　　那么12月31号中午12点之后和12月1号的12点之前是不包含在这个范围之内的。 <br>　　所以，当时间需要精确的时候，觉得to_char还是必要的 <br>　　7. 日期格式冲突问题 <br>　　输入的格式要看你安装的ORACLE字符集的类型, 比如: US7ASCII, date格式的类型就是: '01-Jan-01' <br>　　alter system set NLS_DATE_LANGUAGE = American <br>　　alter session set NLS_DATE_LANGUAGE = American <br>　　或者在to_date中写 <br>　　select to_char(to_date('2002-08-26','yyyy-mm-dd'),'day','NLS_DATE_LANGUAGE = American') from dual; <br>　　注意我这只是举了NLS_DATE_LANGUAGE，当然还有很多， <br>　　可查看 <br>　　select * from nls_session_parameters <br>　　select * from V$NLS_PARAMETERS <br>　　<br>　　8. <br>　　select count(*) <br>　　from ( select rownum-1 rnum <br>　　from all_objects <br>　　where rownum &lt;= to_date('2002-02-28','yyyy-mm-dd') - to_date('2002- <br>　　02-01','yyyy-mm-dd')+1 <br>　　) <br>　　where to_char( to_date('2002-02-01','yyyy-mm-dd')+rnum-1, 'D' ) <br>　　not <br>　　in ( '1', '7' ) <br>　　<br>　　查找2002-02-28至2002-02-01间除星期一和七的天数 <br>　　在前后分别调用DBMS_UTILITY.GET_TIME, 让后将结果相减(得到的是1/100秒, 而不是毫秒). <br>　　<br>　　9. <br>　　select months_between(to_date('01-31-1999','MM-DD-YYYY'), <br>　　to_date('12-31-1998','MM-DD-YYYY')) "MONTHS" FROM DUAL; <br>　　1 <br>　　<br>　　select months_between(to_date('02-01-1999','MM-DD-YYYY'), <br>　　to_date('12-31-1998','MM-DD-YYYY')) "MONTHS" FROM DUAL; <br>　　<br>　　1.03225806451613 <br>　　10. Next_day的用法 <br>　　Next_day(date, day) <br>　　<br>　　Monday-Sunday, for format code DAY <br>　　Mon-Sun, for format code DY <br>　　1-7, for format code D <br>　　<br>　　11 <br>　　select to_char(sysdate,'hh:mi:ss') TIME from all_objects <br>　　注意：第一条记录的TIME 与最后一行是一样的 <br>　　可以建立一个函数来处理这个问题 <br>　　create or replace function sys_date return date is <br>　　begin <br>　　return sysdate; <br>　　end; <br>　　<br>　　select to_char(sys_date,'hh:mi:ss') from all_objects; <br>　　12. <br>　　获得小时数 <br>　　<br>　　SELECT EXTRACT(HOUR FROM TIMESTAMP '2001-02-16 2:38:40') from offer <br>　　SQL&gt; select sysdate ,to_char(sysdate,'hh') from dual; <br>　　<br>　　SYSDATE TO_CHAR(SYSDATE,'HH') <br>　　-------------------- --------------------- <br>　　2003-10-13 19:35:21 07 <br>　　<br>　　SQL&gt; select sysdate ,to_char(sysdate,'hh24') from dual; <br>　　<br>　　SYSDATE TO_CHAR(SYSDATE,'HH24') <br>　　-------------------- ----------------------- <br>　　2003-10-13 19:35:21 19 <br>　　<br>　　获取年月日与此类似 <br>　　13. <br>　　年月日的处理 <br>　　select older_date, <br>　　newer_date, <br>　　years, <br>　　months, <br>　　abs( <br>　　trunc( <br>　　newer_date- <br>　　add_months( older_date,years*12+months ) <br>　　) <br>　　) days <br>　　from ( select <br>　　trunc(months_between( newer_date, older_date )/12) YEARS, <br>　　mod(trunc(months_between( newer_date, older_date )), <br>　　12 ) MONTHS, <br>　　newer_date, <br>　　older_date <br>　　from ( select hiredate older_date, <br>　　add_months(hiredate,rownum)+rownum newer_date <br>　　from emp ) <br>　　) <br>　　<br>　　14. <br>　　处理月份天数不定的办法 <br>　　select to_char(add_months(last_day(sysdate) +1, -2), 'yyyymmdd'),last_day(sysdate) from dual <br>　　<br>　　16. <br>　　找出今年的天数 <br>　　select add_months(trunc(sysdate,'year'), 12) - trunc(sysdate,'year') from dual <br>　　<br>　　闰年的处理方法 <br>　　to_char( last_day( to_date('02' || :year,'mmyyyy') ), 'dd' ) <br>　　如果是28就不是闰年 <br>　　<br>　　17. <br>　　yyyy与rrrr的区别 <br>　　'YYYY99 TO_C <br>　　------- ---- <br>　　yyyy 99 0099 <br>　　rrrr 99 1999 <br>　　yyyy 01 0001 <br>　　rrrr 01 2001 <br>　　<br>　　18.不同时区的处理 <br>　　select to_char( NEW_TIME( sysdate, 'GMT','EST'), 'dd/mm/yyyy hh:mi:ss') ,sysdate <br>　　from dual; <br>　　<br>　　19. <br>　　5秒钟一个间隔 <br>　　Select TO_DATE(FLOOR(TO_CHAR(sysdate,'SSSSS')/300) * 300,'SSSSS') ,TO_CHAR(sysdate,'SSSSS') <br>　　from dual <br>　　<br>　　2002-11-1 9:55:00 35786 <br>　　SSSSS表示5位秒数 <br>　　<br>　　20. <br>　　一年的第几天 <br>　　select TO_CHAR(SYSDATE,'DDD'),sysdate from dual <br>　　310 2002-11-6 10:03:51 <br>　　<br>　　21.计算小时,分,秒,毫秒 <br>　　select <br>　　Days, <br>　　A, <br>　　TRUNC(A*24) Hours, <br>　　TRUNC(A*24*60 - 60*TRUNC(A*24)) Minutes, <br>　　TRUNC(A*24*60*60 - 60*TRUNC(A*24*60)) Seconds, <br>　　TRUNC(A*24*60*60*100 - 100*TRUNC(A*24*60*60)) mSeconds <br>　　from <br>　　( <br>　　select <br>　　trunc(sysdate) Days, <br>　　sysdate - trunc(sysdate) A <br>　　from dual <br>　　) <br>　　<br>　　<br>　　<br>　　select * from tabname <br>　　order by decode(mode,'FIFO',1,-1)*to_char(rq,'yyyymmddhh24miss'); <br>　　<br>　　// <br>　　floor((date2-date1) /365) 作为年 <br>　　floor((date2-date1, 365) /30) 作为月 <br>　　mod(mod(date2-date1, 365), 30)作为日. <br>　　23.next_day函数 <br>　　next_day(sysdate,6)是从当前开始下一个星期五。后面的数字是从星期日开始算起。 <br>　　1 2 3 4 5 6 7 <br>　　日 一 二 三 四 五 六<br><br><br>
<p><font size=3>add_months(d,n)&nbsp;&nbsp;日期d加n个月<br>last_day(d)&nbsp;&nbsp;包含d的月份的最后一天的日期<br>month_between(d,e)&nbsp;日期d与e之间的月份数，e先于d<br>new_time(d,a,b)&nbsp;&nbsp;a时区的日期和时间d在b时区的日期和时间<br>next_day(d,day)&nbsp;&nbsp;比日期d晚，由day指定的周几的日期<br>sysdate&nbsp;&nbsp;当前的系统日期和时间<br>greatest(d1,d2,...dn)&nbsp;给出的日期列表中最后的日期<br>least(d1,k2,...dn)&nbsp;给出的日期列表中最早的日期<br>to_char(d&nbsp;[,fmt])&nbsp;日期d按fmt指定的格式转变成字符串<br>to_date(st&nbsp;[,fmt])&nbsp;字符串st按fmt指定的格式转成日期值，若fmt忽略，st要用缺省格式<br>round(d&nbsp;[,fmt])&nbsp;&nbsp;日期d按fmt指定格式舍入到最近的日期<br>trunc(d&nbsp;[,fmt])&nbsp;&nbsp;日期d按fmt指定格式截断到最近的日期<br></font></p>
<p><font size=3>－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－<br>格式代码　&nbsp;&nbsp;&nbsp;&nbsp;说明&nbsp;&nbsp;&nbsp;举例或可取值的范围<br>－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－<br>DD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;该月某一天&nbsp;&nbsp;1－3<br>DY&nbsp;　　　三个大写字母表示的周几&nbsp;SUN，...SAT<br>DAY&nbsp;　　　完整的周几，大写英文&nbsp;SUNDAY，...SATURDAY<br>MM&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;月份&nbsp;&nbsp;&nbsp;1－12<br>MON　　　　　&nbsp;三个大写字母表示的月份&nbsp;JAN，...DEC<br>MONTH&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;完整&nbsp;&nbsp;&nbsp;JANUARY,...DECEMBER<br>RM&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;月份的罗马数字&nbsp;&nbsp;I,...XII<br>YY或YYYY&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;两位，四位数字年<br>HH:MI:SS　　　时：分：秒<br>HH12或HH24　　以12小时或24小时显示<br>MI　　　　　　分<br>SS　　　　　　秒<br>AM或PM　　　　上下午指示符<br>SP　　　　　　后缀SP要求拼写出任何数值字段<br>TH　　　　　　后缀TH表示添加的数字是序数　4th,1st<br>FM&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;前缀对月或日或年值，禁止填充&nbsp;</font></p>
<p><font size=3>－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－<br>SQL&gt; select to_char(sysdate,'yyyy-mm-dd hh:mi:ss am') from dual;</font></p>
<p>&nbsp;</p>
<p>在oracle中有很多关于日期的函数，如:</p>
<p>　　1、add_months()用于从一个日期值增加或减少一些月份</p>
<p>　　date_value:=add_months(date_value,number_of_months)</p>
<p>　　例:</p>
<p>　　SQL&gt; select add_months(sysdate,12) "Next Year" from dual;</p>
<p>　　Next Year</p>
<p>　　----------</p>
<p>　　13-11月-04</p>
<p>　　SQL&gt; select add_months(sysdate,112) "Last Year" from dual;</p>
<p>　　Last Year</p>
<p>　　----------</p>
<p>　　13-3月 -13</p>
<p>　　SQL&gt;</p>
<p>　　2、current_date()返回当前会放时区中的当前日期</p>
<p>　　date_value:=current_date</p>
<p>　　SQL&gt; column sessiontimezone for a15</p>
<p>　　SQL&gt; select sessiontimezone,current_date from dual;</p>
<p>　　SESSIONTIMEZONE CURRENT_DA</p>
<p>　　--------------- ----------</p>
<p>　　+08:00 13-11月-03</p>
<p>　　SQL&gt; alter session set <a class=bluekey href="http://www.yesky.com/key/115/170115.html" target=_blank><u><font color=#0000ff>time</font></u></a>_zone='-11:00'</p>
<p>　　2 /</p>
<p>　　会话已更改。</p>
<p>　　SQL&gt; select sessiontimezone,current_timestamp from dual;</p>
<p>　　SESSIONTIMEZONE CURRENT_TIMESTAMP</p>
<p>　　--------------- ------------------------------------</p>
<p>　　-11:00 12-11月-03 04.59.13.668000 下午 -11:</p>
<p>　　00</p>
<p>　　SQL&gt;</p>
<p>　　3、current_timestamp()以timestamp with time zone数据类型返回当前会放时区中的当前日期</p>
<p>　　timestamp_with_time_zone_value:=current_timestamp([timestamp_precision])</p>
<p>　　SQL&gt; column sessiontimezone for a15</p>
<p>　　SQL&gt; column current_timestamp format a36</p>
<p>　　SQL&gt; select sessiontimezone,current_timestamp from dual;</p>
<p>　　SESSIONTIMEZONE CURRENT_TIMESTAMP</p>
<p>　　--------------- ------------------------------------</p>
<p>　　+08:00 13-11月-03 11.56.28.160000 上午 +08:</p>
<p>　　00</p>
<p>　　SQL&gt; alter session set time_zone='-11:00'</p>
<p>　　2 /</p>
<p>　　会话已更改。</p>
<p>　　SQL&gt; select sessiontimezone,current_timestamp from dual;</p>
<p>　　SESSIONTIMEZONE CURRENT_TIMESTAMP</p>
<p>　　--------------- ------------------------------------</p>
<p>　　-11:00 12-11月-03 04.58.00.243000 下午 -11:</p>
<p>　　00</p>
<p>　　SQL&gt;</p>
<p>　　4、dbtimezone()返回时区</p>
<p>　　varchar_value:=dbtimezone</p>
<p>　　SQL&gt; select dbtimezone from dual;</p>
<p>　　DBTIME</p>
<p>　　------</p>
<p>　　-07:00</p>
<p>　　SQL&gt;</p>
<p>　　5、extract()找出日期或间隔值的字段值</p>
<p>　　date_value:=extract(date_field from [datetime_value|interval_value])</p>
<p>　　SQL&gt; select extract(month from sysdate) "This Month" from dual;</p>
<p>　　This Month</p>
<p>　　----------</p>
<p>　　11</p>
<p>　　SQL&gt; select extract(year from add_months(sysdate,36)) "3 Years Out" from dual;</p>
<p>　　3 Years Out</p>
<p>　　-----------</p>
<p>　　2006</p>
<p>　　SQL&gt;</p>
<p>　　6、last_day()返回包含了日期参数的月份的最后一天的日期</p>
<p>　　date_value:=last_day(date_value)</p>
<p>　　SQL&gt; select last_day(date'2000-02-01') "<a class=bluekey href="http://www.yesky.com/key/4569/169569.html" target=_blank><u><font color=#0000ff>Leap</font></u></a> Yr?" from dual;</p>
<p>　　Leap Yr?</p>
<p>　　----------</p>
<p>　　29-2月 -00</p>
<p>　　SQL&gt; select last_day(sysdate) "Last day of this month" from dual;</p>
<p>　　Last day o</p>
<p>　　----------</p>
<p>　　30-11月-03</p>
<p>　　SQL&gt;</p>
<p>　　7、localtimestamp()返回会话中的日期和时间</p>
<p>　　timestamp_value:=localtimestamp</p>
<p>　　SQL&gt; column localtimestamp format a28</p>
<p>　　SQL&gt; select localtimestamp from dual;</p>
<p>　　LOCALTIMESTAMP</p>
<p>　　----------------------------</p>
<p>　　13-11月-03 12.09.15.433000</p>
<p>　　下午</p>
<p>　　SQL&gt; select localtimestamp,current_timestamp from dual;</p>
<p>　　LOCALTIMESTAMP CURRENT_TIMESTAMP</p>
<p>　　---------------------------- ------------------------------------</p>
<p>　　13-11月-03 12.09.31.006000 13-11月-03 12.09.31.006000 下午 +08:</p>
<p>　　下午 00</p>
<p>　　SQL&gt; alter session set time_zone='-11:00';</p>
<p>　　会话已更改。</p>
<p>　　SQL&gt; select localtimestamp,to_char(sysdate,'DD-MM-YYYY HH:<a class=bluekey href="http://www.yesky.com/key/4602/169602.html" target=_blank><u><font color=#0000ff>MI</font></u></a>:SS AM') "SYSDATE" from dual;</p>
<p>　　LOCALTIMESTAMP SYSDATE</p>
<p>　　---------------------------- ------------------------</p>
<p>　　12-11月-03 05.11.31.259000 13-11-2003 12:11:31 下午</p>
<p>　　下午</p>
<p>　　SQL&gt;</p>
<p>　　8、months_between()判断两个日期之间的月份数量</p>
<p>　　number_value:=months_between(date_value,date_value)</p>
<p>　　SQL&gt; select months_between(sysdate,date'1971-05-18') from dual;</p>
<p>　　MONTHS_BETWEEN(SYSDATE,DATE'1971-05-18')</p>
<p>　　----------------------------------------</p>
<p>　　389.855143</p>
<p>　　SQL&gt; select months_between(sysdate,date'2001-01-01') from dual;</p>
<p>　　MONTHS_BETWEEN(SYSDATE,DATE'2001-01-01')</p>
<p>　　----------------------------------------</p>
<p>　　34.4035409</p>
<p>　　SQL&gt;</p>
<p>　　9、next_day()给定一个日期值，返回由第二个参数指出的日子第一次出现在的日期值(应返回相应日子的名称字符串)</p>
<p>　　说明:</p>
<p>　　单行日期函数</p>
<p>　　单行日期函数操作data数据类型，绝大多数都有data数据类型的参数，绝大多数返回的也是data数据类型的值。</p>
<p>　　add_months(,)</p>
<p>　　返回日期d加上i个月后的结果。i可以使任意整数。如果i是一个小数，那么数据库将隐式的他转换成整数，将会截去小数点后面的部分。</p>
<p>　　last_day()</p>
<p>　　函数返回包含日期d的月份的最后一天</p>
<p>　　months_between(,)</p>
<p>　　返回d1和d2之间月的数目,如果d1和d2的日的日期都相同，或者都使该月的最后一天，那么将返回一个整数，否则会返回的结果将包含一个分数。</p>
<p>　　new_time(,,)</p>
<p>　　d1是一个日期数据类型，当时区tz1中的日期和时间是d时，返回时区tz2中的日期和时间。tz1和tz2时字符串。</p>
<p>　　next_day(,)</p>
<p>　　返回日期d后由dow给出的条件的第一天，dow使用当前会话中给出的语言指定了一周中的某一天，返回的时间分量与d的时间分量相同。</p>
<p>　　select next_day(''01-jan-2000'',''monday'') "1st monday",next_day(''01-nov-2004'',''tuesday'')+7 "2nd tuesday") from dual;1st monday 2nd tuesday03-jan-2000 09-nov-2004</p>
<p>　　round([,])</p>
<p>　　将日期d按照fmt指定的格式舍入，fmt为字符串。</p>
<p>　　syadate</p>
<p>　　函数没有参数，返回当前日期和时间。</p>
<p>　　trunc([,])</p>
<p>　　返回由fmt指定的单位的日期d.</p>
<p>　　单行转换函数</p>
<p>　　单行转换函数用于操作多数据类型，在数据类型之间进行转换。</p>
<p>　　chartorwid()</p>
<p>　　c 使一个字符串，函数将c转换为rwid数据类型。</p>
<p>　　select test_id from test_case where rowid=chartorwid(''aaaa0saacaaaaliaaa'')</p>
<p>　　convert(,[,])</p>
<p>　　c尾字符串，dset、sset是两个<a class=bluekey href="http://www.yesky.com/key/3460/198460.html" target=_blank><u><font color=#0000ff>字符集</font></u></a>，函数将字符串c由sset字符集转换为dset字符集，sset的缺省设置为数据库的字符集。</p>
<p>　　hextoraw()</p>
<p>　　x为16进制的字符串，函数将16进制的x转换为raw数据类型。</p>
<p>　　rawtohex()</p>
<p>　　x是raw数据类型字符串，函数将raw数据类转换为16进制的数据类型。</p>
<p>　　rowidtochar()</p>
<p>　　函数将rowid数据类型转换为char数据类型。</p>
<p>　　to_char([[,)</p>
<p>　　x是一个data或number数据类型，函数将x转换成fmt指定格式的char数据类型，如果x为日期nlsparm=nls_date_language 控制返回的月份和日份所使用的语言。如果x为数字nlsparm=nls_numeric_characters 用来指定小数位和千分位的分隔符，以及货币符号。</p>
<p>　　nls_numeric_characters ="dg", nls_currency="string"</p>
<p>　　to_date([,[,)</p>
<p>　　c表示字符串，fmt表示一种特殊格式的字符串。返回按照fmt格式显示的c,nlsparm表示使用的语言。函数将字符串c转换成date数据类型。</p>
<p>　　to_multi_byte()</p>
<p>　　c表示一个字符串，函数将c的担子截字符转换成多字节字符。</p>
<p>　　to_number([,[,)</p>
<p>　　c表示字符串，fmt表示一个特殊格式的字符串，函数返回值按照fmt指定的格式显示。nlsparm表示语言，函数将返回c代表的数字。</p>
<p>　　to_<a class=bluekey href="http://www.yesky.com/key/2017/162017.html" target=_blank><u><font color=#0000ff>single</font></u></a>_byte()</p>
<p>　　将字符串c中得多字节字符转化成等价的单字节字符。该函数仅当数据库字符集同时包含单字节和多字节字符时才使用。Oracle关于时间/日期的操作</p>
<p>　　1.日期时间间隔操作</p>
<p>　　当前时间减去7分钟的时间</p>
<p>　　select sysdate,sysdate - interval '7' MINUTE from dual</p>
<p>　　当前时间减去7小时的时间</p>
<p>　　select sysdate - interval '7' hour from dual</p>
<p>　　当前时间减去7天的时间</p>
<p>　　select sysdate - interval '7' day from dual</p>
<p>　　当前时间减去7月的时间</p>
<p>　　select sysdate,sysdate - interval '7' month from dual</p>
<p>　　当前时间减去7年的时间</p>
<p>　　select sysdate,sysdate - interval '7' year from dual</p>
<p>　　时间间隔乘以一个数字</p>
<p>　　select sysdate,sysdate - 8 *interval '2' hour from dual</p>
<p>　　2.日期到字符操作</p>
<p>　　select sysdate,to_char(sysdate,'yyyy-mm-dd hh24:mi:ss') from dual</p>
<p>　　select sysdate,to_char(sysdate,'yyyy-mm-dd hh:mi:ss') from dual</p>
<p>　　select sysdate,to_char(sysdate,'yyyy-ddd hh:mi:ss') from dual</p>
<p>　　select sysdate,to_char(sysdate,'yyyy-mm iw-d hh:mi:ss') from dual</p>
<p>　　参考oracle的相关关文档(ORACLE901DOC/SERVER.901/A90125/SQL_ELEMENTS4.HTM#48515)</p>
<p>　　3. 字符到日期操作</p>
<p>　　select to_date('2003-10-17 21:15:37','yyyy-mm-dd hh24:mi:ss') from dual</p>
<p>　　具体用法和上面的to_char差不多。</p>
<p>　　4. trunk/ ROUND函数的使用</p>
<p>　　select trunc(sysdate ,'YEAR') from dual</p>
<p>　　select trunc(sysdate ) from dual</p>
<p>　　select to_char(trunc(sysdate ,'YYYY'),'YYYY') from dual</p>
<p>　　5.oracle有毫秒级的数据类型</p>
<p>　　--返回当前时间 年月日小时分秒毫秒</p>
<p>　　select to_char(current_timestamp(5),'DD-MON-YYYY HH24:MI:SSxFF') from dual;</p>
<p>　　--返回当前 时间的秒毫秒，可以指定秒后面的精度(最大=9)</p>
<p>　　select to_char(current_timestamp(9),'MI:SSxFF') from dual;</p>
<p>　　6.计算程序运行的时间(ms)</p>
<p>　　declare</p>
<p>　　type rc is ref cursor;</p>
<p>　　l_rc rc;</p>
<p>　　l_dummy all_objects.object_name%type;</p>
<p>　　l_start number default dbms_utility.get_time;</p>
<p>　　begin</p>
<p>　　for I in 1 .. 1000</p>
<p>　　loop</p>
<p>　　open l_rc for</p>
<p>　　'select object_name from all_objects '||</p>
<p>　　'where object_id = ' || i;</p>
<p>　　fetch l_rc into l_dummy;</p>
<p>　　close l_rc;</p>
<p>　　end loop;</p>
<p>　　dbms_output.put_line</p>
<p>　　( round( (dbms_utility.get_time-l_start)/100, 2 ) ||</p>
<p>　　' seconds...' );</p>
<p>　　end;</p>
<p>&nbsp;<br></p>
<img src ="http://www.blogjava.net/zjw-albert/aggbug/108427.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zjw-albert/" target="_blank">zjw_albert</a> 2007-04-04 14:39 <a href="http://www.blogjava.net/zjw-albert/archive/2007/04/04/108427.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>J2ME 游戏程序开发实例精讲详解（转载）</title><link>http://www.blogjava.net/zjw-albert/archive/2006/07/07/57152.html</link><dc:creator>zjw_albert</dc:creator><author>zjw_albert</author><pubDate>Fri, 07 Jul 2006 08:15:00 GMT</pubDate><guid>http://www.blogjava.net/zjw-albert/archive/2006/07/07/57152.html</guid><wfw:comment>http://www.blogjava.net/zjw-albert/comments/57152.html</wfw:comment><comments>http://www.blogjava.net/zjw-albert/archive/2006/07/07/57152.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/zjw-albert/comments/commentRss/57152.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zjw-albert/services/trackbacks/57152.html</trackback:ping><description><![CDATA[
		<p>一、序言</p>
		<p>昨天在网上闲逛，发现一篇讲解用delphi实现华容道游戏的文章，颇受启发．于是，产生了将华容道游戏移植到手机中去的冲动．现在手机游戏琳琅满目，不一而足，华容道的实现版本也很多．正巧不久前笔者对J2ME下了一番功夫，正想借这个机会小试牛刀。选用J2ME的原因还有一个就是目前Java开发大行其到，无线增殖业务迅猛发展，J2ME的应用日渐活跃起来，也希望我的这篇文章能够为J2ME知识的普及和开发团队的壮大推波助澜。由于长期受ISO规范的影响，这次小试牛刀我也打算遵照软件工程的要求，并采取瀑布式的开发模式来规划项目，也希望借此机会向各位没有机会参与正式项目开发的读者介绍一下软件开发的流程。</p>
		<p>这里我们先定义项目组的人员体制(其实只有我一个人)：技术调研、需求分析、概要设计、详细设计、编码、测试均有笔者一人担任；美工这里我找了个捷径，盗用网上现成的图片，然后用ACDSee把它由BMP转换成PNG格式(我出于讲座的目的，未做商业应用，应该不算侵权吧)；至于发布工作，由于缺少OTA服务器，此项工作不做(但是我会介绍这步如何做)。</p>
		<p>接下来，我们规划一下项目实现的时间表，以我个人经验，设想如下：技术调研用2天(这部分解决项目的可行性和重大技术问题，时间会长一些)，需求分析用半天(毕竟有现成的东东可以参照，只要理清思路就行了，况且还有很多以前用过的设计模式和写好的代码)，概要设计再用半天(有了需求，概要只不够是照方抓药)，详细设计要用2天(这一步要把所有的问题想清楚，还要尽可能的准确描述出来)，编码用2天(其实1天就够了，技术已经不是问题，多计划出一天来应付突发事件)，测试用2天(测试应该至少占全部项目的四分之一，不过这个项目只是一个Demo，也太简单了)，发布也要用上半天(尽管我们不去实际发布它，但是还要花点时间搞清楚应该如何做)，最后就是项目总结和开庆功会(时间待定)。</p>
		<p>二、利其器</p>
		<p>“公欲善其事，必先利其器”，做项目之前第一步是前期调研．我们要做的华容道这个东东随处可见，我们要调研的是两个方面：</p>
		<p>1. 游戏的内容：游戏本身很简单，就是有几个格子，曹操占据其中一个较大的格子，然后被几个格子包围，这些格子形状不一定相同，但是挡住了曹操移动的方向．游戏者需要挪动这些格子最终把曹操移动到一个指定的位置才算是过关．更具体的分析我们放在后面需求分析和概要设计中讨论。</p>
		<p>2. 技术储备：谈到技术，这里简单介绍一下J2ME.Java有三个版本，分别是J2ME（微型版）.J2SE（标准版）.J2EE（企业版）．J2ME是一个标准，采用３层结构设计．最低层是配置层（Configuration）也就是设备层，其上是简表层（Profile）,再上是应用层（Application）.MIDP就是移动信息设备简表，目前主流手机支持MIDP1.0，最新的是MIDP2.0,它比前一个版本增加了对游戏的支持，在javax.microedition.lcdui.game包中提供了一些类来处理游戏中的技术，比如我们后面会用到的Sprite类，它是用来翻转图片的.权衡再三，笔者决定使用MIDP2.0来做开发．首先需要安装一个J2ME的模拟器，我们就用Sun公司的WTK2.0，我觉得Sun的东西最权威．当然你也可以使用Nokia.Siemens或是Motolora等其他模拟器，但是他们的JDK不尽相同，写出来的程序移植是比较麻烦的．</p>
		<p>Sun公司的WTK2.0可以到搜索引擎寻找下载，当然要想成功下载的前提是你要先注册成为Sun的会员（其实这样对你是有好处的）．当下来之后就是按照提示一步一步的安装．安装好了之后，我们用一个"Hello World"程序开始你的J2ME之旅．我们启动WTK2.0工具集中的KToolBar，然后点击New Project按钮，在弹出的输入框中输入Project Name为HelloWorld,MIDlet Class Name为Hello,然后点击Create Project，开始生成项目，工具会弹出MIDP配置简表，这里接受生成的默认值（以后还可以修改）点击OK，工具提示我们把写好的Java源程序放到[WTK_HOME]\apps\HelloWorld\src目录之下．我们编辑如下代码，并保存在上述目录之下，文件名为Hello.java。</p>
		<p>
				<br />import javax.microedition.midlet.*; <br />import javax.microedition.lcdui.*; <br />public class Hello extends MIDlet <br />{ <br />private Display display; <br />public Hello(){ <br />display =Display.getDisplay(this); <br />} <br />public void startApp(){ <br />TextBox t = new TextBox("Hello","Hello",256,0); <br />display.setCurrent(t); <br />} <br />public void pauseApp(){ <br />} <br />public void destroyApp(boolean unconditional){ <br />} <br />}<br /> </p>
		<p> </p>
		<p>保存好了之后，点击Build按钮，工具会为你编译程序，如无意外再点击Run按钮，会弹出一个手机界面，剩下的就不用我教了吧（用鼠标对手机按键一顿狂点）。呵呵，你的第一个J2ME程序已经OK了.什么？你还一点都没懂呢（真是厉害，不懂都能写出J2ME程序来，果然是高手）．我这里主要是介绍WTK2.0工具的使用，程序并不是目的，不懂的话后面还会有详细的解说，这里只是带你上路．什么？你不懂Java！那也没有关系，后面我再讲得细一点。 </p>
		<p>跳过J2ME，我们先来讲点游戏的理论．具体到华容道这个游戏，主要有三个方面，贴图．游戏操作．逻辑判断．这里讲讲贴图，其他两方面放在概要设计和详细设计里讲．所谓的贴图，其实就是画图，就是在要显示图形的位置上输出一副图片，（要是牵扯到动画就要麻烦一些，可以使用TimerTask.Thread或Rannable之类的技术)，这副图片可以是事先准备好的也可以是临时处理的．在J2ME中有一个Image类,专门用于管理图片，它有createImage()方法，可以直接读取图片文件（J2ME只支持PNG格式的图片），也可以截取已有的图片的一部分（这样我们可以把很多图片放在一起，然后一张一张的截下来，好处是节省存储空间和文件读取时间，对于手机这两者都是性能的瓶颈）． </p>
		<p>J2ME还有一个Graphics类，专门用于绘图，它有drawImage()方法，可以把一副图片在指定的位置上显示出来，它还有drawRect()方法和setColor()方法，这两个方法在后面我们进行游戏操作时就会用到，这里先交代一下．有了图片和绘图的方法，还需要知道把图画到谁身上，J2ME提供了一个Canvas类，字面意思就是画布，它有一个paint()方法用于刷新页面，还有一个repaint()方法用于调用paint()方法．听着有些糊涂是吧，不要紧，我来结合具体程序讲解一下．为了今后编程的方便，我们创建两个类Images和Draw,Images用于保存一些常量值和图片，Draw主要是用于画图，这两个类的源代码如下。 </p>
		<p>Images类的源代码如下： </p>
		<p>
				<br />package huarongroad; <br />import javax.microedition.lcdui.*; <br />import javax.microedition.lcdui.game.*; <br />public class Images {//保存常量 <br />//绘图位置常量 <br />public static final int UNIT = 32;//方块的单位长度 <br />public static final int LEFT = 10;//画图的左边界顶点 <br />public static final int TOP = 9;//画图的上边界顶点 <br />//地图位置常量 <br />public static final int WIDTH = 4;//地图的宽度 <br />public static final int HEIGHT = 5;//地图的高度 <br />//地图标记常量 <br />public static final byte CAOCAO = (byte) ′a′; ＜A href="file://曹"＞file://曹＜/A＞操的地图标记 <br />public static final byte MACHAO = (byte) ′b′;//马超的地图标记 <br />public static final byte HUANGZHONG = (byte) ′c′;//黄忠的地图标记 <br />public static final byte GUANYU = (byte) ′d′;//关羽的地图标记 <br />public static final byte ZHANGFEI = (byte) ′e′;//张飞的地图标记 <br />public static final byte ZHAOYUN = (byte) ′f′;//赵云的地图标记 <br />public static final byte ZU = (byte) ′g′;//卒的地图标记 <br />public static final byte BLANK = (byte) ′h′;//空白的地图标记 <br />public static final byte CURSOR = (byte) ′i′;//光标的地图标记 <br />//地图组合标记常量 <br />public static final byte DLEFT = (byte) ′1′; ＜A href="file://组"＞file://组＜/A＞合图形左边标记 <br />public static final byte DUP = (byte) ′2′; ＜A href="file://组"＞file://组＜/A＞合图形上边标记 <br />public static final byte DLEFTUP = (byte) ′3′; ＜A href="file://组"＞file://组＜/A＞合图形左上标记 <br />//图片常量 <br />public static Image image_base;//基本图片 <br />public static Image image_Zhaoyun;//赵云的图片 <br />public static Image image_Caocao;//曹操的图片 <br />public static Image image_Huangzhong;//黄忠的图片 <br />public static Image image_Machao;//马超的图片 <br />public static Image image_Guanyu;//关羽的图片 <br />public static Image image_Zhangfei;//张飞的图片 <br />public static Image image_Zu;//卒的图片 <br />public static Image image_Blank;//空白的图片 <br />public static Image image_Frame;//游戏框架的图片 <br />public Images() {//构造函数 <br />} <br />public static boolean init() {//初始化游戏中用到的图片 <br />try { <br />image_base = Image.createImage("/huarongroad/BITBACK.png"); <br />image_Frame = Image.createImage(image_base, 126, 0, 145, 177, <br />Sprite.TRANS_NONE); <br />//Sprite类是用来翻转图片的，是MIDP2.0新新增加的支持游戏的特性 <br />image_Zhaoyun = Image.createImage(image_base, 0, 0, UNIT, 2 * UNIT, <br />Sprite.TRANS_NONE); <br />image_Caocao = Image.createImage(image_base, UNIT, 0, 2 * UNIT, <br />2 * UNIT, Sprite.TRANS_NONE); <br />image_Huangzhong = Image.createImage(image_base, 3 * UNIT, 0, UNIT, <br />2 * UNIT, <br />Sprite.TRANS_NONE); <br />image_Machao = Image.createImage(image_base, 0, 2 * UNIT, UNIT, <br />2 * UNIT, <br />Sprite.TRANS_NONE); <br />image_Guanyu = Image.createImage(image_base, UNIT, 2 * UNIT, <br />2 * UNIT, UNIT, <br />Sprite.TRANS_NONE); <br />image_Zhangfei = Image.createImage(image_base, 3 * UNIT, 2 * UNIT, <br />UNIT, 2 * UNIT, <br />Sprite.TRANS_NONE); <br />image_Zu = Image.createImage(image_base, 0, 4 * UNIT, UNIT, UNIT, <br />Sprite.TRANS_NONE); <br />image_Blank = Image.createImage(image_base, 1 * UNIT, 4 * UNIT,UNIT, <br />UNIT, <br />Sprite.TRANS_NONE); <br />return true; <br />}catch (Exception ex) { <br />return false; <br />} <br />} <br />}<br /> </p>
		<p> </p>
		<p>Draw类的源代码如下： </p>
		<p>
				<br />package huarongroad; <br />import javax.microedition.lcdui.*; <br />public class Draw { <br />//绘制游戏中的图片 <br />public Draw(Canvas canvas) {//构造函数 <br />} <br />public static boolean paint(Graphics g, byte img, int x, int y) { <br />//在地图的x,y点绘制img指定的图片 <br />try { <br />paint(g, img, x, y, Images.UNIT);//把地图x,y点转化成画布的绝对坐标，绘图 <br />return true; <br />} <br />catch (Exception ex) { <br />return false; <br />} <br />} <br />public static boolean paint(Graphics g, byte img, int x, int y, int unit) { <br />try { <br />switch (img) { <br />case Images.CAOCAO://画曹操 <br />//变成绝对坐标，并做调整 <br />g.drawImage(Images.image_Caocao, Images.LEFT + x * unit, <br />Images.TOP + y * unit, <br />Graphics.TOP | Graphics.LEFT); <br />break; <br />case Images.GUANYU://画关羽 <br />g.drawImage(Images.image_Guanyu, Images.LEFT + x * unit, <br />Images.TOP + y * unit, <br />Graphics.TOP | Graphics.LEFT); <br />break; <br />case Images.HUANGZHONG://画黄忠 <br />g.drawImage(Images.image_Huangzhong, Images.LEFT + x * unit, <br />Images.TOP + y * unit, <br />Graphics.TOP | Graphics.LEFT); <br />break; <br />case Images.MACHAO://画马超 <br />g.drawImage(Images.image_Machao, Images.LEFT + x * unit, <br />Images.TOP + y * unit, <br />Graphics.TOP | Graphics.LEFT); <br />break; <br />case Images.ZHANGFEI://画张飞 <br />g.drawImage(Images.image_Zhangfei, Images.LEFT + x * unit, <br />Images.TOP + y * unit, <br />Graphics.TOP | Graphics.LEFT); <br />break; <br />case Images.ZHAOYUN://画赵云 <br />g.drawImage(Images.image_Zhaoyun, Images.LEFT + x * unit, <br />Images.TOP + y * unit, <br />Graphics.TOP | Graphics.LEFT); <br />break; <br />case Images.ZU://画卒 <br />g.drawImage(Images.image_Zu, Images.LEFT + x * unit, <br />Images.TOP + y * unit, <br />Graphics.TOP | Graphics.LEFT); <br />break; <br />case Images.BLANK://画空白 <br />g.drawImage(Images.image_Blank, Images.LEFT + x * unit, <br />Images.TOP + y * unit, <br />Graphics.TOP | Graphics.LEFT); <br />break; <br />case Images.CURSOR://画光标 <br />g.drawRect(Images.LEFT + x * unit, <br />Images.TOP + y * unit,Images.UNIT,Images.UNIT); <br />break; <br />} <br />return true; <br />}catch (Exception ex) { <br />return false; <br />} <br />} <br />}<br /> </p>
		<p> </p>
		<p>其中Images类存的是绘图位置常量（也就是在画图时每个格子的长度和相对坐标原点位置要进行的调整）、地图位置常量（地图的长、宽），地图标记常量（人物对应的记号），地图组合标记常量（后面会细说），图片常量（存放人物的图片）；Draw类主要负责在制定的位置画出人物图片。下面我来说说Images类中的地图标记常量和地图组合标记常量。为了能够灵活的安排各个关面的布局，我们决定把游戏布局的信息存储在外部文件中，然后程序启动后把它读进来。 </p>
		<p>这样我们制定了一套存储图片的代码，这就是地图标记常量，如上面Images类中定义的Caocao(曹操)用a字符来表示，当程序读到a字符时就能将它转化成曹操对应的图片，并在读到a字符的位置上进行显示。但是从实际观察中我们发现所有的图片并不是统一大小的，有的占4个格子，有的占2个格子，还有的占1个格子，而且即便同是占两个格子的图片还有横、竖之分。有鉴于此，我们引入了地图组合标记常量，就是说在遇到占有多个格子的时候，值1(也就是Images.LEFT)表示它的左边是一个真正的地图标记，值2(也就是Images.UP)表示它的上边是一个真正的地图标记，值1(也就是Images.LEFTUP)表示它的左上边是一个真正的地图标记。地图组合标记常量其实就是用来占位置的，与实际显示无关，当后面我们将到移动时还会再来分析组合标记的使用。 </p>
		<p>Draw类主要是用来在画布上画出图形，它有两个paint方法，这是很常见的函数重载。但是程序中实际上只用到了4个参数的paint方法，它直接获得要画图片的相对坐标位置信息，然后调用5个参数的paint方法。5个参数的paint方法将相对坐标位置信息转换成绝对位置，并实际调用Graphics.drawImage()方法，将Images中的图片画了出来。这种实现方法的好处是灵活和便于扩展，但你需要画图的位置并不能够对应到格子中的相对坐标位置时，你就可以直接调用5个参数的paint方法，而不必再去修改这各类；但你添加新的图片时，只要在Images中增加对应的常量，然后向Draw中5个参数的paint方法添加一条处理就可以了。写到这里，两天的时间刚好用完。 </p>
		<p>三、需求分析 </p>
		<p>这部分叫做需求分析，听起来挺吓人的，其实就是搞清楚我们要做什么，做成什么样，那些不做。下面我引领着大家共同来完成这一步骤。首先，我们要做一个华容道的游戏，华容道的故事这里不再赘述了，但其中的人物在这里限定一下，如上面Images类里的定义，我们这个版本只提供曹操(Caocao)、关羽(Guanyu)、张飞(Zhangfei)、赵云(Zhaoyun)、黄忠(Huangzhong)、马超(Machao)和卒(Zu)。我们这里也限定一下游戏的操作方法：首先要通过方向键选择一个要移动的区域(就是一张图片)，被选择的区域用黑色方框框住；选好后按Fire键(就是确定键)将这块区域选中，被选中的区域用绿色方框框住；然后选择要移动到的区域，此时用红色方框框住被选择的区域；选好要移动到的区域之后按Fire键将要移动的区域(图片)移到要移动到的区域，并去掉绿色和红色的方框。这里需要强调的概念有选择的区域、选中的区域、要移动的区域和要移动到的区域，这四个概念请读者注意区分，当然也应当把这一部分记入数据字典之中。 </p>
		<p>为了使文章的重点突出(介绍如何制作一个J2ME的收集游戏)，我们这里限定一些与本主题无关的内容暂不去实现：过关之后的动画(实现时要用到TimerTask或Thread类，后续的系列文章中我会详细介绍动画方面的知识)、关面之间的切换(其实很简单，当完成任务之后重新再做一边)、暂停和保存等操作(这部分的内容介绍的资料很多，我也写不出什么新的东东来，难免抄袭，故此免掉)。 </p>
		<p>需求分析基本完成，离下午还有一段时间，马上动手用ACDSee把从网上找来的BMP文件，调整其大小为271*177(我的这个图片是两个部分合在一起，所以比手机实际屏幕大了)，另存为PNG格式。半天时间刚刚好，不但搞清楚了要做的东东，还把要用的图片准备好了。 </p>
		<p>四、概要设计 </p>
		<p>概要设计是从需求分析过渡到详细设计的桥梁和纽带，这一部分中我们确定项目的实现方法和模块的划分。我们决定将整个项目分成五个部分，分别是前面介绍的Images、Draw，还有Map和Displayable1和MIDlet1。Images和Draw类功能简单、结构固定，因此很多项目我们都使用这两各类，这里直接拿来改改就能用了，前面已经介绍过这里不再赘述。Map类是用来从外部文件读入地图，然后保存在一个数组之中，这部分的内容是我们在本阶段讨论的重点。Displayable1是一个继承了Canvas类的画布，它用来处理程序的主要控制逻辑和一部分控制逻辑所需的辅助函数，主要函数应该包括用来绘图的paint()函数、用来控制操作的keyPressed()函数、用来控制选择区域的setRange()函数、用来控制选择要移动到区域的setMoveRange()函数、用来移动选中区域的Move()函数和判断是否完成任务的win()函数，更具体的分析，我们放到详细设计中去细化。MIDlet1实际上就是一个控制整个J2ME应用的控制程序，其实也没有什么可特别的，它和我们前面介绍的"Hello World"程序大同小异，这里就不展开来说了，后面会贴出它的全部代码。 </p>
		<p>Map类主要应该有一个Grid[][]的二维数组，用来存放华容道的地图，还应该有一个read_map()函数用来从外部文件读取地图内容填充Grid数据结构，再就是要有一个draw_map()函数用来把Grid数据结构中的地图内容转换成图片显示出来(当然要调用Draw类的paint方法)。说到读取外部文件，笔者知道有两种方法：一种是传统的定义一个InputStream对象，然后用getClass().getResourceAsStream()方法取得输入流，然后再从输入流中取得外部文件的内容，例如 </p>
		<p>
				<br />InputStream is = getClass().getResourceAsStream("/filename"); <br />if (is != null) { <br />byte a = (byte) is.read(); <br />}<br /> </p>
		<p> </p>
		<p>这里请注意文件名中的根路径是相对于便以后的class文件放置的位置，而不是源文件(java)。第二种方法是使用onnector.openInputStream方法，然后打开的协议是Resource，但是这种方法笔者反复尝试都没能调通，报告的错误是缺少Resource协议，估计第二种方法用到J2ME的某些扩展类包，此处不再深究。由于以前已经做过一些类似华容道这样的地图，这里直接给出Map类的代码，后面就不再详细解释Map类了，以便于我们可以集中精力处理Displayable1中的逻辑。 </p>
		<p>Map类的代码如下： </p>
		<p>
				<br />package huarongroad; <br />import java.io.InputStream; <br />import javax.microedition.lcdui.*; <br />public class Map { <br />//处理游戏的地图，负责从外部文件加载地图数据，存放地图数据，并按照地图数据绘制地图 <br />public byte Grid[][];//存放地图数据 <br />public Map() {//构造函数，负责初始化地图数据的存储结构 <br />this.Grid = new byte[Images.HEIGHT][Images.WIDTH]; <br />//用二维数组存放地图数据，注意第一维是竖直坐标，第二维是水平坐标 <br />} <br />public int[] read_map(int i) { <br />＜A href="file://从"＞file://从＜/A＞外部文件加载地图数据，并存放在存储结构中，返回值是光标点的位置 <br />//参数是加载地图文件的等级 <br />int[] a = new int[2];//光标点的位置，0是水平位置，1是竖直位置 <br />try { <br />InputStream is = getClass().getResourceAsStream( <br />"/huarongroad/level".concat(String.valueOf(i))); <br />if (is != null) { <br />for (int k = 0; k ＜ Images.HEIGHT; k++) { <br />for (int j = 0; j ＜ Images.WIDTH; j++) { <br />this.Grid[k][j] = (byte) is.read(); <br />if ( this.Grid[k][j] == Images.CURSOR ) { <br />//判断出光标所在位置 <br />a[0] = j;//光标水平位置 <br />a[1] = k;//光标竖直位置 <br />this.Grid[k][j] = Images.BLANK;//将光标位置设成空白背景 <br />} <br />} <br />is.read();//读取回车（13）,忽略掉 <br />is.read();//读取换行（10）,忽略掉 <br />} <br />is.close(); <br />}else { <br />//读取文件失败 <br />a[0] = -1; <br />a[1] = -1; <br />} <br />}catch (Exception ex) { <br />//打开文件失败 <br />a[0] = -1; <br />a[1] = -1; <br />} <br />return a; <br />} <br />public boolean draw_map(Graphics g) { <br />//调用Draw类的静态方法，绘制地图 <br />try { <br />for (int i = 0; i ＜ Images.HEIGHT; i++) { <br />for (int j = 0; j ＜ Images.WIDTH; j++) { <br />Draw.paint(g, this.Grid[i][j], j, i);//绘制地图 <br />} <br />} <br />return true; <br />}catch (Exception ex) { <br />return false; <br />} <br />} <br />}<br /> </p>
		<p> </p>
		<p>对于像华容道这样的小型地图可以直接用手工来绘制地图的内容，比如： </p>
		<p>fa1c </p>
		<p>2232 </p>
		<p>bd1e </p>
		<p>2gg2 </p>
		<p>gihg </p>
		<p>但是，如果遇到像坦克大战或超级玛莉那样的地图，就必须另外开发一个地图编辑器了(我会在后续的文章中介绍用vb来开发一个地图编辑器)。 </p>
		<p>五、详细设计 </p>
		<p>详细设计是程序开发过程中至关重要的一个环节，好在我们在前面的各个阶段中已经搭建好了项目所需的一些工具，现在这个阶段中我们只需集中精力设计好Displayable1中的逻辑。(两天的时间当然不只干这点活，还要把其他几个类的设计修改一下) </p>
		<p>Displayable1这个类负责处理程序的控制逻辑。首先，它需要有表示当前关面的变量level、表示当前光标位置的变量loc、表示要移动区域的变量SelectArea、表示要移动到的区域的变量MoveArea、表示是否已有区域被选中而准备移动的变量Selected和Map类的实例MyMap。然后，我们根据用户按不同的键来处理不同的消息，我们要实现keyPressed()函数，在函数中我们处理按键的上下左右和选中(Fire)，这里的处理需要我展开来讲一讲，后面我很快会把这一部分详细展开。 </p>
		<p>接下来，是实现paint()函数，我们打算在这一部分中反复的重画背景、地图和选择区域，这个函数必须处理好区域被选中之后的画笔颜色的切换，具体讲就是在没有选中任何区域时要用黑色画笔，当选重要移动的区域时使用绿色画笔，当选择要移动到的区域时改用红色画笔(当然附加一张流程图是必不可少的)。 </p>
		<p>再下面要实现的setRange()函数和setMoveRange()函数，这两个函数用来设置要移动的区域和要移动到的区域，我的思路就是利用前面在Images类中介绍过的地图组合标记常量，当移动到地图组合标记常量时，根据该点地图中的值做逆向变换找到相应的地图标记常量，然后设置相应的loc、SelectArea和MoveArea,其中setMoveRange()函数还用到了一个辅助函数isInRange(),isInRange()函数是用来判断给定的点是否在已选中的要移动的区域之内,如果isInRange()的返回值是假并且该点处的值不是空白就表明要移动到的区域侵犯了其他以被占用的区域。有了setRange()和setMoveRange()函数，Move()函数就水到渠成了,Move()函数将要移动的区域移动到要移动到的区域,在移动过程中分为三步进行: </p>
		<p>第一.复制要移动的区域； </p>
		<p>第二.将复制出的要移动区域复制到要移动到的区域(这两步分开进行的目的是防止在复制过程中覆盖掉要移动的区域)； </p>
		<p>第三.用isInRange2()判断给定的点是否在要移动到的区域内,将不在要移动到的区域内的点设置成空白。 下面我们详细的分析一下keyPressed()函数的实现方法:首先,keyPressed()函数要处理按键的上下左右和选中(Fire),在处理时需要用Canvas类的getGameAction函数来将按键的键值转换成游戏的方向,这样可以提高游戏的兼容性(因为不同的J2ME实现,其方向键的键值不一定是相同的)。 </p>
		<p>接下来,分别处理四个方向和选中.当按下向上时,先判断是否已经选定了要移动的区域(即this.selected是否为真),如果没有选中要移动区域则让光标向上移动一格,然后调用setRange()函数设置选择要移动的区域,再调用repaint()函数刷新屏幕,否则如果已经选中了要移动的区域,就让光标向上移动一格,然后调用setMoveRange()函数判断是否能够向上移动已选中的区域,如果能移动就调用repaint()函数刷新屏幕,如果不能移动就让光标向下退回到原来的位置。 </p>
		<p>当按下向下时,先判断是否已经选定了要移动的区域,如果没有选中要移动的区域则判断当前所处的区域是否为两个格高,如果是两个格高则向下移动两格,如果是一个格高则向下移动一格,接着再调用setRange()函数设置选择要移动的区域,而后调用repaint()函数刷新屏幕,否则如果已经选中了要移动的区域,就让光标向下移动一格,然后调用setMoveRange()函数判断是否能够向下移动已选中的区域,如果能移动就调用repaint()函数刷新屏幕,如果不能移动就让光标向上退回到原来的位置.按下向左时情况完全类似向上的情况,按下向右时情况完全类似向下的情况,因此这里不再赘述,详细情况请参见程序的源代码。 </p>
		<p>当按下选中键时,先判断是否已经选中了要移动的区域,如果已经选中了要移动的区域就调用Move()函数完成由要移动的区域到要移动到的区域的移动过程,接着调用repaint()函数刷新屏幕,然后将已选择标记置成false,继续调用win()函数判断是否完成了任务,否则如果还没有选定要移动的区域则再判断当前选中区域是否为空白,如果不是空白就将选中标记置成true,然后刷新屏幕.这里介绍一个技巧,在开发程序遇到复杂的逻辑的时候,可以构造一格打印函数来将所关心的数据结构打印出来以利调试,这里我们就构造一个PrintGrid()函数,这个函数纯粹是为了调试之用,效果这得不错.至此我们完成了编码前的全部工作。 </p>
		<p>六、编码 </p>
		<p>整个项目共有五个类,有四个类的代码前面已经介绍过了,而且是在其他项目中使用过的相对成熟的代码.现在只需全力去实现Displayable1类.Displayable1类的代码如下: </p>
		<p>
				<br />package huarongroad; <br />import javax.microedition.lcdui.*; <br />public class Displayable1 extends Canvas implements CommandListener { <br />private int[] loc = new int[2]; ＜A href="file://光"＞file://光＜/A＞标的当前位置，0是水平位置，1是竖直位置 <br />private int[] SelectArea = new int[4];//被选定的区域，即要移动的区域 <br />private int[] MoveArea = new int[4];//要移动到的区域 <br />private Map MyMap = new Map();//地图类 <br />private boolean selected;//是否已经选中要移动区域的标志 <br />private int level;//但前的关面 <br />public Displayable1() {//构造函数 <br />try { <br />jbInit();//JBuilder定义的初始化函数 <br />}catch (Exception e) { <br />e.printStackTrace(); <br />} <br />} <br />private void Init_game(){ <br />//初始化游戏，读取地图，设置选择区域，清空要移动到的区域 <br />this.loc = MyMap.read_map(this.level);//读取地图文件，并返回光标的初始位置 <br />//0为水平位置，1为竖直位置 <br />this.SelectArea[0] = this.loc[0];//初始化选中的区域 <br />this.SelectArea[1] = this.loc[1]; <br />this.SelectArea[2] = 1; <br />this.SelectArea[3] = 1; <br />this.MoveArea[0] = -1;//初始化要移动到的区域 <br />this.MoveArea[1] = -1; <br />this.MoveArea[2] = 0; <br />this.MoveArea[3] = 0; <br />} <br />private void jbInit() throws Exception {//JBuilder定义的初始化函数 <br />＜A href="file://初"＞file://初＜/A＞始化实例变量 <br />this.selected = false;//设置没有被选中的要移动区域 <br />this.level = 1; <br />Images.init();//初始化图片常量 <br />Init_game();//初始化游戏，读取地图，设置选择区域，清空要移动到的区域 <br />setCommandListener(this);//添加命令监听，这是Displayable的实例方法 <br />addCommand(new Command("Exit", Command.EXIT, 1));//添加“退出”按钮 <br />} <br />public void commandAction(Command command, Displayable displayable) { <br />//命令处理函数 <br />if (command.getCommandType() == Command.EXIT) {//处理“退出” <br />MIDlet1.quitApp(); <br />} <br />} <br />protected void paint(Graphics g) { <br />//画图函数，用于绘制用户画面，即显示图片，勾画选中区域和要移动到的区域 <br />try { <br />g.drawImage(Images.image_Frame, 0, 0, <br />Graphics.TOP | Graphics.LEFT);//画背景 <br />MyMap.draw_map(g);//按照地图内容画图 <br />if ( this.selected ) <br />g.setColor(0,255,0);//如果被选中，改用绿色画出被选中的区域 <br />g.drawRect(this.SelectArea[0] * Images.UNIT + Images.LEFT, <br />this.SelectArea[1] * Images.UNIT + Images.TOP, <br />this.SelectArea[2] * Images.UNIT, <br />this.SelectArea[3] * Images.UNIT);//画出选择区域， <br />＜A href="file://如"＞file://如＜/A＞果被选中，就用绿色 <br />＜A href="file://否"＞file://否＜/A＞则，使用黑色 <br />g.setColor(255,255,255);//恢复画笔颜色 <br />if (this.selected) {//已经选中了要移动的区域 <br />g.setColor(255, 0, 255);//改用红色 <br />g.drawRect(this.MoveArea[0] * Images.UNIT + Images.LEFT, <br />this.MoveArea[1] * Images.UNIT + Images.TOP, <br />this.MoveArea[2] * Images.UNIT, <br />this.MoveArea[3] * Images.UNIT);//画出要移动到的区域 <br />g.setColor(255, 255, 255);//恢复画笔颜色 <br />} <br />}catch (Exception ex) { <br />} <br />System.out.println(Runtime.getRuntime().freeMemory()); <br />System.out.println(Runtime.getRuntime().totalMemory()); <br />} <br />private void setRange() { <br />//设置移动后能够选中的区域 <br />//调整当前光标位置到地图的主位置，即记录人物信息的位置 <br />if (this.MyMap.Grid[this.loc[1]][this.loc[0]] == Images.DLEFT) { <br />this.loc[0] -= 1;//向左调 <br />}else if (this.MyMap.Grid[this.loc[1]][this.loc[0]] == Images.DUP) { <br />this.loc[1] -= 1;//向上调 <br />}else if (this.MyMap.Grid[this.loc[1]][this.loc[0]] == Images.DLEFTUP) { <br />this.loc[0] -= 1;//向左调 <br />this.loc[1] -= 1;//向上调 <br />} <br />this.SelectArea[0] = this.loc[0];//设置光标的水平位置 <br />this.SelectArea[1] = this.loc[1];//设置光标的竖直位置 <br />//设置光标的宽度 <br />if (this.loc[0] + 1 ＜ Images.WIDTH) { <br />this.SelectArea[2] = this.MyMap.Grid[this.loc[1]][this.loc[0] + 1] != (byte) ′1′ ? <br />1 : 2; <br />}else { <br />this.SelectArea[2] = 1; <br />} <br />//设置光标的高度 <br />if (this.loc[1] + 1 ＜ Images.HEIGHT) { <br />this.SelectArea[3] = this.MyMap.Grid[this.loc[1] + 1][this.loc[0]] != (byte) ′2′ ? <br />1 : 2; <br />}else { <br />this.SelectArea[3] = 1; <br />} <br />} <br />private boolean setMoveRange() { <br />//设置要移动到的区域，能够移动返回true,否则返回false <br />for (int i = 0; i ＜ this.SelectArea[2]; i++) { <br />for (int j = 0; j ＜ this.SelectArea[3]; j++) { <br />if (this.loc[1] + j ＞= Images.HEIGHT || <br />this.loc[0] + i ＞= Images.WIDTH || <br />(!isInRange(this.loc[0] + i, this.loc[1] + j) &amp;&amp; <br />this.MyMap.Grid[this.loc[1] + j][this.loc[0] + i] != <br />Images.BLANK)) { <br />return false; <br />} <br />} <br />} <br />this.MoveArea[0] = this.loc[0]; <br />this.MoveArea[1] = this.loc[1]; <br />this.MoveArea[2] = this.SelectArea[2]; <br />this.MoveArea[3] = this.SelectArea[3]; <br />return true; <br />} <br />private boolean isInRange(int x, int y) { <br />//判断给定的（x，y）点是否在选定区域之内，x是水平坐标，y是竖直坐标 <br />if (x ＞= this.SelectArea[0] &amp;&amp; <br />x ＜ this.SelectArea[0] + this.SelectArea[2] &amp;&amp; <br />y ＞= this.SelectArea[1] &amp;&amp; <br />y ＜ this.SelectArea[1] + this.SelectArea[3]) { <br />return true; <br />}else { <br />return false; <br />} <br />} <br />private boolean isInRange2(int x, int y) { <br />//判断给定的（x，y）点是否在要移动到的区域之内，x是水平坐标，y是竖直坐标 <br />if (x ＞= this.MoveArea[0] &amp;&amp; <br />x ＜ this.MoveArea[0] + this.MoveArea[2] &amp;&amp; <br />y ＞= this.MoveArea[1] &amp;&amp; <br />y ＜ this.MoveArea[1] + this.MoveArea[3]) { <br />return true; <br />}else { <br />return false; <br />} <br />} <br />protected void keyPressed(int keyCode) { <br />//处理按下键盘的事件，这是Canvas的实例方法 <br />switch (getGameAction(keyCode)) {//将按键的值转化成方向常量 <br />case Canvas.UP://向上 <br />if (!this.selected) {//还没有选定要移动的区域 <br />if (this.loc[1] - 1 ＞= 0) {//向上还有移动空间 <br />this.loc[1]--;//向上移动一下 <br />setRange();//设置光标移动的区域，该函数能将光标移动到地图主位置 <br />repaint();//重新绘图 <br />} <br />}else {//已经选定了要移动的区域 <br />if (this.loc[1] - 1 ＞= 0) {//向上还有移动空间 <br />this.loc[1]--;//向上移动一下 <br />if (setMoveRange()) {//能够移动，该函数能够设置要移动到的区域 <br />repaint();//重新绘图 <br />}else {//不能移动 <br />this.loc[1]++;//退回来 <br />} <br />} <br />} <br />break; <br />case Canvas.DOWN://向下 <br />if (!this.selected) {//还没有选定要移动的区域 <br />if (this.loc[1] + 1 ＜ Images.HEIGHT) {//向下还有移动空间 <br />if (this.MyMap.Grid[this.loc[1] + 1][this.loc[0]] == <br />Images.DUP){//该图片有两个格高 <br />this.loc[1]++;//向下移动一下 <br />if (this.loc[1] + 1 ＜ Images.HEIGHT) {//向下还有 <br />＜A href="file://移"＞file://移＜/A＞动空间 <br />this.loc[1]++;//向下移动一下 <br />setRange();//设置光标移动的区域， <br />＜A href="file://该"＞file://该＜/A＞函数能将光标移动到地图主位置 <br />repaint();//重新绘图 <br />}else {//向下没有移动空间 <br />this.loc[1]--;//退回来 <br />} <br />}else {//该图片只有一个格高 <br />this.loc[1]++;//向下移动一下 <br />setRange();//设置光标移动的区域， <br />＜A href="file://该"＞file://该＜/A＞函数能将光标移动到地图主位置 <br />repaint();//重新绘图 <br />} <br />}else { <br />} <br />}else {//已经选定了要移动的区域 <br />if (this.loc[1] + 1 ＜ Images.HEIGHT) {//向下还有移动空间 <br />this.loc[1]++;//向下移动一下 <br />if (setMoveRange()) {//能够移动，该函数能够设置要移动到的区域 <br />repaint();//重新绘图 <br />}else {//不能移动 <br />this.loc[1]--;//退回来 <br />} <br />} <br />} <br />break; <br />case Canvas.LEFT://向左 <br />if (!this.selected) {//还没有选定要移动的区域 <br />if (this.loc[0] - 1 ＞= 0) {//向左还有移动空间 <br />this.loc[0]--;//向左移动一下 <br />setRange();//设置光标移动的区域，该函数能将光标移动到地图主位置 <br />repaint();//重新绘图 <br />} <br />}else {//已经选定了要移动的区域 <br />if (this.loc[0] - 1 ＞= 0) {//向左还有移动空间 <br />this.loc[0]--;//向左移动一下 <br />if (setMoveRange()) {//能够移动，该函数能够设置要移动到的区域 <br />repaint();//重新绘图 <br />}else {//不能移动 <br />this.loc[0]++;//退回来 <br />} <br />} <br />} <br />break; <br />case Canvas.RIGHT://向右 <br />if (!this.selected) {//还没有选定要移动的区域 <br />if (this.loc[0] + 1 ＜ Images.WIDTH) {//向右还有移动空间 <br />if (this.MyMap.Grid[this.loc[1]][this.loc[0] + 1] == <br />Images.DLEFT) {//该图片有两个格宽 <br />this.loc[0]++;//向右移动一下 <br />if (this.loc[0] + 1 ＜ Images.WIDTH) {//向右还有 <br />＜A href="file://移"＞file://移＜/A＞动空间 <br />this.loc[0]++;//向右移动一下 <br />setRange();//设置光标移动的区域， <br />＜A href="file://该"＞file://该＜/A＞函数能将光标移动到地图主位置 <br />repaint();//重新绘图 <br />}else {//向右没有移动空间 <br />this.loc[0]--;//退回来 <br />} <br />}else {//该图片只有一个格宽 <br />this.loc[0]++;//向右移动一下 <br />setRange();//设置光标移动的区域， <br />＜A href="file://该"＞file://该＜/A＞函数能将光标移动到地图主位置 <br />repaint();//重新绘图 <br />} <br />}else { <br />} <br />}else {//已经选定了要移动的区域 <br />if (this.loc[0] + 1 ＜ Images.WIDTH) {//向右还有移动空间 <br />this.loc[0]++;//向右移动一下 <br />if (setMoveRange()) {//能够移动，该函数能够设置要移动到的区域 <br />repaint();//重新绘图 <br />}else {//不能移动 <br />this.loc[0]--;//退回来 <br />} <br />} <br />} <br />break; <br />case Canvas.FIRE: <br />if (this.selected) {//已经选定了要移动的区域 <br />Move();//将要移动的区域移动到刚选中的区域 <br />repaint();//重新绘图 <br />this.selected = false;//清除已选定要移动区域的标志 <br />if ( win()) { <br />System.out.println("win"); <br />} <br />}else {//还没有选定要移动的区域 <br />if (this.MyMap.Grid[this.loc[1]][this.loc[0]] == <br />Images.BLANK) {//要移到的位置是一个空白 <br />}else {//要移到的位置不是空白 <br />this.selected = true;//设置已选定要移动区域的标志 <br />} <br />repaint();//重新绘图 <br />} <br />break; <br />} <br />} <br />private boolean win(){ <br />＜A href="file://判"＞file://判＜/A＞断是否已经救出了曹操 <br />if ( this.MyMap.Grid[Images.HEIGHT - 2 ][Images.WIDTH - 3 ] == Images.CAOCAO ) <br />return true; <br />else <br />return false; <br />} <br />private void PrintGrid(String a) { <br />＜A href="file://打"＞file://打＜/A＞印当前地图的内容，用于调试 <br />System.out.println(a); <br />for (int i = 0; i ＜ Images.HEIGHT; i++) { <br />for (int j = 0; j ＜ Images.WIDTH; j++) { <br />System.out.print( (char)this.MyMap.Grid[i][j]); <br />} <br />System.out.println(""); <br />} <br />} <br />private void Move() { <br />＜A href="file://将"＞file://将＜/A＞要移动的区域移动到刚选中的区域 <br />if (this.MoveArea[0] == -1 || this.MoveArea[1] == -1 || <br />this.SelectArea[0] == -1 || this.SelectArea[1] == -1) {//没有选中区域 <br />}else {//已经选中了要移动的区域和要移动到的区域 <br />byte[][] temp = new byte[this.SelectArea[3]][this.SelectArea[2]]; <br />＜A href="file://复"＞file://复＜/A＞制要移动的区域，因为这块区域可能会被覆盖掉 <br />for (int i = 0; i ＜ this.SelectArea[2]; i++) { <br />for (int j = 0; j ＜ this.SelectArea[3]; j++) { <br />temp[j][i] = <br />this.MyMap.Grid[this.SelectArea[1] +j] <br />[this.SelectArea[0] + i]; <br />} <br />} <br />＜A href="<a href="file://PrintGrid/">file://PrintGrid</a>"＞<a href="file://PrintGrid/">file://PrintGrid</a>＜/A＞("1"); // 调试信息 <br />＜A href="file://将"＞file://将＜/A＞要移动的区域移动到刚选中的区域（即要移动到的区域） <br />for (int i = 0; i ＜ this.SelectArea[2]; i++) { <br />for (int j = 0; j ＜ this.SelectArea[3]; j++) { <br />this.MyMap.Grid[this.MoveArea[1] + j] <br />[this.MoveArea[0] + i] = temp[j][i]; <br />} <br />} <br />＜A href="<a href="file://PrintGrid/">file://PrintGrid</a>"＞<a href="file://PrintGrid/">file://PrintGrid</a>＜/A＞("2");// 调试信息 <br />＜A href="file://将"＞file://将＜/A＞要移动的区域中无用内容置成空白 <br />for (int i = 0; i ＜ this.SelectArea[3]; i++) { <br />for (int j = 0; j ＜ this.SelectArea[2]; j++) { <br />if (!isInRange2(this.SelectArea[0] + j, <br />this.SelectArea[1] + i)) {//该点是不在要移动到 <br />＜A href="file://的"＞file://的＜/A＞区域之内，需置空 <br />this.MyMap.Grid[this.SelectArea[1] + i] <br />[this.SelectArea[0] + j] = Images.BLANK; <br />}else { <br />} <br />} <br />} <br />＜A href="<a href="file://PrintGrid/">file://PrintGrid</a>"＞<a href="file://PrintGrid/">file://PrintGrid</a>＜/A＞("3");// 调试信息 <br />this.SelectArea[0] = this.MoveArea[0];//重置选中位置的水平坐标 <br />this.SelectArea[1] = this.MoveArea[1];//重置选中位置的竖直坐标 <br />this.MoveArea[0] = -1;//清空要移动到的位置 <br />this.MoveArea[1] = -1;//清空要移动到的位置 <br />this.MoveArea[2] = 0;//清空要移动到的位置 <br />this.MoveArea[3] = 0;//清空要移动到的位置 <br />} <br />} <br />}<br /> </p>
		<p> </p>
		<p>代码的相关分析,在详细设计阶段已经讲过,代码中有比较相近的注释,请读者自行研读分析.将全部的代码写好,用wtk2.0自带的Ktoolbar工具建立一个工程,接下来把去不源文件放到正确位置下,然后点击build,再点run,就完成了程序的编写.当然如果有错误还要修改和调试。 </p>
		<p>七、测试 </p>
		<p>作为一个真正的产品要经过单体测试、结合测试和系统测试。由于项目本身简单,而且大部分代码已经是相对成熟的,我们跳过单体测试；又由于笔者的实际环境所限,无法搞到Java手机,无法架设OTA服务器,因此我们也只能放弃系统测试。那么就让我们开始结合测试吧。测试之前要先出一个测试式样书,也就是测试的计划。我们将它简化一下,只测试如下几种情况:第一、对各种形状的区域的选择和移动;第二、临近边界区域的选择和移动;第三、同一区域的反复选择和反复移动;第四、非法选择和非法移动。有了测试的目标,接下来的工作就是用wtk2.0自带的Run MIDP Application工具进行测试。打开这个工具,加载huarongRoad的jad文件,程序就会自动运行,选择launch上MIDlet1这个程序,华容道游戏就会跃然屏幕之上,接下来的工作就是左三点.右三点,拇指扭扭,来做测试。测试过程中发现任何的问题,立刻发一个bug票给自己,然后就又是痛苦的调试和修正bug,如此如此。 </p>
		<p>八、发布 </p>
		<p>谈到发布,其实是个关键,再好的产品不能很好的发布出去也只是个产品而已,变不成商品也就得不到回报.由于笔者的条件所限,这里只能是纸上谈兵,不过还是希望能够使读者对这一过程有所了解(网上的资料也很多)。 </p>
		<p>J2ME的程序发布一般都是通过OTA(Over The Air),你只需要一台有公网IP的主机和一个普通的web Server就可以了(尽管要求很低,但笔者还是没有)，这里我们以apache为例介绍一下OTA服务的配置，首先是安装好了apache服务器，然后在conf目录下找到mime.types文件，在该文件中加入如下两行 </p>
		<p>application/java-archive jar </p>
		<p>text/vnd.sun.j2me.app-descriptor jad </p>
		<p>然后重起apache服务器就可以了。接下来的工作就是修改jad文件中MIDlet-Jar-URL:后面的参数，将它改为URL的绝对路径，即＜A href="<a href="http://***/">http://***/</a>"＞<a href="http://***/">http://***/</a>＜/A＞huarongroad.jar(其中***是你的域名或IP地址)。在下面就是用java手机下载jad文件，它会自动部署相应的jar文件并加载它。剩下的工作就和在模拟器上操作是一样的了。 </p>
		<p>九、项目总结 </p>
		<p>至此，我们已经完成了一个J2ME游戏的全部开发过程，程序中涉及到了调研、分析、设计、编码、测试和发布等方面的问题，其实在实际的工作中还有很多更为具体的问题，毕竟技术只在软件开发过程中占据很有限的一部分，这里限于篇幅的限制无法一一具体展开。今后，笔者计划再写一篇使用J2ME开发手机屏保的文章，借此机会向读者展示J2ME动画技术；然后再写一篇J2ME网络应用的文章，做一个类似开心辞典那样的知识问答游戏，以便向读者展示J2ME的网络技术；待这两方面的技术交待清楚之后，我将引领读者制作一个稍大一些的游戏。</p>
<img src ="http://www.blogjava.net/zjw-albert/aggbug/57152.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zjw-albert/" target="_blank">zjw_albert</a> 2006-07-07 16:15 <a href="http://www.blogjava.net/zjw-albert/archive/2006/07/07/57152.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>J2ME与MIDP开发</title><link>http://www.blogjava.net/zjw-albert/archive/2006/07/07/57136.html</link><dc:creator>zjw_albert</dc:creator><author>zjw_albert</author><pubDate>Fri, 07 Jul 2006 06:59:00 GMT</pubDate><guid>http://www.blogjava.net/zjw-albert/archive/2006/07/07/57136.html</guid><wfw:comment>http://www.blogjava.net/zjw-albert/comments/57136.html</wfw:comment><comments>http://www.blogjava.net/zjw-albert/archive/2006/07/07/57136.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/zjw-albert/comments/commentRss/57136.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zjw-albert/services/trackbacks/57136.html</trackback:ping><description><![CDATA[
		<dt>Java嵌入式开发之四 
</dt>
		<dd class="ArticleInfo">2005.08.08  来自：无线空间   
</dd>
		<dd class="ArticleContent">
				<table style="FLOAT: left; MARGIN: 0px 10px 10px" cellspacing="0" cellpadding="0" align="left" border="0">
						<tbody>
								<tr>
										<td>
												<script type="text/javascript">
														<!--
						csdn_AD_Position_GroupID = "{e025b96b-2fda-4e82-84ef-3e0772838ed3}";
						csdn_AD_Page_Url = document.location;
						csdn_AD_CurrPage_CharSet = "gb2312";
						//-->
												</script>
												<script src="http://ggmm.csdn.net/AD/Show_JavaScript_AD.js" type="text/javascript">
												</script>
												<script language="JavaScript1.1" src="http://ggmm.csdn.net/AD/ShowJavaScriptAD.aspx?show=true&amp;position={e025b96b-2fda-4e82-84ef-3e0772838ed3}&amp;CharSet=gb2312">
												</script>
												<br />
												<script src="http://news.csdn.net/ad/news_textlink.js" type="text/javascript">
												</script>
										</td>
								</tr>
						</tbody>
				</table>
				<br />
				<center>
						<b>J2ME与MIDP开发</b>
				</center>
				<br />在我前面的三篇文章中，我介绍了一些关于J2ME的基本的知识，在这篇文章中我想谈谈J2ME与MIDP开发的一些知识，其实在本系列的第二部分我门就已经接触到MIDP了，现在只是想深入探讨一下。MIDP是Mobile Information Devices Profile(移动信息设备简表)的简称，而遵照 MIDP和CLDC规范编写的 Java应用程序我们就称其为 MIDlet。<br /><br />　　你可以从MIDP这个规范的英文名称的含义推测， MIDlet是定位于提供某种水平的网络连接性的移动设备。运行 MIDlet的设备也有好几个共同的属性：有限的屏幕大小，内存和处理能力,这个规范是设计来满足这些需求，典型的设备包含行动电话和呼叫器。<br /><br />　　这篇文章将重点介绍安装和配置 CLDC和 MIDP软件,我们也将写一个简单的 MIDlet并学习在一个移动设备预览这个MIDlet的必需的步骤，最后再谈一谈如何给MIDlet打包。<br /><br />　　CLDC定义了一个用于 Java虚拟机的规范和一组核心类库，CLDC本质上是一个 Java 2标准版 ( J2SE )的简化版本，是为了使用有限内存和资源的设备设计的。配置 (比如 CLDC )是设计来运行简表的，而MID简表是一个规范，它提供一套核心类库来编写那些用于移动设备的Java应用程序。一个简表定义类库，开发者们使用这些类库来为某一特定的设备或用于某一范围的设备编写应用程序。例如， MIDP定义的类是用于创建用户界面(文本框、表单等)，处理用户输入以及使用 HTTP在一个网络上通讯。<br /><br />　　<b>第一节　开发MIDlet</b><br /><br />　　<b>下载软件</b><br /><br />　　在你能写一个 MIDlet之前，你需要下载必需的软件： JDK，CLDC以及 MIDP。<br />　　· <a href="http://java.sun.com/products/jdk/1.2/" target="_blank"><font color="#000066">Java Development Kit ( JDK )</font></a>-- 1.2版本以上 <br /><br />　　· <a href="http://www.sun.com/software/communitysource/j2me/cldc/" target="_blank"><font color="#000066">Connected, Limited Device Configuration (CLDC)</font></a><br />　　·<a href="http://java.sun.com/products/midp/" target="_blank"><font color="#000066"> Mobile Information Device Profile (MIDP)</font></a><br /><br />　　你也可能选择下载 <a href="http://java.sun.com/aboutJava/communityprocess/final/jsr037/index.html" target="_blank"><font color="#000066">J2ME规范</font></a>，下载到的这个规范包括 MIDP应用程序接口，当你是初次开发 MIDlet时，它是一个非常好的参考。<br /><br />　　<b>安装软件</b><br /><br />　　一、JDK<br /><br />　　JDK已经默认了用于安装文件的目录，当然了，你也可以选择安装在一个你自己选定的路径。如果安装的 JDK版本是 1.3并且选择默认路径，那么 JDK将被安装到这个目录：c:jdk1.3<br /><br />　　你一定很好奇，为什么需要 JDK？因为 CLDC和 MIDP安装好后都不包括Java编译程序 javac.exe，很明显，没有编译程序就没有能力编译你的 Java代码，你也不可能有进步。<br /><br />　　二、有限连接设备配置 ( CLDC )<br /><br />　　解压你下载到硬盘上的.zip文件，我推荐路径为 C:j2me。解压以后，c:j2me路径的结构如下所示：解压以后，c:j2me路径的结构如下所示：<br /><br />　　c:j2me<br />　　|<br />　　j2me_cldc<br /><br />　　三、移动信息设备简表 ( MIDP )<br /><br />　　同上，解压你下载到硬盘上的.zip文件，使用上面相同的目录C:j2me，现在那个目录结构应该像：<br /><br />　　C:j2me<br />　　|<br />　　j2me_cldc<br />　　midp-fcs<br /><br />　　<b>配置软件</b><br /><br />　　一、更新 PATH<br /><br />　　PATH环境变量是 Windows操作系统使用来定位可执行程序的，我们需要更新 PATH来指向 Java编译程序和 CLDC、 MIDP程序的路径。<br /><br />　　（1）更新 JDK的PATH<br /><br />　　a、Windows 2000或 Windows NT系统<br /><br />　　　· 从控制面板中选择系统<br /><br />　　　· 点击"高级"，再点击"环境变量"<br /><br />　　　· 找到 PATH，点入，在最后添加JDK安装路径的&#x8;in目录，假设你安装 JDK是 1.3版本并选择默认安装路径，你将添加：C:jdk1.3<br /><br />　　b、Windows 98或 Windows 95<br /><br />　　如果使用的是Windows 98或 Windows 95系统，请在C盘跟目录下的Autoexec.bat文件的最后面加上以下两行： 
<table width="500" align="center" bgcolor="#ebe9eb" border="0"><tbody><tr><td>set path=c:jdk1.3&#x8;in;%path%<br />set classpath=.;</td></tr></tbody></table><br />　　（2）更新 CLDC路径<br /><br />　　你还需要更新你的PATH环境变量来指向存放 CLDC可执行文件的目录。按照上面概述的相同的步骤来添加到PATH中：<br /><br />　　C:j2mej2me_cldc&#x8;in<br /><br />　　（3）更新 MIDP路径<br /><br />　　同上面那样，更新 PATH环境来指出存放 MIDP可执行文件的目录;这个文件是用于测试你的 MIDlet的移动电话模拟器。<br /><br />　　按照上面概述的相同的步骤来添加到PATH中C:j2memidp-fcs&#x8;in<br /><br />　　二、更新 CLASSPATH环境变量<br /><br />　　CLASSPATH告诉 Java编译程序到什么地方搜索那些不是 JDK平台本身附带的类库，在本例中，我们需要更新 CLASSPATH来指向MIDP类。你还需要有当前目录的引用(".")，作为CLASSPATH的一部分，按照上面概述的相同的步骤,更新CLASSPATH: CLASSPATH=C:j2memidp-fcsclasses;. - 注意最后的点"."表示当前的工作目录。<br /><br />　　三、添加SCREEN_DEPTH环境变量<br /><br />　　MIDP含有一个测试 MIDlet用的移动设备模拟器，这个模拟器可以以有色模式运行，也可以运行于黑白两色构成的灰度梯度模式。为了指定颜色数，你可以添加环境变量 SCREEN_DEPTH。例如：<br /><br />　　SCREEN_DEPTH=8<br /><br />　　添加这个环境变量的方法与处理 PATH和 CLASSPATH变量的方法类似。<br /><br />　　SCREEN_DEPTH值和颜色对应表 
<table cellspacing="0" width="500" align="center" border="1"><tbody><tr><td>值</td><td>颜色数</td></tr><tr><td height="12">1 </td><td height="12">2 </td></tr><tr><td>2 </td><td>4 </td></tr><tr><td height="3">4 </td><td height="3">16 </td></tr><tr><td>8 </td><td>256</td></tr></tbody></table><br />　　<b>测试安装</b><br /><br />　　在编写一个 MIDlet之前，让我们检查一下是否所有的软件都已正确地安装。<br /><br />　　1. 进入命令行<br /><br />　　2. 测试CLDC安装，键入preverify并按回车键。 
<table width="500" align="center" border="0"><tbody><tr><td><a href="http://images.csdn.net/20050808/134a98ea-f15d-4fc7-962e-a1e4147137b3.gif" target="_blank"><img alt="" src="http://images.csdn.net/20050808/134a98ea-f15d-4fc7-962e-a1e4147137b3.gif" border="0" /></a><a href="http://gd.91.com/ftbPic/2005/08/01/6363451f-7af0-41ac-ba62-39a80912bb25.gif" target="_blank"></a></td></tr></tbody></table>　3. 测试 MIDP安装，键入 midp并按回车键。应该弹出一个窗口，如下图所示： 
<table width="164" align="center" border="0"><tbody><tr><td><a href="http://images.csdn.net/20050808/5762de42-42c0-4d60-9f7e-2d2bb89509a2.jpg" target="_blank"><img alt="" src="http://images.csdn.net/20050808/5762de42-42c0-4d60-9f7e-2d2bb89509a2.jpg" border="0" /></a></td></tr></tbody></table><br />　　4. 测试 JDK安装，键入 java -version并按回车键，屏幕将出现下面的样子。 
<table width="500" align="center" border="0"><tbody><tr><td><a href="http://images.csdn.net/20050808/9d4fcc10-de01-4520-b313-e7760b985c22.gif" target="_blank"><img alt="" src="http://images.csdn.net/20050808/9d4fcc10-de01-4520-b313-e7760b985c22.gif" border="0" /></a></td></tr></tbody></table><br />　　开发一个MIDlet程序 
<table width="500" align="center" border="0"><tbody><tr><td><a href="http://images.csdn.net/20050808/b03b0d7a-aa79-472a-86c9-86492e7b4761.jpg" target="_blank"><img alt="" src="http://images.csdn.net/20050808/b03b0d7a-aa79-472a-86c9-86492e7b4761.jpg" border="0" /></a></td></tr></tbody></table><br />　　在编写MIDlet程序之前我还要再说两句，前面我也说过了MIDP程序称为MIDlet，这可能因为所有的 MIDlet都是扩展 javax.microedition.midlet.MIDlet类 (正象 Java applet扩展 Applet类一样) 除了从键盘或点击设备上接受输入的信息以外， MIDLet类还提供用于激活、暂停和终结 MIDlet的接口，即分别是startApp()、pauseApp()和destroyApp() 方法。startApp()方法在概念上与 Java applet的 start()方法类似，当MIDlet启动时它被调用，而且在一个MIDlet暂停之后恢复时也被调用。<br /><br />　　另外一个值得注意的类是javax.microedition.lcdui.Command类。这个类定义了好几个移动设备通常使用的语义类型： BACK、CANCEL、EXIT、HELP、ITEM、MENU、OK、SCREEN和STOP。通过 javax.microedition.lcdui.Displayable类（所有的 J2ME UI组件的父类）中的addCommand()方法把这些命令添加到用户界面上。addCommand()方法包括一个优先级参数，允许应用程序提示运行时刻环境应当按照什么顺序显示什么内容。在大多数环境中，如果两个相同类型的命令被使用相同的优先级水平添加的话，环境将显示一个菜单 " menu "选项并允许用户从多个命令选项中选择。<br /><br />　　大家是不是心里都痒痒的了，好，让我们开始编写一个非常简单的 MIDlet吧，这个 MIDlet将创建一个带有一则消息的文本框。我们还要添加一个命令按钮用于退出这个 MIDlet。<br /><br />　　<b>一、编写 Java源代码</b><br /><br />　　创建一个新目录来保存你以后编写的MIDlet，例如 c:midlets，在这个目录里再创建一个叫myMIDlet的目录，使用任何文本编辑器创建一个名为 simpleMIDlet.java的文件并输入下面这一段 Java源代码。把这个文件保存在c:midletsmyMIDlet目录 (或者任何你选择的目录)。<br />代码段1 
<table width="500" align="center" bgcolor="#ebe9eb" border="0"><tbody><tr><td>simpleMIDlet.java<br /><br />import javax.microedition.midlet.*;<br />import javax.microedition.lcdui.*;<br /><br />public class simpleMIDlet extends MIDlet implements CommandListener<br />{<br />private Display display; // 引用MIDlet的Display 对象<br />private TextBox tbxMain; // Textbox 显示一条消息<br />private Command cmdExit; // 设定按钮用于退出MIDlet<br /><br />// MIDlet构造程序<br />public simpleMIDlet()<br />{<br />display = Display.getDisplay(this);<br /><br />cmdExit = new Command("Exit", Command.SCREEN, 1);<br /><br />tbxMain = new TextBox("Simple MIDlet", "Welcome ", 50, 0);<br />tbxMain.addCommand(cmdExit);<br />tbxMain.setCommandListener(this);<br />}<br /><br />// 被应用程序管理器调用来启动MIDlet。<br />public void startApp()<br />{<br />display.setCurrent(tbxMain);<br />}<br /><br />// 一个必要的方法<br />public void pauseApp()<br />{ }<br /><br />file://一个必要的方法<br />public void destroyApp(boolean unconditional)<br />{ }<br /><br />file://检查一下是否选择了退出命令<br />public void commandAction(Command c, Displayable s)<br />{<br />if (c == cmdExit)<br />{<br />destroyApp(false);<br />notifyDestroyed();<br />}<br />}<br />}</td></tr></tbody></table><br />　　此时，先不必担心每行代码是做什么用的，把注意力放在开发这一整个环节中。<br /><br />　　<b>二、编译并预验证（preverify）</b><br /><br />　　现在你必须编译这个 java源文件并且 preverify生成的.class文件。<br /><br />　　1.编译源代码<br /><br />　　进入命令行形式，进入你保存文件的项目目录，使用下面的命令编译程序。使用下面的命令编译程序。 
<table width="579" align="center" bgcolor="#ebe9eb" border="0"><tbody><tr><td height="21">avac -bootclasspath c:j2memidp-fcsclasses simpleMIDlet.java　 </td></tr></tbody></table><br />　　选项 - bootclasspath C： j2memidp - fcsclasses指定了 Java自举(启动)类文件目录。我们必须自己指向midp类，否则javac会使用默认的JDK类库去编译MIDlet程序。不出问题的话，就能顺利地编译simpleMIDlet.java生成simpleMIDlet.class文件 (默认情况下，生成的.class位于 Java源文件所在的目录）。<br /><br />　　2.预验证类文件。 
<table width="557" align="center" border="0"><tbody><tr bgcolor="#ebe9eb"><td>preverify -classpath c:j2memidp-fcsclasses;. -d . simpleMIDlet</td></tr></tbody></table><br />　　选项" -classpath C:j2memidp-fcsclasses;." 指定了到哪里去寻找用于预验证的.class文件。这包括需要用来做验证处理的 MIDP类 (通过 c:j2memidp-fcsclasses指定 )和你的类文件，它位于当前目录 (就是"."指定的)。<br /><br />　　选项"-d." 告诉预验证器把验证过的类文件放在什么地方。这一点"." 指当前目录，即原始的类文件相同的位置。<br /><br />　　注意：前面的 preverify命令行选项将用一个新的、预验证过的类文件覆盖原先的类文件。你可以分两个目录，一个用来保存通过编译的类文件，另一个用来保存通过预验证创建的类文件。但是没有经过预验证的类文件是不能被应用程序管理器载入的。<br /><br />　　3、运行 MIDlet<br /><br />　　我们现在准备在移动设备模拟器中运行 MIDlet，如果你现在还处在命令行方式，请输入 
<table width="500" align="center" bgcolor="#ebe9eb" border="0"><tbody><tr><td>midp firstMIDlet</td></tr></tbody></table><br />　　应该可以看到下面的输出结果：<br /><br /><br /><span class="f14"><br />　　<b>第二节 封装MIDlet</b><br /><br />　　下面我想谈谈封装MIDlet的相关知识，即介绍一下 MIDlet套件以及Java档案和应用程序描述器文件，为了说明方便，我们还将写一个MIDlet程序并利用上面介绍的那个MIDlet程序，并创建JAR文件和JAD文件来封装这些程序。我们还要看着如何使用 Java程序包改变我们的开发过程。最后你将学习如何从一个Web服务器上访问 MIDlet。<br /><br />　　<b>MIDlet套件</b><br /><br />　　虽然把MIDlet封装进 Java档案文件(JAR)并不一定必要，但这是发布 J2ME/MIDP应用程序最常见的方法。MIDlet套件是一个MIDlet中所有的文件以及作为 MIDlet一部分的必需的资源的集合。MIDlet套件由以下几部分组成：<br /><br />　　1、附在JAR文件中的 Java类文件， <br /><br />　　2、描述 JAR文件内容的清单文件 <br /><br />　　3、附在 JAR文件中的资源(如图象)和Java应用程序描述符文件(JAD) <br /><br />　　4、应用程序管理器<br /><br />　　应用程序管理器是一个移动设备上的软件程序，这个应用程序与具体的设备有关，并且由设备的生产商实现。它负责安装、运行以及从设备上删除 MIDlet，而提供错误处理支持。这个应用程序管理器同时还提供一个可选界面，允许用户启动、终止以及删除 MIDlet。<br /><br />　　<b>Java档案文件</b><br /><br />　　一个商品化的、封装过应用程序通常由许多文件构成。除了 Java类以外，其他文件诸如图像和应用程序数据即通常所说的资源，也可能是这个程序包的一部分。你把所有这些信息捆绑进一个整体，就称为 JAR文件。<br /><br />　　除了类和资源文件，一个 JAR文件还包括描述 JAR内容的清单文件。清单文件名为 manifest.mf，储存在 JAR文件本身中，下面这张表中列出定义在这个清单文件中的所有可用的属性。 
<table cellspacing="0" width="585" align="center" border="1"><tbody><tr><td colspan="2"><b>表 1</b></td></tr><tr><td width="215"><div align="center">属性</div></td><td valign="center" width="360"><div align="center">用途</div></td></tr><tr><td width="215">MIDlet-Name</td><td width="360">MIDlet程序包的名称。例如“Game Pack”</td></tr><tr><td width="215">MIDlet-Version</td><td width="360">MIDlet的版本号</td></tr><tr><td width="215">MIDlet-Vendor</td><td width="360">MIDlet的创建者或提供商</td></tr><tr><td width="215">MIDlet-Icon</td><td width="360">应用程序管理器把这个图标与 MIDlet-Name相关联，这是一个图形文件，以 PNG图象格式储存。</td></tr><tr><td width="215">MIDlet-Description</td><td width="360">描述 MIDlet的文本</td></tr><tr><td width="215">MIDlet-Info-URL</td><td width="360">可能提供更多MIDlet和/或供应商信息的 URL</td></tr><tr><td width="215">MIDlet-<n></n></td><td width="360">这个属性包括三段信息： ??MIDlet名称 ??用于这个 MIDlet的图标(可选) ??应用程序管理器将调用来加载这个 MIDlet的类名 在我们的“ Game Pack”例子中，有两个条目： MIDlet-1: KOF, /images/kof.png, kof.kofMIDlet MIDlet-2: Golf, /images/golf.png, golfMIDlet</td></tr><tr><td width="215">MIDlet-Jar-URL</td><td width="360">JAR文件的 URL</td></tr><tr><td width="215">MIDlet-Jar-Size</td><td width="360">JAR文件的大小</td></tr><tr><td width="215">MIDlet-Data-Size</td><td width="360">持久数据存储必需的最小字节数</td></tr><tr><td width="215">MicroEdition-Profile</td><td width="360">MIDlet需要哪一种 J2ME简表</td></tr><tr><td width="215">MicroEdition-Configuration</td><td width="360">MIDlet需要哪一种 J2ME配置</td></tr></tbody></table>　　这些属性并不是全部都需要，可是，没有下面列出的这六个，应用程序管理器就会拒绝加载这个 JAR。<br /><br />　　　MIDlet-Name <br /><br />　　　MIDlet-Version <br /><br />　　　MIDlet-Vendor <br /><br />　　　MIDlet-<n></n><br /><br />　　　MicroEdition-Profile <br /><br />　　　MicroEdition-Configuration <br /><br />　　这里有一个简单的清单文件的例子：<br /><br />　　　MIDlet-Name: KOF2001<br /><br />　　　MIDlet-Version: 1.0<br /><br />　　　MIDlet-Vendor: NeoRage Corporation Inc.<br /><br />　　　MIDlet-1: kof, /images/kof.png, kof.kofMIDlet<br /><br />　　　MicroEdition-Profile: MIDP-1.0<br /><br />　　　MicroEdition-Configuration: CLDC-1.0<br /><br />　　<b>Java应用程序描述器文件（JAD）</b><br /><br />　　虽然没有必要，你仍然可以在 JAR文件中包含一个 JAD文件,就像清单文件一样，这个文件也包含 MIDlet的信息。创建一个 JAD文件是基于两个原因。<br /><br />　　1、向应用程序管理器提供信息，说明 JAR文件的内容，使用这些信息，就可以判断一个 MIDlet是否适合运行在这个设备上。例如，通过查看属性 MIDlet-Data-Size，应用程序管理器可以确定 MIDlet是否需要比设备可以提供的更多的内存。 <br /><br />　　2、提供一种方法，可以把参数传送到 MIDlet而不必更改 JAR文件,在本文的后半段我们将看一个这样的例子。 <br /><br />　　JAD文件使用表 1中相同的属性。如果你需要创建你自己的属性，也可以办得到，只要使用不以 MIDlet为开头的属性名就可以了，下面的 showProperties.jad文件就是自定义属性的例子。和清单文件一样，有某些属性必须被定义，如果这些属性不可用的话，应用程序管理器将不加载这个 MIDlet，它们是：<br /><br />　　　MIDlet-Name <br /><br />　　　MIDlet-Version <br /><br />　　　MIDlet-Vendor <br /><br />　　　MIDlet-<n></n><br /><br />　　　MIDlet-Jar-URL <br /><br />　　　MIDlet-Jar-Size <br /><br />　　MIDlet-Name、MIDlet-Version和MIDlet-Vendor的值必须与 JAR中的清单文件中相同的属性的值一致。可能看出，如果在这两个文件有什么不同的话，申请管理器不也会加载这个 JAR。<br /><br />　　除了这些属性以外，如果两个文件中的另外名称相同的属性，但是属性值不相同的，将优先采取应用程序描述器文件 ( JAD )属性。<br /><br />　　MIDP 1.0规范没有规定 MIDlet-n属性是 JAD文件的必需属性。可是，没有这个属性，就没有办法在设备模拟器中预览 MIDlet。在两个文件中包含这个属性没有问题，并且事实上，那么做可以更清楚看出这些文件是怎样关联的。因此，出于完整性考虑，这里的所有离子都将在JAD文件中包含MIDlet-n属性。因此，出于完整性考虑，这里的全部例子都将在 JAD文件中包含 MIDlet-n属性。<br /><br />　　下面是一个非常简单的例子：<br /><br />　　　MIDlet-Name: Note Pad<br /><br />　　　MIDlet-Version: 1.0<br /><br />　　　MIDlet-Vendor: ABC WorkGroup.<br /><br />　　　MIDlet-Jar-URL: http://www.abcworkgroup.com/MIDlets/notepad.jar<br /><br />　　　MIDlet-Jar-Size: 26248<br /><br />　　　MIDlet-1: NotePad, /images/NotePad.png, NotePad.Main<br /><br />　　<b>从MIDlet中访问 JAR/JAD属性</b><br /><br />　　一个MIDlet程序可以访问所有的定义在清单文件(在JAR文件中）和JAD文件的属性。返回属性信息的方法及所在的完整的程序包名是javax.microedition.midlet.MIDlet.getAppProperty(String name)<br /><br />　　下面是一个例子，从jar/jad文件中读出并打印属性值。<br /><br />　　showProperties.jar中的 manifest.mf文件的内容如下： 
<table width="500" align="center" bgcolor="#ebe9eb" border="0"><tbody><tr><td>MIDlet-Name: Show Properties MIDlet<br />MIDlet-Version: 1.0.1<br />MIDlet-Vendor: ABC WorkGroup.<br />MIDlet-1: ShowProps, , showProperties<br />MicroEdition-Profile: MIDP-1.0<br />MicroEdition-Configuration: CLDC-1.0<br />MIDlet-Description: A simple property list example<br />MIDlet-Data-Size: 1500</td></tr></tbody></table><br />　　showProperties.jad的内容： 
<table width="500" align="center" bgcolor="#ebe9eb" border="0"><tbody><tr><td>MIDlet-Name: Show Properties MIDlet<br />MIDlet-Version: 1.0.1<br />MIDlet-Vendor: ABC WorkGroup.<br />MIDlet-Jar-URL: file://showProperties.jar<br />MIDlet-Jar-Size: 1132<br />MIDlet-1: ShowProps, , showProperties<br />JadFile-Version: 1.5<br />MIDlet-Data-Size: 500</td></tr></tbody></table><br />　　showProperties.java的源程序: 
<table width="500" align="center" bgcolor="#ebe9eb" border="0"><tbody><tr><td>import javax.microedition.midlet.*;<br />public class showProperties extends MIDlet<br />{<br />public void startApp() throws MIDletStateChangeException<br />{<br />System.out.println("Vendor: " + getAppProperty("MIDlet-Vendor"));<br />System.out.println("Description: " + getAppProperty("MIDlet-Description"));<br />System.out.println("JadFile Version: " + getAppProperty("JadFile-Version"));<br />System.out.println("MIDlet-Data-Size: " + getAppProperty("MIDlet-Data-Size"));<br />}<br />public void pauseApp()<br />{ }<br />public void destroyApp(boolean unconditional)<br />{ }<br />}</td></tr></tbody></table><br />　　下面这些是一些比较重要的地方：<br /><br />　　manifest.mf文件作为 JAR文件 showProperties.jar的一部分储存的。 <br /><br />　　JAD文件showProperties.jad使用MIDlet-Jar-URL: file://showProperties.jar 引用showProperties.jar。 <br /><br />　　当你浏览这个 JAD文件的时候，它使用上面那个命令找出相关联的 JAR文件并读取清单文件的内容。 <br /><br />　　属性MIDlet-Name、MIDlet-Version和MIDlet-Vendor 既在 JAR中的清单文件中又在 JAD文件中，这些属性的值都必须完全相同。 <br /><br />　　MIDlet-Description属性来自清单文件，是可选的。 <br /><br />　　JadFile Version属性不在表 1中，因此它是一个自定义属性。因为 JAD文件内的属性可从MIDlet访问，所以你可以不用改变 JAR文件而添加属性到 JAD中。 <br /><br />　　属性 MIDlet-Data-Size在清单文件和 JAD文件中都有，就像前面指出的那样，当两个文件中有完全相同的属性时， JAD文件中的属性将使用。切记这不适用于MIDlet-Name、MIDlet-Version和MIDlet-Vendor。 <br /></span><br /><font style="BACKGROUND-COLOR: #f6fafb">　　</font><b>在 MIDlet套件中封装多个 MIDlet</b><br /><br /><font style="BACKGROUND-COLOR: #f6fafb">　　在我们谈论如何封装多个 MIDlet之前，我们先得多写几个可用的MIDlet。下面有两个简单的 MIDlet。第一个显示一个带有简短消息的文本框组件。<br /><br />　　MIDlet1.java源程序： </font><table width="500" align="center" bgcolor="#ebe9eb" border="0"><tbody><tr><td>import javax.microedition.midlet.*; <br />import javax.microedition.lcdui.*; <br />public class MIDlet1 extends MIDlet implements CommandListener<br />{<br />　private Display display; // 引用Display对象 <br />　private TextBox tbxMain; // 显示消息的文本框 <br />　private Command cmdExit; // 退出MIDlet的命令 <br />　// 构造程序 <br />　public MIDlet1() <br />　{ <br />　　display = Display.getDisplay(this); <br />　　cmdExit = new Command("Exit", Command.SCREEN, 1); <br />　　tbxMain = new TextBox("MIDlet 1", "Welcome", 50, 0); <br />　　tbxMain.addCommand(cmdExit); <br />　　tbxMain.setCommandListener(this); <br />　} <br />　// 启动MIDlet时由应用程序管理器调用 <br />　public void startApp()<br />　{<br />　　display.setCurrent(tbxMain);<br />　}<br />　// 一个必要的方法 <br />　public void pauseApp()<br />　{ }<br />　// 一个必要的方法 <br />　public void destroyApp(boolean unconditional)<br />　{ }<br />　file://检查一下是否选择Exit命令 <br />　public void commandAction(Command c, Displayable s)<br />　{<br />　　if (c == cmdExit)<br />　　{<br />　　　destroyApp(false);<br />　　　notifyDestroyed();<br />　　}<br />　}<br />}</td></tr></tbody></table><br />　　第二个MIDlet使用List组件显示消息(MIDlet2.java): 
<table width="500" align="center" bgcolor="#ebe9eb" border="0"><tbody><tr><td>import javax.microedition.midlet.*;<br />import javax.microedition.lcdui.*;<br />public class MIDlet2 extends MIDlet implements CommandListener<br />{<br />　private Display display; file://引用Display对象 <br />　private List lstMain;<br />　private Command cmdExit; // 退出 MIDlet的命令 <br />　// 构造程序 <br />　public MIDlet2()<br />　{<br />　　display = Display.getDisplay(this);<br />　　cmdExit = new Command("Exit", Command.SCREEN, 1);<br />　　lstMain = new List("MIDlet 2", Choice.IMPLICIT);<br />　　lstMain.append("Welcome Back", null);<br />　　lstMain.addCommand(cmdExit);<br />　　lstMain.setCommandListener(this);<br />　}<br />　file://启动MIDlet时由应用程序管理器调用 <br />　public void startApp()<br />　{<br />　　display.setCurrent(lstMain);<br />　}<br />　file://一个必要的方法 <br />　public void pauseApp()<br />　{ }<br />　file://一个必要的方法 <br />　public void destroyApp(boolean unconditional)<br />　{ }<br />　file://检查一下是否选择Exit命令 <br />　public void commandAction(Command c, Displayable s)<br />　{<br />　　if (c == cmdExit)<br />　　{<br />　　　destroyApp(false);<br />　　　notifyDestroyed();<br />　　}<br />　}<br />}</td></tr></tbody></table><br /><br />　　第一个程序名为 MIDlet1.java，第二个程序名为 MIDlet2.java。在你保存这些文件的目录里，运行下列命令编译并预验证这些文件。 
<table width="548" align="center" bgcolor="#ebe9eb" border="0"><tbody><tr><td>javac -bootclasspath c:mefcs*.java <br />preverify -classpath c:mefcs;. -d . MIDlet1 MIDlet2 <br />jar cvfm MIDlets.jar manifest.txt MIDlet1.class MIDlet2.class spin.png</td></tr></tbody></table><br />　　<b>创建 JAR文件</b><br /><br />　　创建一个新文件，取名为 manifest.txt，然后输入如下内容： 
<table width="500" align="center" bgcolor="#ebe9eb" border="0"><tbody><tr><td>MIDlet-Name: MIDlet Examples<br />MIDlet-Version: 1.0<br />MIDlet-Vendor: My Corporation Inc.<br />MIDlet-1: MIDlet1, /spin.png, MIDlet1<br />MIDlet-2: MIDlet2, /spin.png, MIDlet2<br />MicroEdition-Profile: MIDP-1.0<br />MicroEdition-Configuration: CLDC-1.0</td></tr></tbody></table><br />　　运行下列命令创建一个 JAR文件： 
<table width="566" align="center" bgcolor="#ebe9eb" border="0"><tbody><tr><td>jar cvfm MIDlets.jar manifest.txt MIDlet1.class MIDlet2.class spin.png</td></tr></tbody></table><br />　　这将创建一个名为 MIDlets.jar的 JAR文件，包括 manifest.txt文件和上面两个类文件。<br /><br />　　<font color="#ff0000"><b>注意：</b></font> JAR中的清单文件名应是 manifest.mf。<br /><br />　　<b>创建 JAD文件</b><br /><br />　　创建一个新文件，取名 MIDlets.jad： 
<table width="500" align="center" bgcolor="#ebe9eb" border="0"><tbody><tr><td>MIDlet-Name: MIDlet Examples <br />MIDlet-Version: 1.0 <br />MIDlet-Vendor: My Corporation Inc. <br />MIDlet-Description: Two simple examples to show how to compile and run a MIDlet <br />MIDlet-Jar-URL: http://localhost/MIDlets.jar <br />MIDlet-Jar-Size: 2604 <br />MIDlet-1: MIDlet1, /spin.png, MIDlet1 <br />MIDlet-2: MIDlet2, /spin.png, MIDlet2</td></tr></tbody></table><br />　　注意这两个 MIDlet的引用： 
<table width="500" align="center" bgcolor="#ebe9eb" border="0"><tbody><tr><td>MIDlet-1: MIDlet1, /spin.png, MIDlet1<br /><br />MIDlet-2: MIDlet2, /spin.png, MIDlet2</td></tr></tbody></table><br />　　上面每一行都包括在设备上显示的 MIDlet名 ( MIDlet1和 MIDlet2 )；在每个MIDlet名旁边，应用程序管理器都会显示一个图象文件；以及启动 MIDlet的类文件。<br /><br />　　<b>运行 MIDlet</b><br /><br />　　你既可以从一个局域网文件系统也可以从一个 Web服务器中运行MIDlet,现在我将分别介绍一下。<br /><br />　　从文件系统运行<br /><br />　　键入下列命令来预览MIDlet： 
<table width="500" align="center" bgcolor="#ebe9eb" border="0"><tbody><tr><td>midp -transient file://MIDlets.jad</td></tr></tbody></table><br />　　-transient选项告诉模拟器，你想运行一个指定 url中可找到的描述文件。在本例中，file://MIDlets.jad，这当前目录查找 MIDlets.jad。如果有必要的话，你还可以给出一个 JAD文件的完整的路径。比如说，我的 JAD文件的完整路径是 
<table width="500" align="center" bgcolor="#ebe9eb" border="0"><tbody><tr><td>file://J2ME/MIDlets/welcome.jad</td></tr></tbody></table><br />　　下面的图片显示了应用程序管理器的主画面和 MIDlet1、 MIDlet2的输出。 
<table width="500" align="center" border="0"><tbody><tr><td><a href="http://images.csdn.net/20050808/0eef8070-a91f-430a-b538-445e36b5c8d9.gif" target="_blank"><img alt="" src="http://images.csdn.net/20050808/0eef8070-a91f-430a-b538-445e36b5c8d9.gif" border="0" /></a></td></tr></tbody></table><br />　　从 Web服务器上运行<br /><br />　　你还可以从一个 Web服务器上运行 MIDlet，在上载 JAR和 JAD文件之后，通过改变 url访问 JAD文件： 
<table width="500" align="center" bgcolor="#ebe9eb" border="0"><tbody><tr><td>midp -transient http://localhost/MIDlets.jad</td></tr></tbody></table><br />　　这将访问运行在我的电脑上的Web服务器上的 MIDlets.jad文件，如果你把文件上传到互联网上的 Web服务器，只需简直改变适当域名： 
<table width="500" align="center" bgcolor="#ebe9eb" border="0"><tbody><tr><td>midp -transient http://www.yourwebserver.com/path/MIDlets.jad</td></tr></tbody></table><br />　　使用 Java程序包的项目管理<br /><br />　　按照下列步骤创建最后一个MIDlet：<br /><br />　　1. 创建用于新项目的目录，我使用的名称为 MIDletPackage，是c:me的子目录。<br /><br />　　2. 在新建目录内，创建三个新的子目录： jclasses、 pclasses、 resources<br /><br />　　有了这些附加的目录，能够很容易找到特定的文件。例如，所有的图象文件和其他资源都放入 /resources子目录；所有的由 Java编译程序创建的类文件都置于 /jclasses子目录；经过预验证的类置于/pclasses子目录中。下面是我的系统中的目录结构： 
<table width="500" align="center" border="0"><tbody><tr><td>c:j2me <br />| <br />MIDletPackage =&gt; Java 源代码和manifest.txt文件 <br />| <br />jclasses =&gt; 从Java编译器编译的类 <br />pclasses =&gt;经过预验证的类 <br />resources =&gt;资源文件 (图像文件等)<br /></td></tr></tbody></table><br />　　3. 更新文件：复制 Java源文件( MIDLet1.java和 MIDlet2.java)到 MIDletPackage目录，并在每个文件头部添加 package语句，如下：而且，如果你已经使用一个图象文件的话，把这个文件复制进 resources目录中。 
<table width="500" align="center" bgcolor="#ebe9eb" border="0"><tbody><tr><td>MIDlet1.java: <br />package simpleMIDlets; <br />import javax.microedition.midlet.*; <br />import javax.microedition.lcdui.*; <br />public class MIDlet1 extends MIDlet implements CommandListener <br />{<br /><br />...<br /><br />}<br /><br />MIDlet2.java: <br /><br />package simpleMIDlets; <br />import javax.microedition.midlet.*; <br />import javax.microedition.lcdui.*; <br />public class MIDlet2 extends MIDlet implements CommandListener <br /><br />{<br /><br />...<br /><br />}</td></tr></tbody></table><br />　　4、参考图象文件和类文件的新的位置更新 manifest.txt和 JAD文件。 
<table width="500" align="center" bgcolor="#ebe9eb" border="0"><tbody><tr><td>manifest.txt: <br />MIDlet-Name: MIDlet Examples <br />MIDlet-Version: 1.0 <br />MIDlet-Vendor: My Corporation Inc. <br />MIDlet-1: MIDlet1, /resources/spin.png, simpleMIDlets.MIDlet1 <br />MIDlet-2: MIDlet2, /resources/spin.png, simpleMIDlets.MIDlet2 <br />MicroEdition-Configuration: CLDC-1.0 <br />MicroEdition-Profile: MIDP-1.0 <br /><br /><br />MIDlets.jad: <br />MIDlet-Name: MIDlet Examples <br />MIDlet-Version: 1.0 <br />MIDlet-Vendor: My Corporation Inc. <br />MIDlet-Description: Packaging multiple MIDlets <br />MIDlet-Jar-URL: http://localhost/MIDlets.jar <br />MIDlet-Jar-Size: 2884 <br />MIDlet-1: MIDlet1, /resources/spin.png, simpleMIDlets.MIDlet1 <br />MIDlet-2: MIDlet2, /resources/spin.png, simpleMIDlets.MIDlet2</td></tr></tbody></table><br />　　注意MIDlet-1和MIDlet-2的更改，被引用的类文件使用 simpleMIDlets.MIDlet1和 simpleMIDlets.MIDlet2包名。<br /><br />　　5、编译：编译源程序： 
<table width="500" align="center" bgcolor="#ebe9eb" border="0"><tbody><tr><td>javac -bootclasspath c:mefcs-d jclasses *.java</td></tr></tbody></table><br />　　-d选项告诉编译程序，把类文件写入 jclasses目录。<br /><br />　　6、预验证： 
<table width="500" align="center" bgcolor="#ebe9eb" border="0"><tbody><tr><td>preverify -classpath c:mefcs; -d pclasses jclasses</td></tr></tbody></table><br />　　-d选项告诉预验证器把经过预验证的类保存在 pclasses目录下。最后的 jclasses告诉预验证器到什么地方寻找那些要预验证的类。<br /><br />　　7、创建 JAR：运行 jar程序： 
<table width="500" align="center" border="0"><tbody><tr bgcolor="#ebe9eb"><td>jar cvfm MIDlets.jar manifest.txt -C pclasses . resources　</td></tr></tbody></table><br />　　创建一个名为 MIDlets.jar的文件，使用文件 manifest.txt作为清单文件的内容 (一个名为 manifest.mf的文件将被保存在 JAR中)。 <br /><br />　　运行MIDlet，有两种情况： <br /><br />　　（1）从文件系统中运行MIDlet： 
<table width="500" align="center" bgcolor="#ebe9eb" border="0"><tbody><tr><td>midp -transient file://MIDlets.jad</td></tr></tbody></table><br />　　（2）从web服务器上运行MIDlet：把JAR文件和JAD文件上传到web服务器，输入下面的命令来浏览MIDlet： 
<table width="500" align="center" border="0"><tbody><tr bgcolor="#ebe9eb"><td>midp -transient http://localhost/MIDlets.jad</td></tr></tbody></table></dd>
<img src ="http://www.blogjava.net/zjw-albert/aggbug/57136.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zjw-albert/" target="_blank">zjw_albert</a> 2006-07-07 14:59 <a href="http://www.blogjava.net/zjw-albert/archive/2006/07/07/57136.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转载]J2ME之谜</title><link>http://www.blogjava.net/zjw-albert/archive/2006/07/07/57135.html</link><dc:creator>zjw_albert</dc:creator><author>zjw_albert</author><pubDate>Fri, 07 Jul 2006 06:57:00 GMT</pubDate><guid>http://www.blogjava.net/zjw-albert/archive/2006/07/07/57135.html</guid><wfw:comment>http://www.blogjava.net/zjw-albert/comments/57135.html</wfw:comment><comments>http://www.blogjava.net/zjw-albert/archive/2006/07/07/57135.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/zjw-albert/comments/commentRss/57135.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zjw-albert/services/trackbacks/57135.html</trackback:ping><description><![CDATA[
		<dl class="ReadArticle">
				<dt>Java嵌入式开发之二 
</dt>
				<dd class="ArticleInfo">2005.08.08  来自：无线空间  syg 
</dd>
				<dd class="ArticleContent">
						<table style="FLOAT: left; MARGIN: 0px 10px 10px" cellspacing="0" cellpadding="0" align="left" border="0">
								<tbody>
										<tr>
												<td>
														<script type="text/javascript">
																<!--
						csdn_AD_Position_GroupID = "{e025b96b-2fda-4e82-84ef-3e0772838ed3}";
						csdn_AD_Page_Url = document.location;
						csdn_AD_CurrPage_CharSet = "gb2312";
						//-->
														</script>
														<script src="http://ggmm.csdn.net/AD/Show_JavaScript_AD.js" type="text/javascript">
														</script>
														<script language="JavaScript1.1" src="http://ggmm.csdn.net/AD/ShowJavaScriptAD.aspx?show=true&amp;position={e025b96b-2fda-4e82-84ef-3e0772838ed3}&amp;CharSet=gb2312">
														</script>
														<br />
														<script src="http://news.csdn.net/ad/news_textlink.js" type="text/javascript">
														</script>
												</td>
										</tr>
								</tbody>
						</table>
						<center>
								<b>J2ME之谜</b>
						</center>
						<br />
						<br />　　<b>第一节 引言 J2ME概述</b><br /><br />　　到目前为止，大部分人都已非常熟悉 Java 2平台，以及 Sun如何把 Java技术分成三个版本 (标准版、袖珍版以及企业版），Sun 在1999年6月时推出了 Java 2袖珍版 (J2ME)来满足消费电子和嵌入设备的需要。J2ME是为了那些使用有限的能源、有限的网络连接 (常常是无线连接)以及有限图形用户界面能力的设备开发的。它最初的目标是 16位或 32位处理器，16 MHz时钟频率， 512K或更少内存的设备。乍一看之下， J2ME就像一个没有绑定明显主题的松散的应用程序接口和技术规范。我们想通过说它不是什么东西的方法来描述它，它不是一组用于台式机 Java应用程序规范，如果你再观察仔细一些，你会发现所有的 J2ME组件都围绕一个中心，这些中心被称为configuration(配置 ，Sun的市场营销资料也称它们 design centers，设计中心），它们中间的每一个都是用于消费电子和嵌入设备的特别的类。 <br /><br />　　Connected limited device configuration(有限连接设备配置，简称 CLDC ) 这个配置定义了 Java应用程序接口以及支持手持设备的技术，就像 Sun的文档中所描述的那样， " devices that you hold in your hand（你握在手中的设备） " Palm序列手持设备可能是这一领域的设备的最好的例子，特别是它有开发 CLDC的功能以及 Palm设备运行期系统可用。 <br />Connected device configuration(连接设备配置 CDC ) 这个配置定义支持象 Sun文档中所说， " devices that you plug into plug into the wall（你插入墙的设备）的设备的应用程序接口和技术，这样的设备的一个例子可能就是机顶盒。 <br /><br />　　这两种配置不同的地方就在于它们应用于的装置的能力， CLDC设备的处理器能力有限 (与台式机系统比较 )，并且存储器大小一般也只在128 KB到 512 KB之间， 与此同时， CDC系统就不同了，它可能有 32位或 64位处理器，以及有限的存储容量，不过它的下限也得超过512K。 它遵循的原则就是，每个不同的能力硬件的配置都将被不同的虚拟机支持。 基于 CDC的系统使用一个功能强劲的虚拟机，而基于 CLDC系统的使用 KVM (我过会儿会介绍）。<br /><br />　　每个配置代表一种低水平的，基本的应用程序接口，在这两个相似基础之上是 profile（简表），用于特殊设备的额外的应用程序接口。 我想通过看一张来自SUN提供的文档中的图表 (参见图 1 )来解释这其中的关系。 <br /><br /><br /><a href="http://images.csdn.net/20050808/5fdf4f26-3ac0-4012-86a2-99a01c2ac6b7.gif" target="_blank"><img alt="" src="http://images.csdn.net/20050808/5fdf4f26-3ac0-4012-86a2-99a01c2ac6b7.gif" border="0" /></a><br /><font size="2">图一解释 配置和简表的体系结构 J2ME的体系结构被横向地分成三层，纵向分成两部分。配置包括一个控制配置核心类的虚拟机， 具体的 简表位于每个配置之上。</font><br /><p><br /><font size="3">　　J2ME现在定义两个配置， Connected Device configuration(连接设备配置 CDC )和限制性更强的 Connected Limited Device Configuration (有限连接设备配置)。</font> 简表的实现是 Java应用程序接口的一个集合，用于适应被定义配置的应用程序接口提供的服务，简表是一个完整的运行环境，一个在简表上执行的应用程序不需要额外的支持类。 <br /><br />　　J2ME没有定义满足这两种配置的标准化用户接口，Sun也承认现在的消费设备多种多样，用户界面也各不一样，所以定义一个可用于所有用户的界面是一场失败的战争。 J2ME中的用户界面定义在简表中。</p><br /><p>　　<b>第二节 J2ME的体系结构</b><br /><br />　　现在个人计算机系统的数量和种类已经发展到无法控制的地步，请你想一想，你编写的程序运行在“信息家电”舞台的情景吧，这些信息家电包括呼叫器，行动电话，像Palm这样的个人数字助手(PDA)，电视机顶盒，POS终端以及其他的消费电子设备。现在全世界上光是手提电话生产商就有许多，更不用说别的家电设备了，而且每一种家电设备又有不同的特性和界面。所以，你可以想到， Java应用程序的轻便性以及能够解决开发这么许多不同的设备程序的能力，使大家对J2ME有很大的期许。当然，为了更好的开发这些信息家电，就要求把Java的精髓压缩进一个非常小的程序包中，这就是J2ME。 <br /><br />　　J2ME是一种通过许多部件和规范的技术， 这众多的部件和规范帮助 J2ME来满足这众多的消费产品的不同的需要。和所有的爪哇程式语言技术一样，在它的核心属于一种虚拟机。 就像使用所有 Java技术一样，J2ME的核心也在一种虚拟机中。 最初，用于 J2ME应用程序虚拟机的被称作 Kilobyte virtual machine或简称 KVM。就像它名称的含义， KVM比较小，通常只有 128K或更少。这比起我们通常了解和使用的 Java 2标准版 Java虚拟机 ( JVM )的 32 MB来说就小得多了。 <br /><br />　　用于连接虚拟机的是一系列配置和简表，它们提供了用于特定 J2ME环境的类应用程序接口(见图二）。 每个配置和简表处理一般或具体的消费产品，配置和简表规范是由多种多样的设备生产商和用户共同开发并建立的。配置是用于一组通用设备的最小的 Java平台， 常常归为一种横向的设备分组，相对来说，横向分组设备是那些共享相同的内存安排，通信带宽，能量需求以及用户能力的设备，一般认为配置能够提供这众多的设备的所有需求。 <a href="http://images.csdn.net/20050808/a33b16da-4595-4c3f-ae4e-10e2497ed7a0.gif" target="_blank"><img alt="" src="http://images.csdn.net/20050808/a33b16da-4595-4c3f-ae4e-10e2497ed7a0.gif" border="0" /></a><br /><font size="2">图二解释： J2ME层次 Java虚拟机是 J2ME技术的核心，但是配置和简表提供特殊环境的类应用程序接口。配置是用于一组通用设备的最小的 Java平台，而简表则为具体的设备家族或特别的应用程序提供更具体的能力。</font><br /><br /></p><p>　　J2ME领域的新的开发者常常被这些事实困惑的， 事实上， Sun的第一个配置(现在只是一种配置的引用实现 )带有称为 KVM的虚拟机引用实现， KVM满足配置的虚拟机的必要条件。然而， Sun的 KVM也可以被另外一个虚拟机所代替，现在， 正是因为配置和虚拟机结合得有点紧密，因此导致了这么多的混乱。 <br /><br />　　另一方面，简表完善了 配置，为某个具体的设备家族或某个具体的工业片段应用程序提供更高的性能。 换言之， 简表为具体的纵向市场的设备比如说行动电话提供更多的性能。这里的关键就是 简表必须完善 配置， 没有 配置和虚拟机提供核心类应用程序接口和运行期环境的话，简表也不会工作。<br /><br />　　通常，简表为一种给定的垂直分组设备提供用户界面、输入法、持久性机制。这类 简表被认为是发展这些设备应用程序的完整的工具包。我们见到最多的应用程序简表的例子就移动电话简表和个人数字助手(PDA)简表,其他简表为范围宽广的设备提供非常特殊的功能或应用程序可移植性，这方面的例子就是提供远程方法调用 ( RMI )功能的简表和提供统一银行事务的简表。<br /><br />　　虚拟机、 配置、 简表…你是不是已经被搞迷糊了？ 如果这样的话，我们就来简化一下 J2ME体系结构吧。 如果你想为小型信息家电编写 Java应用程序的话，你就需要两个前提：一个 配置和至少一个 简表。 现在， 一般是配置捆绑了虚拟机和一套针对你的平台所能够用的横向分组设备的Java类库。其次，你至少还需要一个 简表来为你的平台提供附加的 Java类，这个 简表通常会为你的设备提供用户界面、输入和数据库类。有了这两个前提，你就了使用 Java为你的设备编写应用程序的基本的J2ME环境。 </p><br /><p>　　<b>第三节 详细谈谈J2ME配置</b><br /><br />　　J2ME可以在好几个不同的配置中进行配置。 就像先前提到的，每个配置为一组通用设备提供最小的 Java平台，到目前为止，只有两种配置规范。通过 Java规范定义的这两种配置是 Connected Limited Device Configuration (有限连接设备配置， CLDC )和 Connected Device Configuration (连接设备配置 CDC )。<br /><br />　　CLDC是为使用较小的存储容量的设备设计的 (参见图3 )。 CLDC用于内存在128到 512K之间的消费电子设备， 这一类别中典型代表的设备包含呼叫器、行动电话、PDA和POS终端；而另一方面， CDC用于比 PC机小但是具有比 512K内存多的设备，这一类设备包括互联网络电视系统、机顶盒、POS系统、汽车导航以及娱乐系统。一般来说， CDC使小型设备只要具有少量的资源，至少比台式机要少的资源就能进行Java编程，而CLDC使小型设备所拥有的资源只要比一张智能卡多一点就可以进行Java编程了。 <a href="http://images.csdn.net/20050808/813248da-d1dc-48f6-8d98-d12665de0f1f.gif" target="_blank"><img alt="" src="http://images.csdn.net/20050808/813248da-d1dc-48f6-8d98-d12665de0f1f.gif" width="620" border="0" /></a><br /><font size="2">图二解释 设备覆盖的范围 J2ME有两个配置CLDC和 CDC，CLDC是为使用较小的存储容量的设备设计的，而CDC用于比 PC机小但是具有比 512K内存多的设备。</font><br /><br />　　除了在容量大小和能力上对虚拟机规定了必要条件，配置还规定了类应用程序接口要包含常见的 java.io、 java.net、 java.util和 java.lang包，配置可能还要包括其他需要的程序包。 <br /><br />　　CLDC<br /><br />　　CLDC起源可以追溯到1999年JavaOne大会上介绍的Sun的第一个袖珍版 Java和第一个 KVM以及相关的类库，虽然 CLDC和所有的配置都满足成为虚拟机的条件，可它本身还不是虚拟机，CLDC的引用实现只是包含在当前的分布中的 KVM。<br /><br />　　根据规范中所说，运行 CLDC的设备应该有 512K或更少的内存空间、一个有限的电源供给 (通常是使用电池）、有限的或断断续续的网络连接性 ( 9600 bps或更少 )以及多样化的用户界面甚至没有用户界面。 通常说来，这个配置是为个人化的、移动的、有限连接信息设备而设计，比如呼叫器、移动电话和 PDA等。<br /><br />　　与 J2SE相比， CLDC缺少下列所说的这些特征：<br /><br />　　AWT（抽象窗口开发包）， Swing或其他图形库 <br /><br />　　用户定义类装载器 <br /><br />　　类实例的最终化 <br /><br />　　弱的引用 <br /><br />　　RMI <br /><br />　　Reflection（映射） <br /><br />　　CLDC有四个包： java.lang、 java.util、 java.io和 javax.microedition。 除了 microedition包以外，其他的这几个包都是J2SE包的核心子集，CLDC采用这些J2SE类库，但是把其中一些在微型设备中用不到类、属性、方法去掉了。因此 CLDC类库有许多细微的差别。 如果您想研究J2SE和 CLDC类库之间的差别，请参阅相关文档，在此就不详细说明了。<br /><br />　　想要理解为什么CLDC去除这么多J2SE中重要的类和特征，请回想一下与 CLDC相关的两条基本原理。首先，它只有 512K的内存空间， 而像RMI和映射需要的内存太大了。 其次，配置必须满足为一组通用设备提供最小的 Java平台。 在个人移动信息设备领域中，许多系统都不能支持 J2SE中的众多的高级特征。 例如，许多消费电子产品不能支持浮点数； 因此 Float（浮点类）和 Double（双精度类）就被删除了。 再看另外一个例子，许多系统没有或不提供访问一个文件系统的功能或权限。 因此与文件有关的类也被丢弃了。又如，错误处理是一个代价非常高的过程处理，在许多消费电子设备中，故障恢复是很难的甚至是不可能的。 所以在 CLDC中，许多错误处理类也被删除了。 <br /><br />　　java.microedition程序包提供了一个一般的结构来替代许多 J2SE网络输入/输出类。 CLDC一般连接器结构还定义了一个 Connector类，允许许多不同类型的连接能够使用静态方法，下表列出使用同一个Connector类创建和打开五种不同类型的连接的方法：<br /><br />　　HTTP Connector.open("http://www.xyz.com");<br /><br />　　套接字 Connector.open("socket://111.222.111.222:9000");<br /><br />　　通讯端口 Connector.open("comm:1;baudrate=9600");<br /><br />　　数据报 Connector.open("datagram://111.222.111.222"); <br /><br />　　文件 Connector.open("file:/xyz.dat");<br /><br />　　一般连接器结构提供给应用程序开发者一个到通用低水平硬件的简单的映射表。成功执行 open语句将返回一个实现一般连接界面的对象。 <br /><br />　　CDC<br /><br />　　CDC涵盖了个人电脑与有至少 512K内存的小型设备之间的中间地带。现在，这一类设备通常是共享的、固定的 (不用移动)网络连接信息设备，像电视机机顶盒，网络电视系统、互联网电话与汽车导航/娱乐系统等等。<br /><br />　　首先，CDC基于 J2SE 1.3应用程序接口，包含所有定义在CLDC规范(包括 javax.microedition程序包)中的Java语言应用程序接口。与CLDC相比， CLDC所有缺少的特性和类在 CDC中都被补齐，包含映射、最终化、所有的错误处理类、浮点数、属性、输入/输出 ( File、 FileInputStream等等 )和弱的引用。 一般说来， CDC中预期的类包括一个J2SE子集和一个完整的 CLDC超集，如图4中所示： <a href="http://images.csdn.net/20050808/7df584f8-3296-4cc0-b53f-73498143b16b.gif" target="_blank"><img alt="" src="http://images.csdn.net/20050808/7df584f8-3296-4cc0-b53f-73498143b16b.gif" border="0" /></a><br /><br />图4 ：J2SE、CLDC和CDC的关系 <br />　　就像使用所有的配置一样，CDC有基层虚拟机的具体的必要条件。 根据 CDC规范，基层虚拟机必须提供实现完整的 Java虚拟机的支持 。 如果虚拟机实现有一个用于激活设备的本地方法的界面，它必须兼容 JNI 1.1版本。 如果虚拟机实现有一个调试界面，它必须兼容 Java虚拟机调试界面 ( JVMDI )规范。 如果虚拟机有一个简表界面，它必须兼容 Java虚拟机简表界面 ( JVMPI )规范。 可见，为了实现这些功能，CDC肯定会变得很大，就不能称其为K虚拟机了，因此，我们通常称用于CDC的虚拟机为 CVM，这里的 C代表 compact、connected、consumer。<br /><br />　　<b>第四节 谈谈J2ME简表</b><br /><br />　　虽然配置为一组通用设备提供了最小的 Java平台，但是应用程序开发者感兴趣的是为一个个别的设备生产应用程序，当他们只是使用配置的话，他们编写的应用程序就会有一些欠缺。 配置必须满足所有的设备的最小的要求， 用户界面、输入机制和数据持久性有高度地设备具体性，每一种设备都有自己的用户界面、输入机制和数据存储方法，这些往往不在配置所满足的最小要求的范围之内。 <br /><br />　　简表为相同消费电子设备的不同的生产商提供了标准化的 Java类库， 事实上，虽然配置规范的开发由 Sun领导，但是许多简表规范仍将继续由特殊设备的供应商领导。 比如说， Motorola领导了行动电话和呼叫器简表规范的开发，又如 Palm 领导 PDA简表的开发。 <br /><br />　　现在，五个已知简表已经有了规范, 记住，每个简表的责任都是为了完善配置的不足，下表列出了这五个简表： 
</p><table cellspacing="0" width="500" align="center" border="1"><tbody><tr><td>简 表</td><td>完善配置</td></tr><tr><td>Mobile information devices profile (MIDP)</td><td>移动电话和呼叫器 CLDC</td></tr><tr><td>Personal digital assistant profile</td><td>Palm和Handspring的PDA 设备 CLDC </td></tr><tr><td>Foundation profile</td><td>用于所有不需要GUI的CDC设备的标准简表 CDC</td></tr><tr><td>Personal profile</td><td>替代PersonalJava的Foundation完善的简表 CDC </td></tr><tr><td>RMI profile </td><td>提供RMI的Foundation完善的简表 CDC </td></tr></tbody></table>　<br />　　现在我想谈一谈另一个Java类库集，它现在差不多可以被认为是另一个简表了。当Sun为Palm开发第一个KVM时，他们需要一组类来 开发Palm的演示程序。这套类库被封装进 com.sun.kjava程序包， 在 CLDC早期的开发中，这些类被广泛的使用来测试和演示 J2ME。因为 kjava是唯一的允许应用程序开发者使用 J2ME和 KVM开发应用程序的类，所以它就被广泛使用了。甚至到了今天，一个用于 PDA或更特殊一点的 Palm的简表多已经在开发中，许多开发者仍然希望使用 kjava类来开发 PDA应用程序。尽管 kjava类不被支持，并且仅仅用于设计测试程序或演示程序，并且它们将被一个即将到来的简表所替代，但是开发者们仍然热衷于使用它来开发。<br /><br />　　MIDP<br /><br />　　Mobile Information Device Profile(移动信息设备简表 ,简称 MIDP )，第一个实现的简表，补充了 CLDC并且提供应用程序语义和控件、用户界面、持久存储器、网络和用于移动电话的计时器、双通道呼叫器和其他无线电设备。 因为 MIDP和 CLDC两者都有引用实现，我们可以使用一个例程来研究一下这个简表。<br /><br />　 下面的例子是一个允许用户输入代表想知道的基金报价的代号的例子。应用程序然后通过 HTTP接到一个金融网站，获得基金报价，把价格储存在一个数据库，然后把价格返回给用户。 
<table width="500" align="center" bgcolor="#ebe9eb" border="0"><tbody><tr><td>// 到如需要的J2ME类<br />import javax.microedition.midlet.*;<br />import javax.microedition.lcdui.*;<br />import javax.microedition.rms.*;<br /><br />// 扩展MIDlet类来构建我们的自定义MIDlet<br />public class FundTracker extends MIDlet implements <br />CommandListener {<br /><br />file://显示管理者变量<br />private Display display = null; <br />file://MIDlet的表单变量<br />private RequestForm reqForm = null;<br /><br />file://MIDlet构建器<br />public FundTracker () {<br />display = Display.getDisplay(this);<br />reqForm = new RequestForm("Fund Tracker");<br />reqForm.initForm();<br />reqForm.setCommandListener(this);<br />}<br /><br />file://开始 MIDlet 应用程序<br />protected void startApp() {<br />display.setCurrent(reqForm);<br />}<br /><br />file://暂停 Midlet<br />protected void pauseApp() {<br />}<br /><br />file://销毁Midlet<br />protected void destroyApp(boolean unconditional) {<br />}<br /><br />file://通过监听者响应命令<br />public void commandAction(Command c, Displayable s) {<br />if (c == reqForm.getExitCommand()) {<br />destroyApp(false);<br />notifyDestroyed();<br />return;<br />}<br />if ((c == reqForm.getGetCommand()) &amp;&amp; <br />(reqForm.getSymField().getString().length() &gt; 0)) {<br />getAndDisplayQuote();<br />} else<br />{<br />reqForm.getMsgString().setText("Symbol required");<br />}<br />}<br /><br />file://储存由#分开的成对的基金字符串和报价字符串<br />private void storeQuote (String fund, String newQuote) {<br /><br />file://数据库变量 <br /><br />RecordStore quoteDB = null;<br /><br />try {<br />quoteDB = RecordStore.openRecordStore(<br />"FundQuotes", true);<br />byte[] data = (fund + "#" + newQuote).getBytes();<br />int size = data.length;<br />quoteDB.addRecord(data, 0, size);<br />quoteDB.closeRecordStore();<br />}<br />catch (Exception recordException) {<br />System.out.println("Unable to store quote and/or <br />use Fund Quote database.");<br />}<br />}<br /><br />file://通过QuoteService类取回提交的代号表示的基金报价<br />private void getAndDisplayQuote(){<br />String fundSymbol = reqForm.getSymField().getString();<br />if (fundSymbol.length() &gt; 0) {<br />String theQuote = QuoteService.getQuote(fundSymbol);<br />if (theQuote != null) {<br />storeQuote(fundSymbol, theQuote);<br />reqForm.getMsgString().setText(theQuote);<br />}<br />else<br />reqForm.getMsgString().setText("No quote" + <br />'' '' + "Check Symbol");<br />}<br />} <br />}</td></tr></tbody></table><br /><br />　　MIDP应用程序称为 MIDlet， 为了创建一个 MIDlet，你必须写一个扩展基本 MIDlet类的类 (就像我们在上面代码段中列出的那样）。 这有点类似常见的 applet或 servlet。 MIDlets独有的东西是把多个 MIDlet组成一个 MIDlet套件的能力。 这就允许 MIDlet在一个单独的 JVM环境中共享资源，比如一个数据库等等。 事实上，我们上面给出的例子还包括一个 MIDlet ( RetrieveQuote，见上段程序），用于取回所报价格。 当MIDlet被请求时， MIDlet通过构造程序实例化，然后调用实例的 startApp()方法。 <br /><br />　 在 FundTracker例子中， MIDlet的用户界面或显示是由 Display类的一个实例管理的。 对于每个 MIDlet，只有一个显示管理器实例。 所有可以显示的项目，像屏幕或画布（canvas），通过这个管理器都能够成为可见的。因为行动电话和呼叫器能力的多样化,又因为用于这些设备的应用程序类型的差异， MIDP规范提供了两种类型的用户界面。一个可移植性稍差、明确设备、低水平的应用程序接口，允许图形元素精确的控制和放置。 这个接口类型是用于应用程序特性比较典型的设备特别设计的，比如电子游戏。 一个可移植性稍好的、抽象的、高级的 GUI应用程序接口，提供来用于商业应用程序。 <br /><br />　　我们的例程使用的是高级的应用程序接口和典型的用户界面组件 (文本框，列表等等 )，是这类界面通用的。比如说，实际的表单和所有的小组件在一个单独的文件中都已定义。 就像在代码段一中列出的那样，当 MIDlet创建时，一个表单的实例与 MIDlet关联。 在调用 MIDlet startApp()方法的时候，通过 Display对象显示表单。 使用一个用于表单的类，允许我们在我们简单的报价检索应用程序中重新使用这个表单 ( RetrieveQuote )。为了清晰性和风格，我们通过一个单独的类来定义报价服务。 为了演示一般连接器结构的能力，我们的报价服务类通过一个 Connector实例取回报价。 <br /><br /><br /><span class="f14"><br />　　MIDP要求平台设备提供一个机制用来储存简单的数据记录，通过正常的平台事件，比如重新启动和电池更新维护系统的完整性。 MIDP称一个持久数据库为 RecordStore。 在我们的示例中， MIDlet打开并添加一条记录到 " MutualFundQuotes " RecordStore。 正如我们的演示程序，能添加到 RecordStore中的唯一一种类型的记录是字节数组。 相同的 RecordStore是一个资源，它可以通过套件共享。 根据 MIDP规范， 当 MIDlet从平台中删除后，RecordStore也会被从平台中删除。 <br /><br />　　PDA简表<br /><br />　　Palm公司是开发PDA简表规范的领头人， 这个简表也是完善了 CLDC，在相当长的一段时间内，它都将是 kjava类程序包的替代品。 Java规范建议这个 profile至少应当提供两个核心功能片段： 一个用户界面显示工具包，适合于 "有限的尺寸和深度显示 "和一个持久数据存储器机制。 显示工具包应该是抽象窗口工具包的一个子集， 而持久机制将为应用程序、数据、配置/环境信息提供简单的数据存储。<br /><br />　　Foundation简表<br /><br />　　下面三种简表不是非常常见， 这三种简表的职责都是为了完善 CDC。 Personal和 RMI简表实际上是 Foundation简表的扩展。 Foundation简表的任务是担任一个基础简表，便于以后开发出来的提供图形用户接口、 网络等功能的简表附着在它之上。 除了用于基础简表， Foundation简表还提供完整网络的支持，不管有没有使用图形用户接口。<br /><br />　　Personal简表<br /><br />　　在当前的规范需求下， Personal简表提供下一代 PersonalJava环境。这个简表允诺，提供互联网连接性和 Web保真度以及一个能够运行 Java applets的 GUI。<br /><br />　　RMI简表<br /><br />　　回想一下 CDC配置为共享的、固定网络连接信息设备提供最小的 Java环境。 RMI简表将通过提供 Java到 Java的RMI来协助提供更好的网络连接性。 通过使用 J2SE ( 1.2.x或更高版本的 ) RMI，这个简表将允许这些网络设备与其他系统应用程序交互操作 (这个系统不必也运行 J2ME )。<br /><br />　　kjava类<br /><br />　　正如前面提到的那样， kjava类是最初提供的一个供测试用的类，在 Palm设备上运行早期的 KVM和配置版本。 它们将被 PDA简表代替。 kjava类扩展了 CLDC并且提供一个图形用户接口、 Palm数据库访问，简单集合类和一个三角法计算器。<br /><br />　　在代码段2中，我使用 com.sun.kjava重写了 MIDP FundTracker程序，让它在 Palm上工作。 和前面的程序一样，这个简单的程序允许用户输入一个公基金代号并从WWW上的金融报价服务商那里取回报价。<br /><br />　　kjava应用程序被称作 spotlet。 事实上，一个应用程序可以由很多 spotlet组成，但是在任何时间只有一个 spotlet可以显示在 Palm屏幕上。 在我们的例子中，我们创建一个基本 spotlet-- RequestFormSpotlet.java，为我们的两个 spotlets子类提供用户界面。代码段 2扩展了基本的 RequestFormSpotlet以便得到并储存一个报价。 RetrieveSpotlet也扩展了基本 RequestFormSpotlet并允许储存的报价被取回（见图） <br /><br />　　代码段2 
<table width="540" align="center" bgcolor="#ebe9eb" border="0"><tbody><tr><td>import com.sun.kjava.*;<br /><br />public final class FundSpotlet extends RequestFormSpotlet {<br /><br />public static void main (String args[]) {<br />new FundSpotlet().draw();<br />}<br /><br />private void draw() {<br />initForm();<br />setTitle("Fund Quote Requested");<br />}<br /><br />public void penDown(int x, int y){<br />if (getExitButton().pressed(x,y)){<br />getGraphic().playSound(Graphics.SOUND_CONFIRMATION);<br />System.exit(0);<br />}<br />if (getSymField().pressed(x,y))<br />getSymField().setFocus();<br />if (getGetButton().pressed(x,y)) {<br />quoteRequested();<br />}<br />}<br /><br />private void storeQuote (String fund, String newQuote) {<br /><br />int dbType = 0x46554e44; <br />int dbCreator = 0x43415454; <br />com.sun.kjava.Database quoteDB;<br /><br />try {<br />quoteDB = new com.sun.kjava.Database(dbType, <br />dbCreator, com.sun.kjava.Database.READWRITE);<br />if (!quoteDB .isOpen()) {<br /><br />com.sun.kjava.Database.create(0, "MutualFundQuotes", <br />dbCreator, dbType, false);<br />quoteDB = new com.sun.kjava.Database(dbType,<br />dbCreator, com.sun.kjava.Database.READWRITE);<br />}<br />byte[] data = (fund + "#" + newQuote).getBytes();<br />quoteDB.addRecord(data);<br />quoteDB.close();<br />}<br />catch (Exception recordException) {<br />System.out.println("Unable to store quote and/or use <br />Mutual Fund Quote database.");<br />}<br /><br />}<br /><br />private void getAndDisplayQuote() {<br />String fundSymbol = getSymField().getText();<br />if (fundSymbol.length() &gt; 0) {<br />String theQuote = QuoteService.getQuote(fundSymbol);<br />if (theQuote != null) {<br />storeQuote(fundSymbol, theQuote);<br />message(theQuote);<br />}<br />else<br />message("No quote. Check Symbol");<br />}<br />}<br /><br />private void quoteRequested() {<br />message("");<br />getGraphic().playSound(Graphics.SOUND_STARTUP);<br />if ((getSymField().getText().length() &gt; 0)) {<br />getAndDisplayQuote();<br />} else<br />{<br />message("Symbol required!");<br />}<br />}<br /><br />}</td></tr></tbody></table><br /><br />　　在 RequestFormSpotlet程序中，类似于 MIDP中的 Display对象，单独的 Graphics管理许多 spotlet用户界面显示。它考虑到了屏幕会被清除，显示边界会被建立。 不象 MIDlet，没有屏幕或画布对象来让我们添加用户界面小组件， 取而代之的是按钮、文本字段等等，直接描画在 spotlet上。 paint()方法利用图形环境从独一无二的 Graphics在屏幕上显示小组件。<br /><br />　　我们的MIDP程序的 QuoteService类的大部分可以重新使用。 因为 kjava没有象 MIDP中HttpConnection这样特定的连接器界面，所以我们必须利用更多标准的一般的连接器结构表单获取 HTTP链接。 为了做到这一点，使用代码段 3中的代码替换 getQuotePage()方法。注意注意使用 Connector，就像在 MIDP中我们使用 HttpConnection一样。<br /><br />　　代码段3 
<table height="24" width="545" align="center" border="0"><tbody><tr bgcolor="#ebe9eb"><td>private static String getQuotePage(String symbolString) {<br />StringBuffer quotePage = new StringBuffer();<br />int ch;<br />try {<br />InputStream in = Connector.openInputStream (<br />"testhttp://someurl/some_application?page=++&amp;mode=fund&amp;symbol="+<br />symbolString);<br />while ((ch = in.read()) &gt; 0) {<br />quotePage.append((char)ch);<br />}<br />in.close();<br />return quotePage.toString();<br />} catch (IOException ex) {<br />System.out.println("Exception reading quote from<br />　　HTTP Connection");<br />　return null;<br />　}<br />}</td></tr></tbody></table><br /><br />　　Palm设备广泛利用数据库， 你的 Palm中的通讯簿、备忘录和记事本应用程序都与数据库有关。 kjava程序包提供了一个非常小的 Database类，不仅可以创建并保持应用程序数据，而且可以访问现有的数据库。 如果你熟悉 Palm数据库，你可能会对 kjava Database类提供的功能和信息感到失望。 然而，请再次记住， kjava只是一个演示的版本。<br /><br />　　在我们的例子中，我们的 spotlet访问一个 Palm数据库 (如果不存在的话，则创建一个新的数据库）来储存公基金报价。每个 Palm数据库都必须有名字、创建者 ID (一个 Palm登记的唯一的标识号 ) 和一个指定到某个单独应用程序的类型号。 试图打开数据库要通过尝试创建一个带有 ID信息的数据库实例来实现。 就象 MIDP RecordStore，记录被添加进 kjava数据库，通过把一个字节数组当成记录添加到数据库中的形式。<br /></span><br />　　<b>第五节 再谈谈一些J2ME规范</b><br /><br />　　在 J2ME内还有很多子规范， J2ME的重要的部分如下：PersonalJava、K虚拟机 (KVM)、Java嵌入服务器以及 PersonalJava的两个扩展规范： JavaPhone和 JavaTV应用程序接口。 你可以想象， JavaPhone是一个定位于无线电智能电话和互联网络可视电话的应用程序接口，而 JavaTV则满足机顶盒市场的需求。<br /><br />　　下面我想详细的谈一谈以上的规范：<br /><br />　　1、PersonalJava<br /><br />　　PersonalJava应用程序环境目标是 Web连接消费设备----常常执行来自网络的小应用程序。问题是 PersonalJava如何适合 J2ME的配置和简表方案。 答案是 PersonalJava将被包容进 Connected Device Configuration中，最终将被定义为 Personal简表，即前面所谈到的Personal简表。<br /><br />　　另一方面，有一段时间将有两个 Java应用程序接口为嵌入开发世界服务： PersonalJava和 EmbeddedJava。 PersonalJava偎依在 J2ME大伞之下， 可为什么 EmbeddedJava不呢？ EmbeddedJava不和 PersonalJava同在 J2ME内，是因为在 PersonalJava和 EmbeddedJava应用程序之间有一个基本的差别。 PersonalJava应用程序期望连接到某类网络中下载并执行小应用程序。 按照这种观点， PersonalJava设备就是一般用途的消费设备； 它们的能力可以被扩展。<br /><br />　　相比之下， EmbeddedJava设备则惨了点。 它们执行的功能都非常具体的，基本没有必要提供下载新的代码到 EmbeddedJava设备的能力。 Hence， PersonalJava设备使用可扩展 Java应用程序接口； 而EmbeddedJava设备则没有，因为没有必要使用。<br /><br />　　PersonalJava可以以两种形式得到： 由原码形式的，提供给那些对把PersonalJava移植到其他设备感兴趣的开发者，那些已经把 PersonalJava移植到某个具体的操作系统和处理机的组织提供二进制形式的 PersonalJava环境。有兴趣探索 PersonalJava的开发者如果没有二进制平台也可以使用 PersonalJava模拟环境 ( PJEE )。 这个模拟器运行于 Solaris/SPARC或 Windows，并且在许多配置中可用。 这些多种多样的配置基于“ look and feel”和类库支持 (环境是否提供 PersonalJava规范中规定的最低限度的或最大的类库）。PJEE包括类文件，一个应用程序 launcher和一个 appletviewer (两者都是为了调试功能并使其最优化）和其它的附带的文件 (例如字体叙述文件)。<br /><br />　　J2ME家族的另一位成员 JavaCheck实用程序，提供了 PersonalJava的补充支持。 你把应用程序传过 JavaCheck，它将告诉你你的应用程序在一个 PersonalJava环境中能否顺利地执行。 JavaCheck检查类之间的依赖关系，如果应用程序调用了一个在 PersonalJava不可用的应用程序接口，它就会给出一个警报信号。 (据我所知，目前有两种JavaCheck的版本可用，一个是用于检验 PersonalJava 1.0版应用程序，另一个用于检验 1.1.x版程序。 当前的 PersonalJava应用程序接口规范是 1.2，用于这一版本的 JavaCheck还没有。 读者请去Sun相关网站去看看（ http : file://java.sun.com/products/personaljava）。<br /><br />　　2、KVM<br /><br />　　前面我也说过，KVM是用于 J2ME平台最小的虚拟机，并且是用于CLDC配置的虚拟机。可是J2ME应用程序并不一定非要使用 KVM，J2ME技术可以使用任何虚拟机，不过至少应当有 KVM这样的功能。<br /><br />　　为了满足基于KVM的设备一般只有狭小的内存空间和有限的处理能力的事实， KVM使用 C编写 (它不是现有的VM改进了的以后的产品）。 此外， KVM是模块化的， 也就是说，它是由模块构建的，当某个模块实现了预先设定的目标后，就可以很容易地把这一模块卸载。 可选的某块包括： 大的数据类型 ( long、 float和 double )，多维数组、类文件验证等。<br /><br />　　KVM的本地界面以轻便性为原则构建，所以在KVM中任务切换不依赖硬件产生的记时器中断，因此在这种意思上来说不是抢先式。任务切换发生在虚拟机执行了一个预设编号的字节码之后。 并且， KVM的无用单元收集利用一个标记清扫（mark and sweep)算法来实现无用单元释放。 因此，对象引用是直接的，就像标准 Java一样。 <br /><br />　　当然，除了虚拟机以外还有许多可用的执行环境，在小型设备中，虚拟机必须要么被扩展，要么在附加工具协助下提供一个更加完整的运行期环境，正是这个原因， KVM需要附带的工具，比如说， JavaCodeCompact工具提供了预链接和预加载类， 允许Java类被直接地链接进虚拟机中。(（设备上所有的应用程序使用的类 can直接地嵌入虚拟机。） <br /><br />　　KVM一个可选的附件就是 Java Application Manager ( Java应用程序管理器，简称 JAM )。JAM的工作就是处理下载、安装、执行和卸载 CLDC设备上的应用程序的细节问题，因为资源有限，在CLDC设备上有可能不存在这些功能。JAM也处理更新安装应用程序的操作。(如果更新过程失败，它甚至可以重新使用旧的应用程序。 ) <br /><br />　　3、Java Embedded Server（Java嵌入服务器） <br /><br />　　Java Embedded Server（ Java嵌入服务器，简称 JES），在 PersonalJava基础上建立，是一个用于嵌入式网络设备的运行期环境。为了理解 JES，你必须理解两个核心概念：服务和服务空间结构。后者是前者的容器。服务程序是运行于一个 JES服务器上的组件化程序；服务空间结构是为服务程序提供生命周期 支持的环境。<br /><br />　　技术上说，服务程序是界面的实现，事实上，它是一个实现特定活动的Java类集合。比如说，假如把 JES配置为一个家庭的气候控制系统的服务器，可以把从模数转换器读到的温度数据放进一个数据组件程序中。我就可以称这个组件为ReadThermostats服务程序。 <br /><br />　　在 JES的领域，服务的封装媒介称为 bundle。简单地说，bundle就是一个带有特殊内容的JAR文件。服务程序和bundle之间有一对一关系，一个bundle带有一个服务程序。服务程序和 bundle之间有一对一关系，一个 bundle带有一个服务程序。可这也不一定，一个 bundle可以设置多个服务程序索引 (注意， JES提供的所有的核心服务，每个 bundle中只有一个 )。 <br /><br />　　正如前面提到的那样，服务空间的一项工作就是管理服务程序的生命周期，这个工作的很大的部分包括解决服务隶属关系。bundle内容的一个重要的部分是bundle服务的依赖信息。所以，当服务空间打开一个bundle安装它的服务时，服务空间就可以确定外部需要什么服务。而且，一个服务的依赖关系并不是静止不变的，它们可以随某些事件改变。比如说当服务程序更新时的变化就是一个很好的例子。一个服务的新的版本可以添加或去除依赖关系。服务空间跟踪并解决这样的动态依赖关系。如果服务空间处理所有服务程序的生命周期，这就暗示了服务空间被赋予知晓一切的能力，那就是说，它能够推论结构、依赖、安装的细微差别等所有它负责的服务。服务空间通过在 bundle内伴随服务的 Java代码模块处理一些任务，这些模块被称作 wizard（向导）。JES向导是根据它们完成的任务命名的： <br /><br />　　Dependencies -向导告诉调用者一个bundle依赖关系是什么。 <br /><br />　　Installer-向导处理bundle中服务的安装和删除操作。 <br /><br />　　Activator -向导知道如何启动和终止服务。 <br /><br />　　Updater -向导控件更新bundle中的服务。(更新向导不仅知道更新一个服务，而且知道在何时和什么情况下更新服务。 ) <br /><br />　　About -这个向导，就像它名称意味的那样，返回关于 bundle内容的信息。 <br /><br />　　Dispatcher -这是一种元向导（meta-wizard）。服务空间调用dispatcher向导定位一个bundle的其他向导。 <br /><br />　　当一个 JES服务器启动的时候，服务空间并不是完全没有启动服务。JES定义一组核心服务(可选），这些都是任何 JES服务器的组成部分。这些核心服务包含： <br /><br />　　HTTP服务 <br /><br />　　日志 -记录错误和事件日志 <br />　　<br />　　日期 -精确到秒的日期/时间服务 <br />　　<br />　　连接管理器 -提供网络服务和Socket绑定，也处理连接接收。 <br /><br />　　线程管理器 -管理服务器提供的线程。thread管理器支持线程池并允许有效使用线程上界的规范。 <br /><br />　　计划程序 -提供未来的事件计划安排 (可用于告诉服务器某某动作必须在某某事件发生 ) <br /><br />　　RMI <br /><br />　　SNMP <br /><br />　　控制台 -提供远程管理服务器功能 <br /><br />　　基于 HTTP的远程应用程序接口实现 <br /><br />　　基于 RMI的远程应用程序接口实现 <br />　<br />　　如果你把服务空间结构当成 JavaBean中的容器的话， JES就变得容易理解了。在这种类比关系中，服务程序就相当 JavaBean。那么，正象组件容器提供一个环境供 JavaBeans实例化、运行一样，服务空间就是以实例化的服务的聚集地。服务空间管理安装、实例化、执行、终止以及卸载服务；它也提供应用程序接口供服务交互作用。 <br /></dd>
		</dl>
<img src ="http://www.blogjava.net/zjw-albert/aggbug/57135.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zjw-albert/" target="_blank">zjw_albert</a> 2006-07-07 14:57 <a href="http://www.blogjava.net/zjw-albert/archive/2006/07/07/57135.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> [转帖]J2ME程序开发全方位基础讲解汇总</title><link>http://www.blogjava.net/zjw-albert/archive/2006/07/07/57130.html</link><dc:creator>zjw_albert</dc:creator><author>zjw_albert</author><pubDate>Fri, 07 Jul 2006 06:27:00 GMT</pubDate><guid>http://www.blogjava.net/zjw-albert/archive/2006/07/07/57130.html</guid><wfw:comment>http://www.blogjava.net/zjw-albert/comments/57130.html</wfw:comment><comments>http://www.blogjava.net/zjw-albert/archive/2006/07/07/57130.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/zjw-albert/comments/commentRss/57130.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zjw-albert/services/trackbacks/57130.html</trackback:ping><description><![CDATA[
		<u>
				<font color="#800080"> [转帖]J2ME程序开发全方位基础讲解汇总</font>
		</u>
		<div class="postText">
				<p>一、J2ME中需要的Java基础知识<br />       现在有大部分人，都是从零开始学J2ME的，学习J2ME的时候，总是从Java基础开始学习，而且现在讲Java基础的书籍中都是以J2SE来讲基础，这就给学习造成了一些不必要的麻烦，下面将J2ME中用到的和不需要的Java基础知识做一个简单的说明。<br />       J2ME中使用到的Java基础知识：<br />　　  1、Java语法基础：包括基本数据类型、关键字、运算符等等<br />　　  2、面向对象的思想：类和对象的概念，继承和多态等等。<br />　　  3、异常处理<br />　　  4、多线程<br />　　J2ME中没有用到的Java基础知识：<br />　　  1、JDK中javac和java命令的使用<br />　　  2、Java基础中的很多类在J2ME中没有，或者类中的方法做了大量的精简。所以建议在J2ME中熟悉类库。<br />　　  3、Applet、AWT、Swing这些知识在J2ME中根本使用不到。<br />　　简单说这么多，希望学J2ME的朋友们能少走一些弯路，不足之处希望大家积极指正和补充。</p>
				<p>二、J2ME中暂时无法完成的功能<br />　　列一些J2ME中暂时无法完成的功能，希望大家能积极补充：<br />　　  1、在手机中不更改代码实现移植，主要指游戏。<br />　　  2、动态修改按钮文字。<br />　　  3、在Canvas上接受中文输入。<br />　　  4、操作本地资源、例如地址本、已收短信息等。<br />　　  5、制作破坏性的手机病毒。<br />　　  6、其他等待大家来补充。</p>
				<p>三、J2ME的跨平台性<br />　　J2ME技术源于Java，所以也具有JVM的优势，可以在支持Java的平台上进行移植，但是现在的J2ME技术在跨平台上却做的很糟糕，我们来简单看一下原因：<br />　　1、手机的屏幕尺寸不一：<br />　　这个主要在界面制作上。如果你使用的是高级用户界面，比如你做的是应用开发或者用户登陆、用户注册这样的通用功能时，一般没有什么问题。<br />　　如果你使用的是低级用户界面，比如你做的是游戏，那么你就需要考虑这个问题了。<br />　　2、厂商的扩展API不统一：<br />　　例如Nokia的扩展API类库UI系列，在别的手机上或者没有实现，或者包名不同等等。<br />　　3、手机平台上实现的bug：<br />　　例如Nokia的7650在实现双缓冲上有bug，那么在这种机型上运行的软件就不能使用双缓冲。其他NOKIA上的一些bug，可以参看：<a href="http://blog.csdn.net/Mailbomb/archive/2005/03/24/329123.aspx">http://blog.csdn.net/Mailbomb/archive/2005/03/24/329123.aspx</a><br />　　4、手机性能问题。<br />　　不同手机的可用内存、最大jar文件都有要求，例如Nokia S40的大部分手机支持的最大jar文件为64K，最大可用内容为210K。<br />　　所以现在的手机软件，特别是游戏都提供支持的机型列表，也才有了手机游戏移植人员的存在。</p>
				<p>四、学习J2ME可以从事的工作种类<br />　　现在J2ME技术可以说相当的火暴，这里介绍一些学好了J2ME之后可以从事的工作的种类：<br />　　1、J2ME游戏开发人员<br />　　根据游戏策划或者文档要求，在某种特定的机型(以Nokia S40或S60居多)开发游戏程序。<br />　　这是现在大部分J2ME程序员从事的工作。<br />　　需要熟练掌握：高级用户界面、低级用户界面、线程，如果是网络游戏，还需要熟练网络编程。<br />　　2、J2ME应用开发人员<br />　　现在的移动应用还不是很多，但是还是出现了一些，特别是移动定位以及移动商务相关的内容。<br />　　需要熟练掌握：高级用户界面、线程和网络编程。<br />　　3、J2ME游戏移植人员<br />　　参照源代码，将可以在一个平台上可以运行的游戏移植到其他平台上去。例如将Nokia S40的游戏移植到S60上，或者索爱的T618等等。<br />　　主要是控制屏幕坐标，有些可能需要替换一些API。<br />　　需要熟悉各平台之间的差异以及相关的技术参数，比如屏幕大小、最大jar文件尺寸等等。</p>
				<p>五、J2ME程序设计的几个原则<br />　　1、使用面向对象编程。<br />　　虽然使用面向过程编程可以减小文件的尺寸，但是为了以后维护的方便和利于扩展，还是要使用面向对象编程。<br />　　2、使用MVC模式<br />　　将模型、界面和控制分离。现在很多的程序将三者合一，但是如果你做的程序比较大的话，还是建议你进行分离。<br />　　3、自动存储用户设定<br />　　使用RMS来存储用户的信息，例如存储用户上次输入的用户名、密码、用户对于系统的设定等，这样不仅可以减少用户的输入，而且对用户友好。很多程序甚至做了自动登陆等。<br />　　4、一些系统设置允许用户关闭。如背景音乐、背景灯显示等。<br />　　5、将低级用户界面的绘制动作放在一个独立的线程里面去。<br />　　6、在需要大量时间才能完成的工作时，给用户一个等待界面。</p>
				<p>六、从模拟器到真机测试<br />　　对于J2ME开发者来说，模拟器给我们带来了很多方便，比如可以在模拟器中调试程序以及很方便的察看程序的效果，但是模拟器也给我们带来了一些问题，比如模拟器实现的bug等等，所以进行真机测试是必须的。<br />　　1、为什么要进行真机测试？<br />　　因为模拟器程序可能存在bug，以及真机的性能有限，所以必须进行真机测试。<br />　　2、如何将程序传输到机器中？<br />　　将程序传输到机器中有如下方式：<br />　　  a)　OTA下载<br />　　  b)　使用数据线传输<br />　　  c)　红外传输<br />　　  d)　蓝牙<br />　　你可以根据条件，选择合适的方式。<br />　　3、 真机测试主要测什么？<br />　　真机测试的内容很多，主要测试以下几个方面：<br />　　  a)　程序的功能<br />　　  b)　程序的操作性，是否易操作<br />　　  c)　程序的大小,比如Nokia S40系列的手机大部分接受的最大文件尺寸为64K<br />　　  d)　程序运行速度，速度是否可以忍受。</p>
				<p>七、从WTK到厂商SDK<br />　　对于J2ME爱好者来说，基本上大家都是从SUN的WTK(J2ME Wireless Toolkit)开始的，但是对于实际应用来说，仅仅使用WTK是远远不够的，所以在学习过程中，必须完成从WTK到SDK的跨越。<br />　　1、厂商SDK的下载地址？<br />　　<a href="http://blog.csdn.net/Mailbomb/archive/2005/01/01/236606.aspx">http://blog.csdn.net/Mailbomb/archive/2005/01/01/236606.aspx</a><br />　　2、厂商SDK和WTK有什么不同？<br />　　厂商SDK最简单的理解就是在WTK的基础上增加了自己的模拟器和自己的扩展API。<br />　　也就是说，你在使用厂商的SDK时，可以使用厂商的扩展类库，例如Nokia的UI类库，和厂商自己的模拟器而已。<br />　　每个厂商的扩展API都不多，而且不尽相同。<br />　　3、如何使用？<br />　　有些厂商SDK的使用都和WTK相同，例如SamSung。<br />　　Nokia提供了独立的界面来开发，但是这个界面在实际开发中使用不多。<br />　　4、厂商SDK的问题<br />　　厂商SDK实现过程中，有一些bug，而且和真机实现不一致。例如NOKIA的混音播放问题等等。</p>
				<p>八、在J2ME中获得手机IMEI的方法<br />　　IMEI是Internation mobile entity identification的简称，在手机中输入*#06#可以显示该数字，长度为15位，全球唯一，永远不会冲突，所以可以作为识别用户的一个标志。<br />　　下面是在J2ME中获得IMEI的方法：<br />　　1、MOTO系列的手机可以通过读取系统的IMEI属性获得，代码如下：<br />　　           String imei = System.getProperty("IMEI");<br />　　2、SIEMENS系列的手机可以通过读取系统的com.siemens.IMEI属性获得，代码如下：<br />　　           String imei = System.getProperty("com.siemens.IMEI");</p>
				<p>九、J2ME网络连接中显示问题的解决办法<br />　　在网络编程中，有些时候会出现一些在没有接收到网络数据就显示界面的，造成界面显示不符合要求（例如公告显示，会先显示公告的背景图片再显示公告信息），这里提一个简单的解决办法给大家：<br />　　解决这种情况的方法分成三个步骤：<br />　　1、在需要显示的界面中，调用发送网络数据的方法。每次显示时调用该构造方法，不调用Display的setCurrent方法显示。<br />　　2、显示等待界面(例如进度条等)，给用户提示，在进行网络连接。<br />　　3、在处理网络反馈的数据完以后，调用Display的setCurrent方法显示显示当前界面。</p>
				<p>十、增强J2ME的String能力——分割字符串<br />　　从JDK1.4以后，String类中新增了split方法来实现字符串的分割，但是在J2ME中却没有该方法(MIDP2.0中也没有实现)，但是在实际使用过程中，有些时候的确要用到这种操作，这里将我以前实现的一段代码和大家共享：<br />/**<br />* 分割字符串，原理：检测字符串中的分割字符串，然后取子串<br />* @param original 需要分割的字符串<br />* @paran regex 分割字符串<br />* @return 分割后生成的字符串数组<br />*/</p>
				<p>private static String[] split(String original,String regex)<br />{<br />     //取子串的起始位置<br />     int startIndex = 0;<br />     //将结果数据先放入Vector中<br />     Vector v = new Vector();<br />     //返回的结果字符串数组<br />     String[] str = null;<br />     //存储取子串时起始位置<br />     int index = 0;</p>
				<p>     //获得匹配子串的位置<br />     startIndex = original.indexOf(regex); <br />     //System.out.println("0" + startIndex); <br />     //如果起始字符串的位置小于字符串的长度，则证明没有取到字符串末尾。<br />     //-1代表取到了末尾<br />     while(startIndex &lt; original.length() &amp;&amp; startIndex != -1)<br />     {<br />           String temp = original.substring(index,startIndex);<br />           System.out.println(" " + startIndex);<br />           //取子串<br />           v.addElement(temp);</p>
				<p>           //设置取子串的起始位置<br />           index = startIndex + regex.length();</p>
				<p>           //获得匹配子串的位置<br />           startIndex = original.indexOf(regex,startIndex + regex.length());<br />     }</p>
				<p>     //取结束的子串<br />     v.addElement(original.substring(index + 1 - regex.length()));<br />     //将Vector对象转换成数组<br />     str = new String[v.size()];<br />     for(int i=0;i <br />     {<br />          str[i] = (String)v.elementAt(i);<br />     }<br />     <br />     //返回生成的数组<br />     return str;<br />}</p>
				<p>十一、J2ME在低级用户界面上分行显示文字<br />　　在J2ME的低级用户界面开发中，经常会遇到需要在Canvas上显示大量的文字，例如关于界面、游戏说明、游戏公告等信息。如果在设计时，将文字的内容和长度都固定，既不利于修改也不利于维护。下面介绍一个简单的方法，实现一个简单、可维护性强的方式。<br />　　实现方法：<br />　　  1、将需要显示的所有信息做成一个字符串。<br />　　  2、编写一个将该字符串按照要求转换为字符串数组的方法。<br />　　  3、将转换后的数组以循环的方式显示在Canvas上。<br />　　通过这样三个步骤，则修改显示的信息时，只需要修改包含显示信息的字符串即可，自己书写的方法可以按照以前的标准重新分割新的字符串。如果需要修改每行显示的字符个数，则只需要修改自己书写的方法即可。<br />　　通过这样一种实现方式，可以很方便的实现显示一些比较长的文本信息，即使是可变长度的字符串也没有问题。</p>
				<p>十二、J2ME中使用记录存储系统(RMS)存储信息<br />　　在MIDP中，没有文件的概念，所以永久存储一般只能依靠记录存储系统实现，关于记录存储系统的简介，可以参看教程：<a href="http://www-900.ibm.com/developerWorks/cn/java/j-wi-rms/index.shtml">http://www-900.ibm.com/developerWorks/cn/java/j-wi-rms/index.shtml</a><br />　　下面是一些记录存储系统的常用编码介绍：<br />　　  1、打开记录集：<br />　　打开记录集使用RecordStore里面的静态方法openRecordStore，示例代码如下：<br />          RecordStore rs = RecordStore.openRecordStore(“username”,true);<br />　　这样就打开了一个名称为rs的记录集，其中username为记录集的名称，该名称可以根据需要来取，第二个参数代表是否则没有时创建新的记录集，true代表在该记录集不存在时，创建新的记录集，false代表不创建。<br />　　如果在打开记录集时，该记录集不存在，则抛出RecordStoreNotFoundException异常，所以检测记录集是否已创建可以使用该异常。<br />　　注意：记录集打开以后记得关闭。<br />　　  2、向记录集中写入数据<br />　　      2.1增加数据<br />　　向已经打开的记录集中添加数据，需要使用addRecord方法，示例代码：<br />                 byte[] bytes = {1,2,3};<br />　　           int id = rs. addRecord(bytes,0,bytes.length);<br />　　该代码将字节数组bytes的全部内容写入到记录集中，该方法的返回值为该信息的id，注意：id从1开始，而不是从0开始。<br />　　你可以循环使用该方法向记录集中写入多条数据。<br />　　      2.2修改数据<br />　　修改已经存在的记录集中指定id的数据，需要使用setRecord方法，示例代码：<br />                 byte[] bytes = {1,2,3};<br />　　           rs. setRecord(1,bytes,0,bytes.length);<br />　　以上代码的作用是将字节数组bytes的全部内容写入到id为1的记录集rs中。<br />　　该操作会覆盖已有的数据。<br />　　说明：有些时候，你需要将信息写入到记录集中的第一条记录中，则可以结合以上两个方法，则第一次时向记录集增加数据，以后来进行修改。<br />　　  3、从记录集中读出数据<br />　　从记录集中读取已有数据，需要使用getRecord方法，示例代码：<br />            byte[] bytes = rs. getRecord(1);<br />　　该代码从记录集rs中读取第一条数据，将读取到的数据放在bytes数组中。<br />　　在读取数据时，可以获得记录集中id的个数，可以使用getNumRecords方法获得<br />　　综合代码为：<br />       int number = rs. getNumRecords();<br />       int id = 1;<br />       if(id &gt;0 &amp;&amp; id &lt; number)<br />       {<br />　　     byte[] bytes = rs. getRecord(1);<br />       }<br />　　  4、从记录集中删除记录<br />　　从记录集中删除记录的方法有两种：逻辑删除和物理删除。<br />　　逻辑删除是指给删除的记录打标记。<br />　　物理删除是指从物理上删除该记录，但是该记录的id不能被重用，也就是说该id不会被继续使用。例如一个记录集中有5个记录，假设你删除了id为3的数据，则剩余记录的id依然为1、2、4、5。这给便历带来了一定的麻烦。<br />　　  5、便历记录集<br />　　便历记录集，即访问记录集中的所有数据，有两个方法，详见：<br /><a href="http://gceclub.sun.com.cn/NASApp/sme/controller/teclist?tid=0103">http://gceclub.sun.com.cn/NASApp/sme/controller/teclist?tid=0103</a><br />　　  6、其他操作<br />　　删除记录集<br />　　删除记录集不同于删除记录，需要使用deleteRecordStore方法，示例代码：           <br />                RecordStore. deleteRecordStore(“username”);<br />　　该代码删除名称为username的记录集。</p>
				<p>十三、J2ME加密数据的一个第三方开源免费类库介绍<br />　　在J2ME编程中，经常遇到一些数据在存储或者传输时需要加密，下面介绍一个第三方的加密类库的一些资料：<br />　　加密类库的官方主页：<a href="http://www.bouncycastle.org/">http://www.bouncycastle.org/</a><br />　　介绍的文章：<br />　　中文：<a href="http://18900.motorola.com/ewa_portal/develope/jc_j2messl_5_1.jsp">http://18900.motorola.com/ewa_portal/develope/jc_j2messl_5_1.jsp</a><br />　　英文：<a href="http://www.javaworld.com/javaworld/jw-12-2002/jw-1220-wireless.html">http://www.javaworld.com/javaworld/jw-12-2002/jw-1220-wireless.html</a><br />　　该文章的源代码包含使用的一些方法。<br />　　备注：因为该类库提供的功能比较强大，所以类库的尺寸比较大，最后在发布时需要将类库中不需要的类删除</p>
				<p>十四、如何播放声音<br />　　在J2ME中，处理声音需要使用到Mobile Media API(MMAPI)，该包是MIDP1.0的可选包，在MIDP2.0中已经包含了这个包。所以如果你使用MIDP1.0的话，请确认你的运行环境是否支持。<br />　　一般手机支持的声音文件格式为wav、mid和mpg等。具体请查阅你的手机说明文档。<br />　　在声音处理中，有很多处理的方式，这里说一下最常用的情况，播放JAR文件中的wav文件。<br />　　播放声音文件的流程：<br />　　  1、按照一定的格式读取声音文件。<br />　　播放JAR文件中的声音文件一般是将声音文件处理成流的形式。示例代码：<br />             InputStream is = this.getClass().getResourceAsStream("/Autorun.wav");<br />       其中Autorun.wav文件位于JAR文件的根目录下，如果位于别的目录，需要加上目录名称，如/res /Autorun.wav。<br />　　  2、将读取到的内容传递给播放器。<br />　　将流信息传递给播放器，播放器按照一定的格式来进行解码操作，示例代码：<br />             Player player = Manager.createPlayer(is,"audio/x-wav");<br />　　其中第一个参数为流对象，第二个参数为声音文件的格式。<br />　　  3、播放声音。<br />　　使用Player对象的start方法，可以将声音播放出来，示例代码：<br />             player.start()；<br />　　在播放声音时也可以设定声音播放的次数，可以使用Player类中的setLoopCount方法来实现，具体可查阅API文档。<br />　　下面是在NOKIA S60模拟器中测试通过。代码如下：<br />package sound;<br />import javax.microedition.midlet.*;<br />import javax.microedition.lcdui.*;<br />import javax.microedition.media.*;<br />import java.io.*;</p>
				<p>public class SoundMIDlet extends MIDlet <br />{<br />　　private Player player = null;<br />　　/** Constructor */<br />　　public SoundMIDlet() <br />       {<br />             try<br />             {<br />                   InputStream is = this.getClass().getResourceAsStream("/Autorun.wav");<br />                   player = Manager.createPlayer(is,"audio/x-wav");<br />             }<br />             catch(IOException e)<br />             {<br />                   System.out.println("1:" + e);<br />             }<br />             catch(MediaException e)<br />             {<br />                   System.out.println("2:" + e);<br />             }<br />             catch(Exception e)<br />             {<br />                   System.out.println("3:" + e);<br />             }<br />      }</p>
				<p>      /** Main method */<br />      public void startApp() <br />      {<br />             if(player != null)<br />             {<br />                   try<br />                   {<br />　　　　          player.start();<br />                   }<br />                   catch(MediaException e)<br />                   {<br />　　　　          System.out.println("4:" + e);<br />                   }<br />             }<br />       }</p>
				<p>       /** Handle pausing the MIDlet */<br />       public void pauseApp() <br />       {<br />       }</p>
				<p>       /** Handle destroying the MIDlet */<br />       public void destroyApp(boolean unconditional) <br />       {<br />       }<br />}</p>
				<p>十五、J2ME 3D编程的一些资料<br />　　随着J2ME技术的发展，以及硬件速度的提升，3D游戏程序将慢慢的变成主流，最近想学习这一块的编程，所以收集了一些资料，和大家一起分享：<br />　　1、JSR184<br />　　JSR184是Nokia公司起草的一个关于3D API的规范，下载地址为：<br />　　<a href="http://www.forum.nokia.com/main/1,,1_0_10,00.html#jsr184">http://www.forum.nokia.com/main/1,,1_0_10,00.html#jsr184</a><br />　　2、Nokia的3D编程资料<br />　　<a href="http://www.forum.nokia.com/main/1,6566,21,00.html">http://www.forum.nokia.com/main/1,6566,21,00.html</a><br />　　3、3D引擎<br />　　一个简单的开放源代码的3D游戏引擎<br />　　<a href="http://www.j2me.com.cn/Soft_Show.asp?SoftID=19">http://www.j2me.com.cn/Soft_Show.asp?SoftID=19</a><br />　　国内一个合作开发3D引擎的项目：<br />　　<a href="http://gceclub.sun.com.cn/NASApp/sme/jive/thread.jsp?forum=11&amp;thread=8593">http://gceclub.sun.com.cn/NASApp/sme/jive/thread.jsp?forum=11&amp;thread=8593</a><br />　　4、一款3D游戏产品<br />　　<a href="http://games.sina.com.cn/newgames/2004/04/040217696.shtml">http://games.sina.com.cn/newgames/2004/04/040217696.shtml</a><br />　　5、支持3D的开发工具<br />　　当前一些高端的手机支持3D开发，支持3D开发的开发工具中，通用的有SUN的J2MEWTK2.2。专用的是厂商提高的支持JSR184的SDK。</p>
				<p>十六、3D编程——第一个3D程序<br />　　参考WTK2.2提供的demo，完成了第一个3D程序，虽然很简单，而且有些问题还不是很清楚，还是把代码共享出来和愿意学习J2ME 3D编程的朋友一起学习。<br />　　关于代码的编译和运行说明如下：<br />　　1、以下代码在J2ME WTK2.2下面编译通过。<br />　　2、代码分为两个文件：First3DCanvas.java和First3DMIDlet.java。<br />　　3、使用J2ME WTK2.2建立新的工程，主MIDlet类为：first3d. First3DMIDlet<br />　　4、将代码保存在你的工程目录下的first3d目录下。<br />　　5、将J2ME WTK安装目录下的apps\Demo3D\res\com\superscape\m3g\wtksamples\retainedmode\content目录中的swerve.m3g文件复制到你的工程目录下的res目录下。<br />　　6、你的工程建立后，设置工程，通过WTK界面中的“设置”按钮打开设置窗口，在“API选择”中，设置“目标平台”为：自定义；“简档”为“MIDP2.0”；“配置”为“CLDC1.1”；选中“Mobile 3D Graphics for J2ME(JSR184)”。<br />　　7、这样你就可以编译和运行以下代码了。<br />　　源代码如下： </p>
				<p>// First3DMIDlet.java<br />package first3d;<br />import javax.microedition.midlet.*;<br />import javax.microedition.lcdui.*;<br />public class First3DMIDlet extends MIDlet <br />{<br />      private First3DCanvas displayable = new First3DCanvas();<br />      public void startApp() <br />      {<br />            Display.getDisplay(this).setCurrent(displayable);<br />      }</p>
				<p>      public void pauseApp() {}</p>
				<p>      public void destroyApp(boolean unconditional) {}<br />}</p>
				<p>// First3Dcanvas.java<br />package first3d;<br />import javax.microedition.lcdui.*;<br />import javax.microedition.m3g.*;<br />import java.util.*;<br />/**<br />* 第一个3D程序<br />*/<br />public class First3DCanvas extends Canvas implements Runnable <br />{<br />      /**World对象*/<br />      private World myWorld = null;<br />      /**Graphics3D对象*/<br />      private Graphics3D g3d = Graphics3D.getInstance();<br />      /**Camera对象*/<br />      private Camera cam = null;<br />      private int viewport_x;<br />      private int viewport_y;<br />      private int viewport_width;<br />      private int viewport_height;<br />      private long worldStartTime = 0;<br />      //重绘时间<br />      private int validity = 0;<br />      <br />      public First3DCanvas() <br />      {<br />            //启动重绘界面的线程<br />            Thread thread = new Thread(this);<br />            thread.start();<br />            try <br />            {<br />                   //导入3D图片<br />                   myWorld = (World) Loader.load("/swerve.m3g")[0];<br />                   viewport_x = 0;<br />                   viewport_y = 0;<br />                   viewport_width = getWidth();<br />                   viewport_height = getHeight();<br />                   cam = myWorld.getActiveCamera();<br />                   //设置cam对象<br />                   float[] params = new float[4];<br />                   int type = cam.getProjection(params);<br />                   if (type != Camera.GENERIC) <br />                   {<br />                          //calculate window aspect ratio<br />                          float waspect = viewport_width / viewport_height;<br />                          if (waspect &lt; params[1]) <br />                          {<br />                                float height = viewport_width / params[1];<br />                                viewport_height = (int) height;<br />                                viewport_y = (getHeight() - viewport_height) / 2;<br />                          }<br />                          else <br />                          {<br />                                float width = viewport_height * params[1];<br />                                viewport_width = (int) width;<br />                                viewport_x = (getWidth() - viewport_width) / 2;<br />                          }<br />                   }<br />                   worldStartTime = System.currentTimeMillis();<br />            }<br />            catch (Exception e) {}<br />      }<br />      <br />      protected void paint(Graphics g) <br />      {<br />            //清除背景<br />            g.setColor(0x00);<br />            g.fillRect(0, 0, getWidth(), getHeight());<br />            //和3D对象绑定<br />            g3d.bindTarget(g);<br />            g3d.setViewport(viewport_x, viewport_y, viewport_width, viewport_height);<br />            long startTime = System.currentTimeMillis() - worldStartTime;<br />            validity = myWorld.animate((int)startTime);<br />            try <br />            {<br />                   g3d.render(myWorld);<br />            }<br />            finally <br />            {<br />                   g3d.releaseTarget();<br />            }<br />      }</p>
				<p>      public void run() <br />      {<br />            try<br />            {<br />                   while(true)<br />                   {<br />                         //重绘图形<br />                         repaint(viewport_x, viewport_y, viewport_width, viewport_height);<br />                   }<br />            }<br />            catch(Exception e){}<br />      }<br />}</p>
				<p>十七、在J2ME网络编程中使用CMWAP代理<br />　　在中国移动提供的网络连接中，分为CMNET和CMWAP两种，其中CMNET可以无限制的访问互联网络，资费比较贵。CMWAP类似一个HTTP的代码，只能访问支持HTTP的应用，但是资费便宜，稳定性比较差。<br />　　在实际的J2ME网络编程中，一般需要提供以CMWAP代理的方式连接网络，在J2ME中，连接的代码和直接连接有所不同，代码如下：<br />             HttpConnection http = (HttpConnection)Connector.open(("<a href="http://10.0.0.172/&quot;+url">http://10.0.0.172/"+url</a>);<br />             http.setRequestProperty("X-Online-Host",ServerName);<br />　　例如你需要访问的地址为：<a href="http://www.test.com/login/loginServlet">http://www.test.com/login/loginServlet</a>则上面的代码就为：<br />             HttpConnection http = (HttpConnection)Connector.open(("<a href="http://10.0.0.172/">http://10.0.0.172/</a>" + "login/loginServlet");<br />             http.setRequestProperty("X-Online-Host","<a href="http://www.test.com/">www.test.com</a>");<br />　　在实际使用过程中，只需要使用实际需要访问的地址的域名或者IP来代替ServerName，例如示例中的“www.test.com”，使用后续的地址类代替代码中的url，例如示例中的“login/loginServlet”，就可以实际的使用CMWAP代理来进行连接了。</p>
				<p>十八、J2ME中的时间处理全攻略<br />　　时间处理在程序开发中相当常见，下面对于时间处理做一个简单的说明。<br />　　一、时间的表达方式<br />　　时间在J2ME中有两种表达方式：<br />　　1、以和GMT1970年1月1号午夜12点和现在相差的毫秒数来代表<br />　　这种方式适合比较两个时间之间的差值。<br />　　2、以对象的形式来表达<br />　　二、时间处理的相关类<br />　　时间处理在J2ME中涉及三个类：<br />　　1、System类<br />　　 long time = System. currentTimeMillis();<br />　　使用该方法可以获得当前时间，时间的表达方式为上面提到的第一种。<br />　　2、Date类<br />　　 Date date = new Date();<br />　　获得当前时间，使用对象的形式来进行表达。<br />　　3、Calendar类<br />　　 Calendar calendar = Calendar. getInstance();</p>
				<p>三、时间处理的具体操作<br />　　1、以上三种表达方式的转换：<br />　　a)将System类获得的时间转换为Date对象<br />　　 Date date = new Date(System. currentTimeMillis());<br />　　b)将Date类型的对象转换为Calendar类型的对象<br />　　 Calendar calendar = Calendar. getInstance();<br />　　 Date date = new Date();<br />　　 calendar.setTime(date);<br />　　2、使用Calendar完成一些日期操作：<br />　　Calendar是时间处理中最常用也是功能最强大的类，可以用它来获得某个时间的日期、星期几等信息。<br />　　获得日期：<br />　　 Calendar calendar = Calendar. getInstance();<br />　　 ……<br />　　 int day = calendar.get(Calendar. DATE);<br />　　获得日期、年份、星期的操作和这个类似。<br />　　需要注意的是：Calendar中表示月份的数字和实际相差1，即1月用数字0表示，2月用数字1表示，……12月用数字11表示。</p>
				<p>十九、J2ME中随机数字处理全攻略<br />　　在程序中生成随机数字，用处比较，如人工智能领域等等，这里对于在J2ME中生成随机数的操作进行一个简单的整理，希望对大家能有帮助。<br />　　J2ME和J2SE不同，不能使用Math类的random来生成随机数字，只能使用java.util包的Random类来生成随机数字。<br />　　1、创建Random类型的对象：<br />         Random random = new Random();<br />　　 Random random = new Random(10010010);<br />　　以上两种是创建Random对象的方式，第一种使用默认构造方法，和以下的代码作用完全等价：<br />　　 Random random = new Random(System. currentTimeMillis());<br />　　相当与使用当前时间作为种子数字来进行创建。<br />　　第二种方式通过自己来指定种子数字来进行创建。<br />　　大家可以根据需要使用以上两种方式的任一种。<br />　　2、生成随机数字：<br />　　创建好了随机对象以后，我们就可以来生成随机数字了：<br />　　生成随机整数：<br />         int k = random.nextInt();<br />       生成随机长整数：<br />         long l = random.nextLong();<br />　　3、生成指定范围的数字：<br />　　例如生成0-10之间的随机数字：<br />         int k = random.nextInt();<br />　　 int j = Math.abs(k % 10);<br />　　首先生成一个随机整数k，然后用k和10取余，最后使用Math类的abs方法取绝对值，获得0-10之间的随机数字。<br />　　获得0-15之间的随机数，类似：<br />         int k = random.nextInt();<br />　　 int j = Math.abs(k % 15);<br />　　获得10-20之间的随机数字：<br />         int k = random.nextInt();<br />　　 int j = Math.abs(k % 10) + 10;</p>
				<p>二十、在J2ME手机编程中使用字体<br />　　在J2ME手机编程中，可以通过使用字体类——Font在低级用户界面中，获得更好的表现效果，那么如何使用Font类呢？<br />　　首先，由于手机设备的限制，手机中支持的字体类型很有限，所以在J2ME中只能使用手机支持的默认字体来构造Font类对象。下面是创建Font类的对象时使用的方法：<br />          getFont(int face,int style,int size);<br />例如：<br />          Font font = Font.getFont(Font.FACE_SYSTEM,Font.STYLE_BOLD,Font. SIZE_MEDIUM);<br />　　无论哪一个参数，都只能使用系统设置的数值，这些数值具体的大小在不同的手机上可能不同。下面对于其中的三个参数的取值做详细的介绍：<br />　　face参数指字体的外观，其的取值：<br />　　FACE_MONOSPACE——等宽字体<br />　　FACE_PROPORTIONAL——均衡字体<br />　　FACE_SYSTEM——系统字体<br />　　style参数指字体的样式，其的取值：<br />　　STYLE_BOLD——粗体<br />　　STYLE_ITALIC——斜体<br />　　STYLE_PLAIN——普通<br />　　STYLE_UNDERLINED——下划线<br />　　STYLE_BOLD | STYLE_ITALIC——粗斜体<br />　　STYLE_UNDERLINED | STYLE_BOLD——带下划线粗体<br />　　STYLE_UNDERLINED | STYLE_ITALIC——带下划线斜体<br />　　STYLE_UNDERLINED | STYLE_ITALIC | STYLE_BOLD——带下划线的粗斜体<br />　　size参数指字体的大小，其的取值：<br />　　SIZE_SMALL——小<br />　　SIZE_MEDIUM——中<br />　　SIZE_LARGE——大<br />　　通过上面的参数的值，可以组合出你需要的字体对象。<br />　　下面是一些常用的字体操作：<br />　　1. 获得系统的默认字体：<br />          Font font = Font.getDefaultFont();<br />　　2. 在panit方法内部，假设Graphics参数的名称为g，则获得当前字体的方法是：<br />          Font font = g.getFont();<br />　　3. 在panit方法内部，假设Graphics参数的名称为g，则设置当前字体的方法是：<br />          g.setFont(font);<br />　　其中font为你构造好的字体对象。<br />　　4. 在MIDP2.0中，List可以设置每行的字体格式，方法是：<br />          list.setFont(0,font);<br />　　则上面的代码是将list中的第一行设置为font类型的字体。</p>
				<p>二十一、在J2ME手机程序开发中使用颜色<br />　　在J2ME手机开发过程中，需要经常用到颜色来进行绘制，增强程序的表现效果，下面就介绍一下如何使用颜色。<br />　　由于J2ME技术比较简单，所以没有实现专门的颜色类，而只是使用RGB的概念来代表颜色。这里简单介绍一下RGB的概念，颜色是由红(Red)、绿(Green)、蓝(Blue)三原色组成的，所以可以使用这三个颜色的组合来代表一种具体的颜色，其中R、G、B的每个数值都位于0-255之间。在表达颜色的时候，即可以使用三个数字来表达，也可以使用一个格式如0X00RRGGBB这样格式的十六进制来表达，下面是常见颜色的表达形式：<br />　　红色：(255,0,0)或0x00FF0000<br />　　绿色：(0,255,0)或0x0000FF00<br />　　蓝色：(255,255,255)或0x00FFFFFF<br />　　其他颜色也可以通过上面的方式组合出来。<br />　　知道了颜色的表达方式以后，下面来介绍一下如何在J2ME程序中使用颜色，涉及的方法均在Graphics类中，有以下几个：<br />　　1.getColor()：<br />　　获得当前使用的颜色，返回值是0x00RRGGBB格式的数字。例如：<br />          int color = g.getColor();<br />　　其中g为Graphics类型的对象。<br />　　2.setColor(int RGB)：<br />　　设置使用的颜色。例如：<br />          g.setColor(0x00ff0000);<br />　　3.setColor(int red, int green, int blue)<br />　　和上面的方法作用一样，例如：<br />          g.setColor(255,0,0);<br />　　在设置了Graphics使用的颜色以后，再进行绘制的时候，就可以绘制指定的颜色了。</p>
				<p>二十二、在J2ME联网应用中获得客户端的手机号码<br />　　在J2ME程序开发过程中，为了一定的需要，经常需要来获得用户的手机号码，但是这个功能却在标准的J2ME类库中没有提供。<br />　　在使用中国移动的CMWAP方式连接网络时，中国移动会将用户的手机号码放在一个名称为x-up-calling-line-id的头信息中，可以通过读取该头信息，获得用户的手机号码，具体代码如下：<br />          String usermphone = http.getHeader("x-up-calling-line-id");<br />　　其中http是HttpConnction类型的对象。</p>
				<p>二十三、使用J2ME发送手机短信息<br />　　在程序中，发送短信息的方式一般有三种：<br />　　1、 使用程序在网络上发送短信息，例如各大网站的短信业务。这种方式是通过程序将信息发送给运营商的网关服务器，然后通过运营商的网络发送给手机。<br />　　2、 在计算机中，通过数据线连接到手机，然后通过手机来发送短信息。这种方式是通过使用AT指令来实现。爱立信手机的AT指令你可以在以下地址找到：<a href="http://mobilityworld.ericsson.com.cn/development/download_hit.asp">http://mobilityworld.ericsson.com.cn/development/download_hit.asp</a><br />　　3、 通过在手机中运行的程序来发送短信息。这个正是本文实现的方式。<br />　　在J2ME中，如果想发送短信息，需要使用WMA包，MIDP2.0中已经包含，MIDP1.0中可以通过厂商提供的扩展API实现，和WMA的类库基本一样。<br />       下面是使用WMA向指定手机号码发送短信息的一个方法，很简单。当然WMA也提供了其他的方式来发送更多的内容。</p>
				<p>// SMSUtil.java<br />package my.util;<br />import javax.wireless.messaging.*;<br />import javax.microedition.io.*;<br />/**<br />* 发送文本短信息的方法<br />*/<br />public class SMSUtil<br />{<br />      /**<br />      * 给指定号码发送短信息<br />      * @param content 短信息内容<br />      * @param phoneNumber 手机号码<br />      * @return 发送成功返回true，否则返回false<br />      */<br />      public static boolean send(String content,String phoneNumber)<br />      {<br />            //返回值<br />            boolean result = true;<br />            try<br />            {<br />                   //地址<br />                   String address = "sms://+" + phoneNumber;<br />                   //建立连接<br />                   MessageConnection conn = (MessageConnection)Connector.open(address);<br />                   //设置短信息类型为文本，短信息有文本和二进制两种类型<br />                   TextMessage msg = (TextMessage)conn.newMessage(MessageConnection.TEXT_MESSAGE);<br />                   //设置信息内容<br />                   msg.setPayloadText(content);<br />                   //发送<br />                   conn.send(msg);<br />            }<br />            catch(Exception e)<br />            {<br />                   result = false;<br />                   //未处理<br />            }<br />            return result;<br />      } <br />}</p>
				<p>二十四、使用简单的J2ME程序测试MIDlet的生命周期<br />　　在MIDlet程序学习中，生命周期是一个比较抽象的概念。其实生命周期就是一个简单的规定，规定了MIDlet中的每个方法，什么时候被系统调用。下面是一个示例代码，在每个方法的内部都输出一条语句，可以根据程序的输出结果来验证各方法被调用的顺序，具体代码如下：</p>
				<p>
						<br />//文件名：LifeCircleMIDlet.java<br />import javax.microedition.midlet.*;<br />/**<br />* 测试MIDlet的生命周期<br />*/<br />public class LifeCircleMIDlet extends MIDlet<br />{<br />      /**<br />      * 默认构造方法<br />      */<br />      public LifeCircleMIDlet()<br />      {<br />            System.out.println("默认构造方法");<br />      }<br />      /**<br />      * 启动方法<br />      */<br />      public void startApp()<br />      {<br />            System.out.println("startApp方法");<br />      }<br />      /**<br />      * 暂停方法<br />      */<br />      public void pauseApp()<br />      {<br />            System.out.println("pauseApp方法"); <br />      }<br />      /**<br />      * 销毁方法<br />      * @param b <br />      */<br />      public void destroyApp(boolean b)<br />      {<br />            System.out.println("destroyApp方法"); <br />      } <br />}<br />　　在J2WTK中运行该程序时，可以使用浏览器中的“MIDlet”菜单中的暂停和恢复菜单，模拟暂停事件。</p>
				<p>二十五、使用OTA来发布你的程序<br />　　众所周知，J2ME程序发布的形式主要有：OTA、数据线传输、红外和蓝牙传输等。这里简单说说如何通过OTA来发布你的程序。<br />　　OTA是Over The Air的简写，也就是通过网络下载，这是主要的发布形式之一。现在的百宝箱都是采用这种形式。<br />　　使用OTA来发布程序，需要如下几个步骤：<br />　　1、在你的WEB服务器上添加对于jad和jar文件的MIME支持。<br />　　后缀名:jad<br />　　MIME类型:text/vnd.sun.j2me.app-descriptor<br />　　后缀名:jar<br />　　MIME类型:application/java-archive<br />　　2、发布WML页面：<br />　　例如你的jar文件名test.jad，则最简单的下载页面是：<br />　　&lt;?xml version="1.0"?&gt; <br />　　&lt;!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.3//EN" <br />　　"<a href="http://www.wapforum.org/DTD/wml13.dtd">http://www.wapforum.org/DTD/wml13.dtd</a>"&gt; <br />　　&lt;wml&gt; <br />　　&lt;card id="card1" title="Download Midlet"&gt; <br />　　&lt;a href="test.jad"&gt;test&lt;/a&gt; <br />　　&lt;/card&gt; <br />　　&lt;/wml&gt; <br />　　你可以将以上代码保存在WEB服务器上，例如保存为text.wml<br />　　3、修改jad文件：<br />　　在jad文件中增加　MIDlet-Jar-URL: <a href="http://domain/directory/test.jar">http://domain/directory/test.jar</a><br />　　其中的<a href="http://domain/directory/test.jar">http://domain/directory/test.jar</a>为你的jar文件的路径。<br />　　经过上面的设置，你就可以将你的wml页面路径作为你的WAP下载页面发布了。用户只需要在手机上输入这个路径就可以访问和下载你的程序了。<br /><strong>作者Blog：</strong><a id="ArticleContent1_ArticleContent1_AuthorBlogLink" href="http://blog.csdn.net/Mailbomb/" target="_blank">http://blog.csdn.net/Mailbomb/</a></p>
		</div>
<img src ="http://www.blogjava.net/zjw-albert/aggbug/57130.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zjw-albert/" target="_blank">zjw_albert</a> 2006-07-07 14:27 <a href="http://www.blogjava.net/zjw-albert/archive/2006/07/07/57130.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>实现连接池</title><link>http://www.blogjava.net/zjw-albert/archive/2006/06/06/50898.html</link><dc:creator>zjw_albert</dc:creator><author>zjw_albert</author><pubDate>Tue, 06 Jun 2006 12:36:00 GMT</pubDate><guid>http://www.blogjava.net/zjw-albert/archive/2006/06/06/50898.html</guid><wfw:comment>http://www.blogjava.net/zjw-albert/comments/50898.html</wfw:comment><comments>http://www.blogjava.net/zjw-albert/archive/2006/06/06/50898.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/zjw-albert/comments/commentRss/50898.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zjw-albert/services/trackbacks/50898.html</trackback:ping><description><![CDATA[通常商业数据库JDBC驱动都会提供自已的数据库连接池管理器，无需自己制做。 <br />无论如何，这里给出一个简单实现 <br /><br />实现连接池的关键点： <br />1. 单实例 <br />2. 由实现类来管理数据库连接，包括连接，刷新 <br />3. 重载java.sql.Connection的close功能。当客户程序调用close时不是真正的断开连接，而是将连接归还连接池管理器。 <br />4. 将数据库属性独立于管理器本身 <br /><br />可选： <br />1. 实现javax.sql.PooledConnection <br />2. 实现javax.sql.DataSource <br />3. 实现javax.sql.ConnectionPoolDataSource <br /><br />一个简单实现： <br />import java.io.*; <br />import java.util.*; <br />import java.sql.*; <br /><br />public class ConnectionPool implements Runnable { <br />    static String configFileName; // 如./connection-pool.properties <br />    static Properties config; <br />private static List list = null; <br />    private static boolean isCreate = false; <br />    /** <br />     * 实现单实例，关键点1 <br />     * @throws SQLException <br />     */ <br />public ConnectionPool () throws SQLException { <br />if (list == null) init (); <br />        if (!isCreate) { <br />            Thread thread = new Thread(this); <br />            thread.run(); <br />            isCreate = true; <br />        } <br />} <br /><br />    public synchronized Connection getConnection () { <br />        if (list == null) return null; <br /><br />        // 寻找空闲的连接 <br />        for (int i = 0; i &lt; list.size(); i ++){ <br />            ConnectionWrap conn = (ConnectionWrap)list.get(i); <br />            if (conn.free) { <br />                conn.free = false; <br />                conn.start = System.currentTimeMillis(); <br />                return conn; <br />            } <br />        } <br /><br />        // 没有空闲的连接则自动扩展 <br />        int step = Integer.parseInt(config.getProperty("step")); // 取得自动扩展的步长 <br />        this.addConnection(step); <br />            return (ConnectionWrap)list.get(list.size() - step - 1); <br />    } <br /><br />    public void run () { <br />        long interval = Long.parseLong(config.getProperty("interval")); // 扫描时间 <br />        while (true) { <br />            try { <br />                Thread.sleep(interval); <br />            } catch (Exception e) { <br />                // 出错处理 <br />            } <br />            scan (); <br />        } <br />    } <br /><br />    /** <br />     * 关键点2，管理连接。一些超时的连接刷新 <br />     */ <br />    private void scan () { <br />        int timeout = Integer.parseInt(config.getProperty("timeout")); <br />        for (int i = 0; i &lt; list.size(); i ++) { <br />            ConnectionWrap conn = (ConnectionWrap) list.get(i); <br />            if (conn.start &gt;; 0) { <br />                time = System.currentTimeMillis() - conn.start; <br />                if (time &gt;;= timeout) <br />                    conn.close(); <br />            } <br />        } <br /><br />        int initCount = Integer.parseInt(config.getProperty("init-count")); <br />        if (list.size() &gt;;  initCount) { // 恢复到初始连接数 <br />            for (int i = list.size() - 1; i &gt;; initCount; i --) { <br />                ConnectionWrap conn = (ConnectionWrap) list.get(i); <br />                if (conn.free) { // 真正地断开连接 <br />                    try { <br />                        conn.conn.close(); <br />                    } catch (SQLException ignore){} <br />                    list.remove(conn); <br />                } <br />            } <br />        } <br />    } <br /><br />private void init () throws SQLException { <br />config = readConfig (); <br />createConnectionPool (config); <br />} <br /><br />    /** <br />     * 读取配置文件 <br />     * @return java.util.Properties <br />     * @throws SQLException <br />     */ <br />private void readConfig () throws SQLException { <br />InputStream in = null; <br />        try { <br />            in = new FileInputStream (configFileName); <br />            config = new Properties (); <br />            config.load(in); <br />        } catch (IOException ioe) { // 出错处理 <br />            throw new SQLException (ioe.getMessage()); <br />        } finally { <br />            if (in != null) <br />                try { in.close(); } catch (IOException ignore) {} <br />        } <br />} <br /><br />    private void createConnectionPool () throws SQLException { <br />        String driverName = config.getProperty("driver-name"); <br /><br />        int initCount = Integer.parseInt(config.getProperty("init-count")); <br />        int maxCount = Integer.parseInt(config.getProperty("max-count")); <br />        try { <br />            Driver driver = Class.forName(driverName); <br />            addConnection (initCount); <br />        } catch (Exception e) { <br />            throw new SQLException (e.getMessage()); <br />        } <br />    } <br /><br />    private void addConnection (int count) throws SQLException { <br />        if (list == null) list = new ArrayList (count); <br />        String url = config.getProperty("url"); <br />        String user = config.getProperty("user"); <br />        String password = config.getProperty("password"); <br /><br />        for (int i = 0; i &lt; count; i ++) <br />            list.add(new ConnectionWrap (url, user, password)); <br />    } <br /><br />    class ConnectionWrap implements Connection { <br />        Connection conn = null; <br />        boolean free; <br />        long start; <br />        ConnectionWrap (String url, String user, String password) throws Exception { <br />            Connection conn = DriverManager.getConnection(url, user, password); <br />            free = true; <br />        } <br /><br />        /** <br />         * 这里关键点3，并不真正断开连接，而是归还给管理器 <br />         * @return <br />         * @throws SQLException <br />         */ <br />        public boolean close () throws SQLException { <br />            free = true; <br />            start = 0; <br />        } <br /><br />        // 其他java.sql.Connection的方法 <br />        // ... <br />    } <br />} <br /><br />配置文件示例 <br />driver-name = oracle.jdbc.driver.Driver <br />url = jdbc:oracle:thin:@host:1521:employee <br />user = scott <br />password = tiger <br />timeout = 60000 # 一分钟 <br />init-count = 10 <br />step = 5 <br />interval = 1000 # 1秒 <br />... <br /><br />以后在客户端可以这么调用 <br />ConnectionPool pool = new ConnectionPool (); <br />Connection conn = null; <br />try { <br />conn = pool.getConnection (); <br />// 其他操作 <br />} finally { <br />if (conn != null) conn.close (); <br />} <br /><br />限于篇幅，javax.sql.DataSource, javax.sql.ConnectionPoolDataSource等就不一一列出了<br /><img src ="http://www.blogjava.net/zjw-albert/aggbug/50898.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zjw-albert/" target="_blank">zjw_albert</a> 2006-06-06 20:36 <a href="http://www.blogjava.net/zjw-albert/archive/2006/06/06/50898.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java的网络功能与编程（转载）</title><link>http://www.blogjava.net/zjw-albert/archive/2006/03/20/36282.html</link><dc:creator>zjw_albert</dc:creator><author>zjw_albert</author><pubDate>Mon, 20 Mar 2006 04:28:00 GMT</pubDate><guid>http://www.blogjava.net/zjw-albert/archive/2006/03/20/36282.html</guid><wfw:comment>http://www.blogjava.net/zjw-albert/comments/36282.html</wfw:comment><comments>http://www.blogjava.net/zjw-albert/archive/2006/03/20/36282.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/zjw-albert/comments/commentRss/36282.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zjw-albert/services/trackbacks/36282.html</trackback:ping><description><![CDATA[
		<font face="宋体">Java的</font>
		<a class="wordstyle" href="http://www.yeaho.net/" target="_blank">
				<font face="宋体">网络</font>
		</a>
		<font face="宋体">功能与编程<br />徐迎晓<br />(上海大学计算中心25＃)<br />                       <br />摘  要：Java语言是Internet上最热门的编程语言，本文针对<br /><br />       Java的</font>
		<a class="wordstyle" href="http://www.yeaho.net/" target="_blank">
				<font face="宋体">网络</font>
		</a>
		<font face="宋体">功能，对Java从</font>
		<a class="wordstyle" href="http://www.yeaho.net/" target="_blank">
				<font face="宋体">网络</font>
		</a>
		<font face="宋体">上获取图象、声音、<br /><br />       HTML文档及文本文件等编程方法作了初步的介绍，同<br /><br />       时介绍了动态获取</font>
		<a class="wordstyle" href="http://www.yeaho.net/" target="_blank">
				<font face="宋体">网络</font>
		</a>
		<font face="宋体">上资源的方法作了介绍。文中<br /><br />       提供了大量简明易懂的实例。<br /><br />关键词：Java；Internet；</font>
		<a class="wordstyle" href="http://www.yeaho.net/" target="_blank">
				<font face="宋体">网络</font>
		</a>
		<br />
		<br />
		<br />
		<br />
		<font face="宋体">    Java语言是Internet上新兴的编程语言，对Java的特性以及基<br /><br />本的编程方法已有很多文章作过介绍。但是，广大Java爱好者更希望<br /><br />了解Java更深一步的编程方法，本文就Java的</font>
		<a class="wordstyle" href="http://www.yeaho.net/" target="_blank">
				<font face="宋体">网络</font>
		</a>
		<font face="宋体">功能及其编程方法<br /><br />作一初步的介绍。<br /><br />    为了方便初次接触Java的读者，本文先就Java编程的一些常识<br /><br />作简单介绍。<br /><br /><br /><br />    一、Java编程简介<br /><br /><br /><br />    1. 编程环境：<br /><br /><br /><br />    对于大部分读者，以下的配置是较为经济的一种选择：<br /><br />操作系统 Win95<br /><br />编译软件 JDK1.01<br /><br />浏览软件 Netscape2.0以上（32位）<br /><br /><br /><br />    2. 编程方法：<br /><br /><br /><br />    先用文本编辑器如Edit、NotePad等输入Java程序，以.java为<br /><br />文件名后缀存盘。<br /><br />    再执行命令行：“Javac 文件名”来编译Java程序。编译后生成<br /><br />后缀为.class的字节码文件。<br /><br />    最后，如果是Java Applitcation，则执行命令行：“Java 字<br /><br />节码文件名”来运行Java程序。<br /><br />    如果是Java Applet，则用文本编辑器输入调用该Java Applet<br /><br />的HTML 文档， 以 .htm 为文件名后缀存盘。 再执行命令行：<br /><br />“appletviewer HTML文件名”来运行Java Applet。或用Netscape<br /><br />打开该HTML文档。<br /><br /><br /><br />    3. 关于本文中程序的说明<br /><br /><br /><br />    为了使程序能够最简洁地体现其所代表的编程方法，本文中的程<br /><br />序一般采用最简单的形式，省略了线程等内容。因此，本文的程序不<br /><br />是“好”的程序，但最容易为初学者理解。<br /><br />    本文的所有程序经编译后，生成的字节码文件及对应的HTML文档<br /><br />已上载到http://www.shu.edu.cn/~xyx/test/jvnet， 均可正确<br /><br />运行。连入Internet的读者可用浏览器打开该地址，查看运行效果。<br /><br />    连入Internet的读者也可以在本地硬盘输入并编译本文的程序，<br /><br />用Netscape的File/Open File菜单打开HTML文档，体会编程方法并<br /><br />查看运行效果。如果读者想将Java Applet 放到自己的主机上或其他<br /><br />ftp服务器上，在Netscape中用http协议或ftp协议调用，出于安全<br /><br />性限制，应作如下修改：<br /><br />   如果读者在某个WWW主机上有帐号，可以做个人Homepage（一般<br /><br />在用户根目录创建WWW或public_html目录即可，Homepage的地址为<br /><br />http://HostName/~个人帐号），可将本文程序中对应的<br /><br />http://www.shu.edu.cn/~xyx/部分修改为读者自己的Web结点地址，<br /><br />然后将编译后生成的字节码文件及对应的HTML文档上载到自己的结点上。<br /><br />    如果读者的计算机连入了Internet，也可以找一个可以上载的<br /><br />ftp结点，如：ftp://ftp.shnet.edu.cn/incoming，将本文程序中<br /><br />对应的http://www.shu.edu.cn/~xyx/部分修改为ftp结点的地址，<br /><br />将编译后生成的字节码文件及对应的HTML文档上载到该结点上，以查<br /><br />看运行效果。<br /><br />    如果读者的计算机没有联网，也可以在单机上运行Web 服务软<br /><br />件如Webstar for Win95，将本文程序中对应的http: //www. shu<br /><br />.edu.cn/~xyx/部分修改为“http://本地IP地址”的形式，来模拟<br /><br /></font>
		<a class="wordstyle" href="http://www.yeaho.net/" target="_blank">
				<font face="宋体">网络</font>
		</a>
		<font face="宋体">编程。<br /><br /><br /><br />    二、Java</font>
		<a class="wordstyle" href="http://www.yeaho.net/" target="_blank">
				<font face="宋体">网络</font>
		</a>
		<font face="宋体">功能及获取</font>
		<a class="wordstyle" href="http://www.yeaho.net/" target="_blank">
				<font face="宋体">网络</font>
		</a>
		<font face="宋体">上资源的一般步骤<br /><br /><br /><br />    Java程序可以获取</font>
		<a class="wordstyle" href="http://www.yeaho.net/" target="_blank">
				<font face="宋体">网络</font>
		</a>
		<font face="宋体">上结点的图象、声音、HTML文档及文本<br /><br />等资源，并可以对获得的资源进行处理。例如Java程序可以每隔一<br /><br />定时间读取某结点提供的最新数据，并以图表的形式显示出来。<br /><br />    在编程处理上，一般先生成一个URL类型的对象，然后用 Java<br /><br />中相应的方法（method）获取该对象所代表的资源。下面分别介绍<br /><br />Java</font>
		<a class="wordstyle" href="http://www.yeaho.net/" target="_blank">
				<font face="宋体">网络</font>
		</a>
		<font face="宋体">功能的几个例子，并由此介绍几种不同的编程方法。<br /><br /><br /><br />    三、从</font>
		<a class="wordstyle" href="http://www.yeaho.net/" target="_blank">
				<font face="宋体">网络</font>
		</a>
		<font face="宋体">上获取图象<br /><br /><br /><br />    Java Applet可以直接从</font>
		<a class="wordstyle" href="http://www.yeaho.net/" target="_blank">
				<font face="宋体">网络</font>
		</a>
		<font face="宋体">上结点获取图象并显示出来。 为<br /><br />了了解其编程方法和从本地显示图象的编程有何不同，我们先不考虑<br /><br /></font>
		<a class="wordstyle" href="http://www.yeaho.net/" target="_blank">
				<font face="宋体">网络</font>
		</a>
		<font face="宋体">功能，来看一个简单的图象显示的例子：<br /><br /><br /><br />●程序1<br /><br />import java.applet.*;<br /><br />import java.awt.*;<br /><br />public class imag0 extends Applet{<br /><br />  Image image;<br /><br />  public void init() {<br /><br />image=getImage(getDocumentBase(),"test.gif");<br /><br />  }<br /><br />  public void paint(Graphics g) {<br /><br />     g.drawImage(image, 0, 0,this);<br /><br />  }<br /><br />}<br /><br /><br /><br />    这是一个最简单的获取并显示图象的例子， 在该例中， 先用<br /><br />getImage(getDocumentBase(),图象文件名)从HTML文档所在位置调<br /><br />用图象test.gif，并由此生成一个Image类型的对象image， 然后用<br /><br />drawImage(image, 0, 0,this)在屏幕上将图象显示出来。<br /><br />    如果想从</font>
		<a class="wordstyle" href="http://www.yeaho.net/" target="_blank">
				<font face="宋体">网络</font>
		</a>
		<font face="宋体">上其他结点获取图象，关键是创建对应于</font>
		<a class="wordstyle" href="http://www.yeaho.net/" target="_blank">
				<font face="宋体">网络</font>
		</a>
		<font face="宋体">上<br /><br />其他结点的Image类型的对象，一旦获得Image类型的对象获得了，<br /><br />便可以对其进行任何可能的图象操作。<br /><br />    Java提供了如下方法可以创建对应于其他结点的图象：<br /><br />getImage(new URL(字符串))<br /><br />    其使用格式可有两种：<br /><br /><br /><br />    String  url = "结点URL";<br /><br />    Image image;<br /><br />    try {<br /><br />      image = getImage(new URL(url));<br /><br />    } <br /><br />catch(Exception e){<br /><br />System.out.println("Can't open the URL ");<br /><br />    }<br /><br /><br /><br />或<br /><br /><br /><br />URL imgur=null;<br /><br />Image image;<br /><br />try {<br /><br />            imgur=new URL("结点URL ");<br /><br />     }<br /><br />     catch (MalformedURLException e) {<br /><br />            System.out.println("Can't open the URL ");<br /><br />     }<br /><br />     image=getImage(imgur);<br /><br /><br /><br />    前一种格式用“new URL(url)”生成 URL 对象， 并直接作为<br /><br />getImage的参数，后一种格式先用“new URL(url)”生成一个 URL<br /><br />对象，再传给getImage。两种格式本质上是一样的。两种格式中，<br /><br />生成URL对象的部分都包含在<br /><br /><br /><br />try{<br /><br />获取URL对象<br /><br />                           }<br /><br />catch (MalformedURLException e) {<br /><br />出错提示<br /><br />                           }<br /><br />中。<br /><br />    例如要调用http://www.shu.edu.cn/~xyx/img/shnet.jpg结点<br /><br />的图象，第一种格式完整的程序如下：<br /><br />●程序2<br /><br />import java.applet.*;<br /><br />import java.net.*;<br /><br />import java.awt.*;<br /><br />public class imag extends Applet{<br /><br />  Image image;<br /><br />  public void init() {<br /><br />    String  url = "http://www.shu.edu.cn/~xyx/img/shnet.jpg";<br /><br />    try {<br /><br />      image = getImage(new URL(url));<br /><br />    } catch(Exception e){}<br /><br />  }<br /><br /><br /><br />  public void paint(Graphics g) {<br /><br />     g.drawImage(image, 0, 0,this);<br /><br />  }<br /><br />}<br /><br /><br /><br />    第二种格式完整的程序如下：<br /><br />●程序3<br /><br />import java.applet.*;<br /><br />import java.net.*;<br /><br />import java.awt.*;<br /><br />public class imag2 extends Applet{<br /><br />  Image image;<br /><br />  URL imgur=null;<br /><br />  public void init() {<br /><br />     try {<br /><br />      imgur=new URL("http://www.shu.edu.cn/~xyx/img/shnet.jpg");<br /><br />         }<br /><br />        catch (MalformedURLException e) {<br /><br /><br /><br />                System.out.println("Can't open the URL ");<br /><br />      }<br /><br />      image=getImage(imgur);<br /><br />  }<br /><br />  public void paint(Graphics g) {<br /><br />     g.drawImage(image, 0, 0,this);<br /><br />  }<br /><br />}<br /><br /><br /><br />    将上述两个程序分别以imag.java和imag2. java 存盘， 执行<br /><br />javac imag.java和javac imag2.java，将得到编译后生成的imag<br /><br />.class和imag2.class，最后创建调用这两个Java Applet的HTML文<br /><br />档，如imag.class对应的HTML文档可如下：<br /><br />&lt; html &gt;<br /><br />&lt; head &gt;<br /><br />&lt; title &gt;Example &lt; /title &gt;<br /><br />&lt; /head &gt;<br /><br />&lt; center &gt;<br /><br />&lt; applet code=imag.class width=550 height=250 &gt;<br /><br />&lt; /applet &gt;<br /><br />&lt; /html &gt;<br /><br /><br /><br />    将该HTML文档存入test.html文件，用Netscape打开， 如果你<br /><br />的计算机连入了Internet，便可以看到Java Applet 所显示的从网<br /><br />络上获得的图象了。（对于本文中其他不同的Java Applet， 对应<br /><br />的HTML文档只要修改其中相应的“code=imag.class”即可。）<br /><br /><br /><br />    四、从</font>
		<a class="wordstyle" href="http://www.yeaho.net/" target="_blank">
				<font face="宋体">网络</font>
		</a>
		<font face="宋体">上获取声音<br /><br /><br /><br />    Java从</font>
		<a class="wordstyle" href="http://www.yeaho.net/" target="_blank">
				<font face="宋体">网络</font>
		</a>
		<font face="宋体">上获取声音文件并播放声音的编程方法有两类，一<br /><br />是利用Java提供的play(URL)及play(URL,String) 直接播放</font>
		<a class="wordstyle" href="http://www.yeaho.net/" target="_blank">
				<font face="宋体">网络</font>
		</a>
		<br />
		<br />
		<font face="宋体">上的声音文件，另一类是通过getAudioClip(URL)或getAudioClip<br /><br />(URL,String)先从</font>
		<a class="wordstyle" href="http://www.yeaho.net/" target="_blank">
				<font face="宋体">网络</font>
		</a>
		<font face="宋体">上获取声音文件，并生成AudioClip 类型的<br /><br />对象，然后对该对象进行操作。<br /><br />    前者的使用格式是：<br /><br /><br /><br />String  Audur = "结点URL";<br /><br />        try {<br /><br />     play(new URL(Audur));    <br /><br />        } catch(Exception e){} <br /><br /><br /><br />或<br /><br /><br /><br />String  Audur = "结点URL";<br /><br />        try {<br /><br />           play(new URL(Audur),声音文件名);<br /><br />        } catch(Exception e){}<br /><br />    后者使用的格式是：<br /><br />String Audur = "结点URL";<br /><br />AudioClip  loopClip;<br /><br />    try {<br /><br />           loopClip = getAudioClip(new URL(Audur));<br /><br />        }<br /><br />catch(Exception e){<br /><br />System.out.println("Can't open the URL ");<br /><br />                  }<br /><br /><br /><br />或<br /><br /><br /><br />String Audur = "结点URL";<br /><br />    AudioClip  loopClip;<br /><br />    try {<br /><br />           loopClip = getAudioClip(new URL(Audur) ,声音文件名);<br /><br />                    }<br /><br />catch(Exception e){<br /><br />System.out.println("Can't open the URL ");<br /><br />}<br /><br /><br /><br />    上面的四种格式都是将生成URL对象部分－－“new URL(url)”<br /><br />直接作为play或getAudioClip的参数；和前面处理图象的例子一样，<br /><br />也可以先用“new URL(url)”获取一个URL对象， 再传给 play 或<br /><br />getAudioClip。如对第一种play(URL)的格式， 也可采用如下的编<br /><br />程格式：<br /><br />URL  Audur =null;<br /><br />        try {<br /><br />   Audur=new URL("结点URL ");<br /><br />        } catch(Exception e){<br /><br />System.out.println("Can't open the URL ");<br /><br />     }<br /><br />    play(Audur);<br /><br />    下面对前述四种从</font>
		<a class="wordstyle" href="http://www.yeaho.net/" target="_blank">
				<font face="宋体">网络</font>
		</a>
		<font face="宋体">上获取并播放声音文件的格式各举一简单的例子，<br /><br />以作编程时参考：<br /><br />                         ●程序4   格式一<br /><br />import java.applet.*;<br /><br />import java.awt.*;<br /><br />import java.net.*;<br /><br />public class sound1 extends Applet <br /><br /><br /><br />{   AudioClip  loopClip;<br /><br />    public void paint(Graphics g) {<br /><br />    String  Audur = "http://www.shu.edu.cn/~xyx/java/Animator/audio/bark.au";<br /><br />        try {<br /><br />     play(new URL(Audur));    <br /><br />        } catch(Exception e){} <br /><br />    }<br /><br />}<br /><br /><br /><br />                             ●程序5   格式二<br /><br />import java.applet.*;<br /><br />import java.awt.*;<br /><br />import java.net.*;<br /><br />public class sound2 extends Applet <br /><br />{   AudioClip  loopClip;<br /><br />     public void paint(Graphics g) {<br /><br />        String  Audur = "http://www.shu.edu.cn/~xyx/java/Animator/audio/";<br /><br />        try {<br /><br />           play(new URL(Audur),"bark.au");<br /><br />        } catch(Exception e){}<br /><br />    }<br /><br />}<br /><br /><br /><br />                             ●程序6   格式三<br /><br />import java.applet.*;<br /><br />import java.awt.*;<br /><br />import java.net.*;<br /><br />public class sound extends Applet{<br /><br />   AudioClip  loopClip;<br /><br />   public void init() {<br /><br />     String  Audur = "http://www.shu.edu.cn/~xyx/java/Animator/audio/bark.au";<br /><br />        try {<br /><br />           loopClip = getAudioClip(new URL(Audur));<br /><br />        } catch(Exception e){}<br /><br />    }<br /><br /><br /><br />   public void paint(Graphics g){<br /><br />        loopClip.loop();<br /><br />   }<br /><br />}<br /><br /><br /><br />●程序7  格式四<br /><br />import java.applet.*;<br /><br />import java.awt.*;<br /><br />import java.net.*;<br /><br />public class sound0 extends Applet{<br /><br />   AudioClip  loopClip;<br /><br />   URL auur;<br /><br />   public void init() {<br /><br />     try {<br /><br />            auur=new URL("http://www.shu.edu.cn/~xyx/java/Animator/audio/");<br /><br />      }<br /><br />      catch (MalformedURLException e) {<br /><br />                System.out.println("Can't open the URL ");<br /><br />      }<br /><br />      loopClip = getAudioClip(auur,"bark.au");<br /><br /><br /><br />    }<br /><br /><br /><br />   public void paint(Graphics g){<br /><br />        loopClip.loop();<br /><br />   }<br /><br />}</font>
		<br />
		<br />
		<br />
		<div class="ContentFont" id="NewaspContentLabel" style="PADDING-RIGHT: 10px; DISPLAY: block; PADDING-LEFT: 10px; PADDING-BOTTOM: 0px; PADDING-TOP: 0px">
				<font id="font_word" style="FONT-SIZE: 14px; FONT-FAMILY: 宋体, Verdana, Arial, Helvetica, sans-serif">    五、显示<a class="wordstyle" href="http://www.yeaho.net/" target="_blank">网络</a>上其他HTML文档<br /><br /><br /><br />    利用Java提供的getAppletContext().showDocument(URL)可以<br /><br />显示其他结点的HTML文档，同前面的显示<a class="wordstyle" href="http://www.yeaho.net/" target="_blank">网络</a>上其他结点的图象，<br /><br />有两种格式，下面各举一例：<br /><br />                      ●程序8   格式一<br /><br />import java.applet.*;<br /><br />import java.awt.*;<br /><br />import java.net.*;<br /><br />public class showdoc extends Applet<br /><br />{    <br /><br />    URL docur= null;<br /><br />    public void paint(Graphics g) {<br /><br />      try {<br /><br />            docur=new URL("http://www.shu.edu.cn/~xyx/doc/manhua.html");        <br /><br />      } <br /><br />      catch (MalformedURLException e) {<br /><br />                System.out.println("Can't open the URL ");<br /><br />      }<br /><br />      if (docur != null) {<br /><br />                    getAppletContext().showDocument(docur,"_blank");<br /><br />      }   <br /><br />    }<br /><br />}<br /><br /><br /><br />                          ●程序9 格式二<br /><br />import java.applet.*;<br /><br />import java.awt.*;<br /><br />import java.net.*;<br /><br />public class showdoc2 extends Applet<br /><br />{    <br /><br />   URL docur= null;<br /><br />   public void paint(Graphics g) { <br /><br />      try {<br /><br />getAppletContext().showDocument(new URL("http://www.shu.edu.cn/<br /><br />~xyx/doc/manhua.html"));       <br /><br />      } <br /><br />      catch (MalformedURLException e) {<br /><br />                System.out.println("Can't open the URL ");<br /><br />      }   <br /><br />   }<br /><br />}<br /><br /><br /><br />     六、读取<a class="wordstyle" href="http://www.yeaho.net/" target="_blank">网络</a>上文件内容<br /><br /><br /><br />     前述的<a class="wordstyle" href="http://www.yeaho.net/" target="_blank">网络</a>功能只是显示或播放<a class="wordstyle" href="http://www.yeaho.net/" target="_blank">网络</a>上结点的图象、 声音及<br /><br />HTML文档，并没有对其内容进行处理。事实上，Java还可读取<a class="wordstyle" href="http://www.yeaho.net/" target="_blank">网络</a><br /><br />上文件的内容，并对其内容进行处理。<br /><br />    读取<a class="wordstyle" href="http://www.yeaho.net/" target="_blank">网络</a>上文件内容的步骤可如下：<br /><br />    1. 创建一个URL类型的对象<br /><br />    如：<br /><br />    String url = "ftp://202.120.127.218/incoming/test/readtxt.html";<br /><br />URL fileur;<br /><br />        try { <br /><br />fileur = new URL(url); } <br /><br />        catch ( MalformedURLException e) { <br /><br />               System.out.println("Can't get URL: " );<br /><br />        }<br /><br />    2. 利用URL类的openStream()，获得对应的InputStream类的对象<br /><br />    如：<br /><br />InputStream filecon = fileur.openStream();<br /><br />    3. 将InputStream对象转化为DataInputStream类的对象<br /><br />    如：<br /><br />    DataInputStream filedata = new DataInputStream(filecon);<br /><br />    4. 读取内容<br /><br />    如对前面的filedata，可用filedata.readLine() 一行一行读<br /><br />取内容，或用filedata.readchar一个字符一个字符读取内容。 对<br /><br />读取到的内容，可由Java Applet进行各种处理， 并将处理结果用<br /><br />各种方式显示出来。<br /><br />    下面的例子是读取 http://www.shu.edu.cn/~xyx/doc/manhua.html<br /><br />文件内容的例子，为简洁起见，该例中只将文件的内容逐行读出，<br /><br />并在文本区显示出来。<br /><br />●程序10<br /><br />import java.io.*;<br /><br />import java.net.*;<br /><br />import java.awt.*;<br /><br />import java.applet.*;<br /><br />public class showfile extends Applet{<br /><br />     URL fileur;<br /><br />     TextArea showarea = new TextArea("Please wait a while for get<br /><br />text",10,70);<br /><br />     public void init() {<br /><br />        String url = "http://www.shu.edu.cn/~xyx/doc/manhua.html";<br /><br />        try { fileur = new URL(url); } <br /><br />        catch ( MalformedURLException e) { <br /><br />               System.out.println("Can't get URL: " );<br /><br />        }<br /><br />        add(showarea);<br /><br />}<br /><br /><br /><br />    public void paint(Graphics g) {<br /><br />        InputStream filecon = null;<br /><br />        DataInputStream filedata = null;<br /><br />        String fileline;<br /><br />try {<br /><br />                filecon = fileur.openStream();<br /><br />                filedata = new DataInputStream(filecon);<br /><br />                while ((fileline = filedata.readLine()) != null) {<br /><br />                        showarea.appendText(fileline+"\n");<br /><br />}<br /><br />}<br /><br />catch (IOException e) {<br /><br />                System.out.println("Error in I/O:" + e.getMessage());<br /><br />}<br /><br />   }<br /><br />}<br /><br /><br /><br />    七、动态使用<a class="wordstyle" href="http://www.yeaho.net/" target="_blank">网络</a>上资源<br /><br />    在前面介绍的例子的基础上，可以动态地利用<a class="wordstyle" href="http://www.yeaho.net/" target="_blank">网络</a>上的资源。<br /><br />其方法是编制一个线程，每隔一定时间自动到相应结点读取最新的<br /><br />内容。本文对线程的编制不再展开，读者可参考有关文章或直接套<br /><br />用下面的例子。<br /><br />    例如对上例中读取http://www.shu.edu.cn/~xyx/doc/manhua<br /><br />.html文件内容的例子，加入线程后如下所示。该例子每隔5秒更新<br /><br />一次数据。如果http://www.shu.edu.cn/~xyx/doc/manhua.html中<br /><br />存放的是一些变化较快的信息如股市行情等，并有程序随时动态地<br /><br />更新其内容，则在Web中加入这种Java Applet，可以让流览者得到<br /><br />动态的信息。进一步，也可以在程序中对数据进行处理，并用图形<br /><br />方式显示处理结果。例如将各时刻的数据绘制成曲线，流览者可以<br /><br />看到动态变化的曲线。<br /><br />//程序11<br /><br />import java.io.*;<br /><br />import java.net.*;<br /><br />import java.awt.*;<br /><br />import java.applet.*;<br /><br />public class dynashow extends java.applet.Applet<br /><br />    implements Runnable {<br /><br />    Thread dthread;<br /><br />    URL fileur;<br /><br />TextArea showarea = new TextArea("Wait for a while...",10,70);<br /><br />     public void init() {<br /><br />        String url = " http://www.shu.edu.cn/~xyx/doc/manhua.html ";<br /><br />        try { fileur = new URL(url); } <br /><br />        catch ( MalformedURLException e) { <br /><br />               System.out.println("Can't get URL: " );<br /><br />        }<br /><br />        add(showarea);<br /><br />     }<br /><br /><br /><br />     public void start() {<br /><br />        if (dthread == null) <br /><br />        {<br /><br />                dthread = new Thread(this);<br /><br />                dthread.start();<br /><br />        }<br /><br />    }<br /><br />    public void stop() {<br /><br />        if (dthread != null) {<br /><br />                dthread.stop();<br /><br />                dthread = null;<br /><br />        }<br /><br />    }<br /><br /><br /><br />    public void run() {<br /><br />        InputStream filecon = null;<br /><br />        DataInputStream filedata = null;<br /><br />        String fileline;<br /><br />        while(true){<br /><br />            try {<br /><br />                filecon = fileur.openStream();<br /><br />                filedata = new DataInputStream(filecon);<br /><br />                while ((fileline = filedata.readLine()) != null) {<br /><br />                        showarea.appendText(fileline+"\n");<br /><br />        }<br /><br />            }<br /><br />           catch (IOException e) {<br /><br />                System.out.println("Error in I/O:" + e.getMessage());<br /><br />           }<br /><br />           try{<br /><br />                dthread.sleep(5000);<br /><br />           }<br /><br />           catch (InterruptedException e){}<br /><br />           repaint();<br /><br />       }<br /><br />     }<br /><br />}<br /><br /><br /><br />    八、Java<a class="wordstyle" href="http://www.yeaho.net/" target="_blank">网络</a>能力的限制<br /><br /><br /><br />    出于安全性考虑，在用netscape浏览时，Java Applet 只能和<br /><br />其所在的主机建立连接，因此，前面的程序编译后大部分只能存放<br /><br />在http://www.shu.edu.cn/~xyx对应的主机上。存放到其他主机时<br /><br />需更改程序中的结点地址。否则浏览器将显示安全出错。<br /><br />    但对显示<a class="wordstyle" href="http://www.yeaho.net/" target="_blank">网络</a>上其他HTML文档没有此限制（如程序8、9），读<br /><br />者可以将程序编译后放到任意WWW服务器或FTP服务器，均可正常运<br /><br />行。<br /><br />    此外，当浏览器从本地盘打开调用Java Applet的HTML文档时，<br /><br />也不受此限制。因此，本文所有的程序都可存放在本地盘编译，只<br /><br />要用netscape的File/Open File菜单打开，便可正确运行。<br /><br />    对于另一种Java程序－－Java Application，也无此限制，例<br /><br />如对于读取<a class="wordstyle" href="http://www.yeaho.net/" target="_blank">网络</a>上文件内容的程序10，对应的Java Application可<br /><br />作如下编程：<br /><br /><br /><br />●程序11<br /><br />import java.io.*;<br /><br />import java.net.*;<br /><br />import java.awt.*;<br /><br />class showfile2 {<br /><br />     public static void main(String args[]){<br /><br />        InputStream filecon = null;<br /><br />        DataInputStream filedata = null;<br /><br />        String fileline;<br /><br />        String url = "http://www.shu.edu.cn/~xyx/doc/manhua.html";<br /><br />        URL fileur;<br /><br />        try {<br /><br />   fileur = new URL(url);<br /><br />                filecon = fileur.openStream();<br /><br />                filedata = new DataInputStream(filecon);<br /><br />                while ((fileline = filedata.readLine()) != null) {<br /><br />System.out.println(fileline+"\n");<br /><br />}<br /><br />}<br /><br />catch (IOException e) {<br /><br />                System.out.println("Error in I/O:" + e.getMessage());<br /><br />}<br /><br />  }<br /><br />}<br /><br />    将其以showfile2.java存盘，用javac showfile2.java编译后，<br /><br />只需执行“java showfile2”便可以在屏幕上打印出<br /><br />http://www.shu.edu.cn/~xyx/doc/manhua.html 文件的内容。<br /><br /><br /><br />    九、创建URL对象的方法<br /><br /><br /><br />    在前面的例子中我们统一使用new URL(url字符串)的形式创建<br /><br />URL对象。其实，Java提供了四种创建URL对象的形式：<br /><br />    1.new URL(url字符串)    本文中的程序均采用此种格式，如：<br /><br />new  URL("http://www.shu.edu.cn/~xyx/doc/manhua.html")<br /><br />    2.new URL(协议，主机名，文件名或路径)    如程序2中的<br /><br />String  url = "http://www.shu.edu.cn/~xyx/img/shnet.jpg";<br /><br />image = getImage(new URL(url));部分可改为：<br /><br />image = getImage(new URL("http","www.shu.edu.cn","/~xyx /img/shnet.jpg"));<br /><br />    3.new URL(协议，主机名，端口号，文件名或路径)1<br /><br />如：new URL("http","www.shu.edu.cn",80, "/~xyx/doc/manhua.html")<br /><br />    4.new URL(基准url，文件名或路径)<br /><br /><br /><br />    十、实现<a class="wordstyle" href="http://www.yeaho.net/" target="_blank">网络</a>功能的其他方法<br /><br /><br /><br />    以上着重介绍了利用Java的URL类实现从<a class="wordstyle" href="http://www.yeaho.net/" target="_blank">网络</a>上获取声音、 图<br /><br />象、HTML文档及文件数据的编程方法。Java的<a class="wordstyle" href="http://www.yeaho.net/" target="_blank">网络</a>功能很强大，除<br /><br />上面介绍的外，还可以利用URLconnection 类实现更广泛的<a class="wordstyle" href="http://www.yeaho.net/" target="_blank">网络</a>功<br /><br />能，如向WWW 服务器上的 CGI 程序发送信息等； 通过 Socket 及<br /><br />ServerSocket类，可以自己编写客户软件及服务软件，并可以自己<br /><br />设计通讯协议。<br /><br /><br /><br />〖参考文献〗<br /><br />Laura Lemay,Charles L. Perkins  "Teach Yourself JAVA in 21 Days" <br /><br />摘自《Internet世界》 </font>
		</div>
<img src ="http://www.blogjava.net/zjw-albert/aggbug/36282.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zjw-albert/" target="_blank">zjw_albert</a> 2006-03-20 12:28 <a href="http://www.blogjava.net/zjw-albert/archive/2006/03/20/36282.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java入门笔记_Socket（转载）</title><link>http://www.blogjava.net/zjw-albert/archive/2006/03/20/36281.html</link><dc:creator>zjw_albert</dc:creator><author>zjw_albert</author><pubDate>Mon, 20 Mar 2006 04:21:00 GMT</pubDate><guid>http://www.blogjava.net/zjw-albert/archive/2006/03/20/36281.html</guid><wfw:comment>http://www.blogjava.net/zjw-albert/comments/36281.html</wfw:comment><comments>http://www.blogjava.net/zjw-albert/archive/2006/03/20/36281.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/zjw-albert/comments/commentRss/36281.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zjw-albert/services/trackbacks/36281.html</trackback:ping><description><![CDATA[
		<font face="宋体">1. Client/Server Networking<br />Java通过socket来完成它所有的</font>
		<a class="wordstyle" href="http://www.yeaho.net/" target="_blank">
				<font face="宋体">网络</font>
		</a>
		<font face="宋体">底层的通讯，socket是一种通讯的通道，通过它可以将数据通过特定的端中发送及接收。Java中的socket可以分成二大类：<br /><br />（1） Datagram Sockets：数据包socket；<br /><br />（2） Stream Sockets：流socket；<br /><br />1.2 Datagram Socket<br />Datagram socket使用UDP来实现数据通讯，因此它不能保证数据能够到达目的地，但是由于它不需要专用的</font>
		<a class="wordstyle" href="http://www.yeaho.net/" target="_blank">
				<font face="宋体">网络</font>
		</a>
		<font face="宋体">链接，所以它所需的资源相对少的多。<br /><br />Datagram以包的方式发送数据，但它不能保证这些数据包以特定的顺序到达目的，因此包中往往需要包含序列号的信息，接收方可以根据序列号的信息决定是否所有的包都已收到，并按正常顺序重组这些包。<br /><br />Java通过两个类DatagramSocket和DatagramPacket来支持Datagram socket。DatagramSocket实现了Datagram socket的基本功能，而DatagramPacket则提供了对包的一些支持。<br /><br />DatagramSocket的几个重要方法：<br /><br />（1） DatagramSocket()：随机绑定一个有效的端口；<br /><br />（2） DatagramSocket(int port)：绑定指定的端口；<br /><br />（3） Void send(DatagramPacket p)：发送数据报，由于目的地的地址信息已包含在数据报中，所以不需要在本函数中提供地址信息；<br /><br />（4） synchronized void receive(DatagramPacket p)：接收数据包，线程安全；<br /><br />（5） synchronized void close()：关闭socket；<br /><br />在DatagramSocket中并不区分ServerSocket和ClientSocket，如果一定要区分，那么发送的是client，而接收的是server。<br /><br />DatagramPacket有以几个重要的方法：<br /><br />（1） DatagramPacket(byte ibuf[], int ilength)：用于接收数据报；<br /><br />（2） DatagramPacket(byte ibuf[], int ilength, InetAddressiaddr, int iport)：用于发送的数据报；<br /><br />（3） byte[] getData()<br /><br />（4） int getLength()<br /><br />以下是完整的Datagram Socket的例子：<br /><br />接收端，Server端代码：<br /><br />import java.io.*;<br /><br />import java.net.*;<br /><br /><br /><br />class FortuneServer1 extends Thread<br /><br />{<br /><br />DatagramSocket ServerSocket;<br /><br />public FortuneServer1() <br /><br />{ <br /><br />super("FortuneServer1");<br /><br />try <br /><br />{<br /><br />ServerSocket = new DatagramSocket(1114);<br /><br />System.out.println("FortuneServer up and running...");<br /><br />}<br /><br />catch (SocketException e) <br /><br />{<br /><br />System.err.println("Exception: couldn't create datagram socket");<br /><br />System.exit(1);<br /><br />} } <br /><br /><br /><br />public static void main(String[] args) <br /><br />{<br /><br />FortuneServer1 server = new FortuneServer1();<br /><br />server.start();<br /><br />}<br /><br /><br /><br />public void run() <br /><br />{<br /><br />if (ServerSocket == null)<br /><br />return;<br /><br /><br /><br />while (true) <br /><br />{<br /><br />try <br /><br />{<br /><br />InetAddress address;<br /><br />int port;<br /><br />DatagramPacket packet;<br /><br />byte[] data = new byte[256];<br /><br />int num = 1;<br /><br /><br /><br />packet = new DatagramPacket(data, data.length);<br /><br />ServerSocket.receive(packet); <br /><br />address = packet.getAddress();<br /><br />port = packet.getPort();<br /><br /><br /><br />File inFile = new File("Fortunes.txt");<br /><br />FileInputStream inStream = new FileInputStream(inFile);<br /><br /><br /><br />if (inStream.read(data) &lt;= 0) <br /><br />{<br /><br />System.err.println("Error: couldn't read fortunes"); <br /><br />}<br /><br /><br /><br />packet = new DatagramPacket(data, data.length, address, port);<br /><br />ServerSocket.send(packet);<br /><br />}<br /><br />catch (Exception e) <br /><br />{<br /><br />System.err.println("Exception: " + e);<br /><br />e.printStackTrace();<br /><br />} } } }<br /><br />说明：<br /><br />（1） 这个例子中接收端的socket使用了多线程，多线程的概念可以参考本文的多线程部分；<br /><br />（2） 在构造函数中创建了DatagramSocket，并且使用了1114这个端口；<br /><br />（3） 本例子的关键函数是run，它使用了死循环，在循环中使用了receive这方法来临听1114端口，如果1114端口没有请求数据到来，那么这个程序就一直停留在receive这个位置，不再往下执行；<br /><br />（4） 当1114端有数据时，receive方法将接收到的DatagramPacket数据包放在packet这个对象中，然后解析其中的数据，获取发送方的地址信息；<br /><br />（5） 然后再创建DatagramPacket包，并填充数据，发送到原接收端。<br /><br />以下是发送端的代码：<br /><br />import java.io.*;<br /><br />import java.net.*; <br /><br />class FortuneClient<br /><br />{<br /><br />public static void main(String args[])<br /><br />{<br /><br />FortuneClient client = new FortuneClient();<br /><br />System.out.println(client.getMessage());<br /><br />}<br /><br /><br /><br />public String getMessage()<br /><br />{<br /><br />String fortune;<br /><br />try {<br /><br />DatagramSocket socket;<br /><br />DatagramPacket packet;<br /><br />byte[] data = new byte[256];<br /><br /><br /><br />socket = new DatagramSocket();<br /><br />packet = new DatagramPacket(data, data.length,InetAddress.getByName("127.0.0.1"), 1114);<br /><br />socket.send(packet);<br /><br /><br /><br />packet = new DatagramPacket(data, data.length);<br /><br />socket.receive(packet);<br /><br />fortune = new String(packet.getData(), 0);<br /><br />socket.close();<br /><br />}<br /><br />catch (UnknownHostException e) {<br /><br />System.err.println("Exception: host could not be found");<br /><br />return null;<br /><br />}<br /><br />catch (Exception e) {<br /><br />System.err.println("Exception: " + e);<br /><br />e.printStackTrace();<br /><br />return null;<br /><br />}<br /><br />return fortune;<br /><br />} }<br /><br />客户端的代码与服务器端的代码基本相同，只是没有了循环，并且处理步骤与服务器端的基本相反。这也说明了Datagram Socket不真正区分Server和Client。<br /><br />1.3 Stream Socket<br />Stream Socket与Datagram Socket不同，它有一个永久性的链接，可以确保数据可靠的发送到对方。但是Stream Socket所占的资源更多。<br /><br />Java主要通过Socket及ServerSocket来实现Stream Socket，一个用于客户端，另一个用户服务器端。<br /><br />Socket类的几个重要方法如下：<br /><br />（1） Socket(String host, int port)<br /><br />（2） Socket(InetAddress address, int port)<br /><br />（3） synchronized void close()<br /><br />（4） InputStream getInputStream()<br /><br />（5） OutputStream getOutputStream()<br /><br />可以看出Stream Socket中的Socket与Datagram Socket中的Socket的区别：<br /><br />（1） 在构造函数中，这里需要指定服务器的地址与端口，用于它发送数据之前建立链接，而Datagram的Socket不需要建立链接，它仅需要在要发送的数据包中包含地址信息即可；<br /><br />（2） Stream Socket的两个重要方法和其它流的方法类似，而且在操作上也相似，其实在操作Stream Socket时，只要建立了链接，那么以后的操作和流的操作一样了，你可以忘了你在操作Socket，只当做自己在操作普通的流。<br /><br />ServerSocket有以下几个重要的方法：<br /><br />（1） ServerSocket(int port)：监听指定端口，监听时间为默认值50；<br /><br />（2） ServerSocket(int port, int count)：监听指定端口，并指定监听时间；<br /><br />（3） ServerSocket(int port, int backlog, InetAddress bindAddr)：只接收指定接口发过来的数据；<br /><br />（4） Socket accept()：accpet方法会返回一个Socket对象，使用该Socket对象的getInputStream及getOutputStream方法获取输入及输出流。由此可见无论是服务器端还是客户端，它们都是通过Socket对象来收发数据的。程序执行到accpet时会进入监听状态，不再向下执行一直到接收到数据。<br /><br />（5） void close()<br /><br />以下是关于Stream Socket的一个例子，在这个例子中使用单独的二个类Receiver和Sender负责对指定的输入及输出流进行操作，用另一个类SocketPerformer来创建Receiver和Sender这两个类的实例，并传入指定的输入及输出流，而在Client及Server这两个类中，负责创建SocketPerformer对象，并传入指定的Socket。因此这五个类在功能上分为三层，第一层负责对流进行操作，第二层负责创建指定的Socket流，并这些Socket流传到第一层，第三层负责创建Socket并将这些Socket传到第二层。<br /><br />Receriver代码：<br /><br />package socketChat;<br /><br />import java.io.BufferedReader;<br /><br />public class Receiver extends Thread {<br /><br />BufferedReader reader;<br /><br />public Receiver(BufferedReader theSocketReader) {<br /><br />reader = theSocketReader;<br /><br />}<br /><br /><br /><br />public void run() {<br /><br />while (true) {<br /><br />try {<br /><br />String words = reader.readLine(); System.out.println("\r\n&lt;&lt;&lt; " + words);<br /><br />} catch (Exception e) {<br /><br />e.printStackTrace();<br /><br />return;<br /><br />} } }}<br /><br />Sender代码：<br /><br />package socketChat;<br /><br />import java.io.BufferedReader;<br /><br />import java.io.InputStreamReader;<br /><br />import java.io.PrintWriter;<br /><br /><br /><br />public class Sender extends Thread { <br /><br />PrintWriter writer;<br /><br />public Sender(PrintWriter theWriter) {<br /><br />writer = theWriter;<br /><br />}<br /><br />public void run() {<br /><br />try {<br /><br />while (true) {<br /><br />BufferedReader consoleReader = new BufferedReader(<br /><br />new InputStreamReader(System.in));<br /><br />String userInput = consoleReader.readLine();<br /><br />writer.write(userInput + "\r\n");<br /><br />writer.flush(); // send the data in buffer immediately<br /><br />}<br /><br />} catch (Exception e) {<br /><br />e.printStackTrace();<br /><br />return;<br /><br />} }}<br /><br />SocketPerformer代码：<br /><br />package socketChat;<br /><br />import java.io.BufferedReader;<br /><br />import java.io.InputStreamReader;<br /><br />import java.io.PrintWriter;<br /><br />import java.net.Socket;<br /><br />public class SocketPerformer {<br /><br />Socket socket;<br /><br />public SocketPerformer(Socket theSoc){<br /><br />socket = theSoc;<br /><br />}<br /><br />public void execut() throws Exception{<br /><br />BufferedReader socketReader = new BufferedReader(new InputStreamReader(<br /><br />socket.getInputStream()));<br /><br />PrintWriter socketWriter = new PrintWriter(socket.getOutputStream());<br /><br />System.out.println("connection built !"); <br /><br /><br /><br />Receiver rec = new Receiver(socketReader); <br /><br />rec.start();<br /><br /><br /><br />Sender sender = new Sender(socketWriter);<br /><br />sender.start();<br /><br />}}<br /><br />Server代码：<br /><br />package socketChat;<br /><br /><br /><br />import java.net.ServerSocket;<br /><br />import java.net.Socket;<br /><br />public class Server {<br /><br />public static void main(String[] args) throws Exception { <br /><br />ServerSocket server = new ServerSocket(30000, 5);<br /><br />Socket socket = null;<br /><br />System.out.println("waiting incoming connection...");<br /><br />socket = server.accept();<br /><br />System.out.println("a connection built!");<br /><br />System.out.println("the peer ip is: " + socket.getInetAddress().getHostAddress());<br /><br />new SocketPerformer(socket).execut();<br /><br />server.close();<br /><br />}}<br /><br />Client端代码如下：<br /><br />package socketChat;<br /><br />import java.net.Socket;<br /><br />public class Client {<br /><br /><br /><br />public static void main(String[] args) throws Exception {<br /><br />String ip = "127.0.0.1"; <br /><br />int port = 30000;<br /><br />System.out.println("connecting to server: " + ip <br /><br />+ " at port: " + port + " ..."); <br /><br /><br /><br />Socket soc = new Socket(ip, port);<br /><br />new SocketPerformer(soc).execut();<br /><br />}}<br /><br />2. 其它<br />（1） 常量定义以final做修饰符，如final int I = 3；final还可以用在class及method上，如果用在class上，那么该class不能被继承，如果用在method上，那么该method不能被重载<br /><br />（2） 类变量定义：static int sum<br /><br />（3） 判断对象类型：objName instanceof className，如"helloWorld" instanceof String，判断的结果是true<br /><br />（4） 提取对象的类名：objName.getClass().getName()<br /><br />（5） java.lang：Java最基本的包，包含java语言最基本的定义<br /><br />（6） java.util：包含如Date，及基本的集合类，如Vector、Hashtable等<br /><br />（7） java.io：包含输入输出的定义<br /><br />（8） java.net：包含如Socket等<br /><br />（9） java.awt：用于Window界面开发<br /><br />（10） java.applet：用于applet开发<br /><br />（11） null关键字引用null对象，注意大小写<br /><br />（12） 每个基本的数据类型如int，都有相应的类与之对应中Int<br /><br />（13） 构造函数名与类名相同，并且不需要返回类型，即在构造函数前不需要加类型修饰符<br /><br />（14） 调用自身的构造函数：this(参数列表);<br /><br />（15） 调用父类的构造函数：super(参数列表);<br /><br />（16） 调用父类已被重载的函数：super.方法名(参数列表);<br /><br />（17） 在同一文件中可以有多个类的定义，但只能有一个类是public并且类名与文件一样，该文件编译成功后会生成多个.class文件，与类的定义一一对应；<br /><br />（18） 接口比抽象类功能强有：抽象类属于特定的类结构树中，它不能被其它树中的类共享；<br /><br />（19） 接口的定义与类的定义类似，只需将class改成interface即可，但接口定义必须是public或者缺省的（package）；<br /><br />（20） 在接口中可以定义方法和变量，接口中的定义的方法应是public并且是abstract的（缺省）；变量的定义必须是public static final（缺省）；<br /><br />（21） String.copyValueOf(buffer, 0, offset)：用于从字符数组中取出字符，并形成字符串；<br /><br />（22） new String(buf, 0, count)<br /><br />（23） System.in(标准输入)是一个InputStream；<br /><br />（24） System.err是一个PrintStream；<br /><br />（25） System.out是一个PrintStream；</font>
		<br />
<img src ="http://www.blogjava.net/zjw-albert/aggbug/36281.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zjw-albert/" target="_blank">zjw_albert</a> 2006-03-20 12:21 <a href="http://www.blogjava.net/zjw-albert/archive/2006/03/20/36281.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>