﻿<?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-&lt;script language="javascript" src="http://www.shi-ci.com/embeded.do"&gt;&lt;/script&gt;-随笔分类-Java</title><link>http://www.blogjava.net/yglwxl/category/24749.html</link><description /><language>zh-cn</language><lastBuildDate>Sat, 21 Apr 2012 02:24:53 GMT</lastBuildDate><pubDate>Sat, 21 Apr 2012 02:24:53 GMT</pubDate><ttl>60</ttl><item><title>Create Struts 2 Application in Eclipse : HTTP Status 500 </title><link>http://www.blogjava.net/yglwxl/archive/2012/04/21/375434.html</link><dc:creator>九宝</dc:creator><author>九宝</author><pubDate>Fri, 20 Apr 2012 18:41:00 GMT</pubDate><guid>http://www.blogjava.net/yglwxl/archive/2012/04/21/375434.html</guid><wfw:comment>http://www.blogjava.net/yglwxl/comments/375434.html</wfw:comment><comments>http://www.blogjava.net/yglwxl/archive/2012/04/21/375434.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yglwxl/comments/commentRss/375434.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yglwxl/services/trackbacks/375434.html</trackback:ping><description><![CDATA[<a href="http://viralpatel.net/blogs/2009/12/tutorial-create-struts-2-application-eclipse-example.html">http://viralpatel.net/blogs/2009/12/tutorial-create-struts-2-application-eclipse-example.html</a>&nbsp;<br /><br />problem:<br /><h1>HTTP Status 500&nbsp;<br /></h1><pre>java.lang.NullPointerException 	<br />org.apache.struts2.impl.StrutsActionProxy.getErrorMessage(StrutsActionProxy.java:69) 	<br />com.opensymphony.xwork2.DefaultActionProxy.prepare(DefaultActionProxy.java:185) </pre>resolve problem:<br />1. struts.xml should under src<br />2. in struts.xml: &nbsp;<br /><span style="white-space: pre; ">		</span>&lt;action name="login" method="<span style="color: red; ">excute"</span><br /><div><span style="white-space:pre">			</span>class="net.viralpatel.struts2.LoginAction"&gt;</div><a id="uc_a_fake_clicker_735275" style="display:none"></a><script id="uc_phone_parser_js_9462355" name="uc_phone_parser_js_9462355" type="text/javascript">var uc_country = "39";
var uc_area = "06";
var uc_rules = 
{ R:
[
{I:"30051929-67a4-4362-8c27-28b7f6c614fb", C:null, A:null, G:{C:2, A:5, P:7, E:-1, D:-1}, R:/^((?:(?:\+|011|810|00)?))((?:43))((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0?(?: *(?:\)|\.|_| |-) *)?))((?:1)|(?:5[79])|(?:6[7-9]))((?:(?: *(?:\)|\.|_| |-) *)?))((?:[0-9][0-9][0-9][0-9]?[0-9]?[0-9]?[0-9]?[0-9]?[0-9]?[0-9]?))$/ },
{I:"e608cc38-216d-4e15-b2ef-de481e150d56", C:null, A:null, G:{C:2, A:5, P:7, E:-1, D:-1}, R:/^((?:(?:\+|011|810|00)?))((?:43))((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0?(?: *(?:\)|\.|_| |-) *)?))((?:316)|(?:463)|(?:50[1-9])|(?:51[27])|(?:65[0123579])|(?:66[0-9])|(?:711)|(?:718)|(?:720)|(?:732)|(?:780)|(?:80[04])|(?:810)|(?:82[018])|(?:90[01])|(?:93[019]))((?:(?: *(?:\)|\.|_| |-) *)?))((?:[0-9][0-9][0-9][0-9]?[0-9]?[0-9]?[0-9]?[0-9]?[0-9]?[0-9]?))$/ },
{I:"f9294acb-f1f4-44d5-b0e5-6d672fcc7f3d", C:null, A:null, G:{C:2, A:5, P:7, E:-1, D:-1}, R:/^((?:(?:\+|011|810|00)?))((?:43))((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0?(?: *(?:\)|\.|_| |-) *)?))((?:2[1256789][0-9][0-9])|(?:3[134568][0-9][0-9])|(?:4[2378][0-9][0-9])|(?:5[23456][0-9][0-9])|(?:6[1245][0-9][0-9])|(?:7[2345679][0-9][0-9]))((?:(?: *(?:\)|\.|_| |-) *)?))((?:[0-9][0-9][0-9][0-9]?[0-9]?[0-9]?[0-9]?[0-9]?[0-9]?[0-9]?))$/ },
{I:"ed94ef63-e94f-44ee-a693-39f6be20da4e", C:"43", A:null, G:{C:-1, A:3, P:5, E:-1, D:-1}, R:/^((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0?(?: *(?:\)|\.|_| |-) *)?))((?:1)|(?:5[79])|(?:6[7-9]))((?:(?: *(?:\)|\.|_| |-) *)?))((?:[0-9][0-9][0-9][0-9]?[0-9]?[0-9]?[0-9]?[0-9]?[0-9]?[0-9]?))$/ },
{I:"621b081e-b182-4d6c-97fe-4f1c40f58320", C:"43", A:null, G:{C:-1, A:3, P:5, E:-1, D:-1}, R:/^((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0?(?: *(?:\)|\.|_| |-) *)?))((?:316)|(?:463)|(?:50[1-9])|(?:51[27])|(?:65[0123579])|(?:66[0-9])|(?:711)|(?:718)|(?:720)|(?:732)|(?:780)|(?:80[04])|(?:810)|(?:82[018])|(?:90[01])|(?:93[019]))((?:(?: *(?:\)|\.|_| |-) *)?))((?:[0-9][0-9][0-9][0-9]?[0-9]?[0-9]?[0-9]?[0-9]?[0-9]?[0-9]?))$/ },
{I:"642e1082-c638-4dfe-b853-df6c9231e005", C:"43", A:null, G:{C:-1, A:3, P:5, E:-1, D:-1}, R:/^((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0?(?: *(?:\)|\.|_| |-) *)?))((?:2[1256789][0-9][0-9])|(?:3[134568][0-9][0-9])|(?:4[2378][0-9][0-9])|(?:5[23456][0-9][0-9])|(?:6[1245][0-9][0-9])|(?:7[2345679][0-9][0-9]))((?:(?: *(?:\)|\.|_| |-) *)?))((?:[0-9][0-9][0-9][0-9]?[0-9]?[0-9]?[0-9]?[0-9]?[0-9]?[0-9]?))$/ },
{I:"807df1b8-a268-4478-9e2a-7cf32597324b", C:"32", A:null, G:{C:-1, A:3, P:6, E:-1, D:-1}, R:/^((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0(?: *(?:\)|\.|_| |-) *)?))((?:[2349]))((?:(?: *(?:\)|\.|_| |-) *)?))((?:[\.\- ]?))((?:[1-9][0-9][0-9][0-9][0-9][0-9][0-9])|(?:[1-9][0-9][0-9][\.\- ]?[0-9][0-9][0-9][0-9])|(?:[1-9][0-9][0-9][\.\- ]?[0-9][0-9][\.\- ]?[0-9][0-9]))$/ },
{I:"f732f4d4-2a42-4b1e-a076-9f0ead8d0411", C:"32", A:null, G:{C:-1, A:3, P:6, E:-1, D:-1}, R:/^((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0(?: *(?:\)|\.|_| |-) *)?))((?:1[01234569])|(?:4[0-9][0-9])|(?:5[0-9])|(?:6[01345789])|(?:7[01])|(?:8[012345679])|(?:800)|(?:90[0-9]))((?:(?: *(?:\)|\.|_| |-) *)?))((?:[\.\- ]?))((?:[1-9][0-9][0-9][0-9][0-9][0-9])|(?:[1-9][0-9][0-9][\.\- ]?[0-9][0-9][0-9])|(?:[1-9][0-9][\.\- ]?[0-9][0-9][\.\- ]?[0-9][0-9]))$/ },
{I:"b8a310d4-8d10-44de-b97d-7c04d4f5e52c", C:null, A:null, G:{C:2, A:5, P:8, E:-1, D:-1}, R:/^((?:(?:\+|011|810|00)?))((?:32))((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0?(?: *(?:\)|\.|_| |-) *)?))((?:[2349]))((?:(?: *(?:\)|\.|_| |-) *)?))((?:[\.\- ]?))((?:[1-9][0-9][0-9][0-9][0-9][0-9][0-9])|(?:[1-9][0-9][0-9][\.\- ]?[0-9][0-9][0-9][0-9])|(?:[1-9][0-9][0-9][\.\- ]?[0-9][0-9][\.\- ]?[0-9][0-9]))$/ },
{I:"b22dc2d2-aca7-4e24-baaf-e17d61424753", C:null, A:null, G:{C:2, A:5, P:8, E:-1, D:-1}, R:/^((?:(?:\+|011|810|00)?))((?:32))((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0?(?: *(?:\)|\.|_| |-) *)?))((?:1[01234569])|(?:4[0-9][0-9])|(?:5[0-9])|(?:6[01345789])|(?:7[01])|(?:8[012345679])|(?:800)|(?:90[0-9]))((?:(?: *(?:\)|\.|_| |-) *)?))((?:[\.\- ]?))((?:[1-9][0-9][0-9][0-9][0-9][0-9])|(?:[1-9][0-9][0-9][\.\- ]?[0-9][0-9][0-9])|(?:[1-9][0-9][\.\- ]?[0-9][0-9][\.\- ]?[0-9][0-9]))$/ },
{I:"dbb46c91-b818-488a-aea2-ef70b56f9929", C:"86", A:null, G:{C:-1, A:3, P:5, E:-1, D:-1}, R:/^((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0(?: *(?:\)|\.|_| |-) *)?))((?:1[3458][0-9]))((?:(?: *(?:\)|\.|_| |-) *)?[\.\- ]?))((?:[1-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]))$/ },
{I:"7d7218f3-1b01-468d-95b0-0f31e8f8277e", C:"86", A:null, G:{C:-1, A:3, P:5, E:-1, D:-1}, R:/^((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0(?: *(?:\)|\.|_| |-) *)?))((?:10)|(?:2[0-9])|(?:[3456789][0-9][0-9]))((?:(?: *(?:\)|\.|_| |-) *)?[\.\- ]?))((?:[1-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]?))$/ },
{I:"72d9321c-60cd-45a8-8979-ed917ec05d9c", C:null, A:null, G:{C:2, A:4, P:6, E:-1, D:-1}, R:/^((?:(?:\+|011|810|00)?))((?:86))((?:(?: *(?:\(|\.|_| |-) *)?))((?:1[3458][0-9]))((?:(?: *(?:\)|\.|_| |-) *)?[\.\- ]?))((?:[1-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]))$/ },
{I:"a65be6e1-4fb3-46ca-bd61-54a55beebe3f", C:null, A:null, G:{C:2, A:5, P:7, E:-1, D:-1}, R:/^((?:(?:\+|011|810|00)?))((?:86))((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0?(?: *(?:\)|\.|_| |-) *)?))((?:10)|(?:2[0-9])|(?:[3456789][0-9][0-9]))((?:(?: *(?:\)|\.|_| |-) *)?[\.\- ]?))((?:[1-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]?))$/ },
{I:"03b7b017-6ccb-43b0-8b35-76ac2797b52d", C:"57", A:null, G:{C:-1, A:3, P:5, E:-1, D:-1}, R:/^((?:01))((?:[\.\- ]?))((?:800)|(?:900)|(?:901)|(?:947)|(?:948))((?:[\.\- ]?))((?:[1-9][0-9][0-9][0-9][0-9][0-9][0-9])|(?:[1-9][0-9][0-9][\.\- ]?[0-9][0-9][0-9][0-9])|(?:[1-9][0-9][0-9][\.\- ]?[0-9][0-9][\.\- ]?[0-9][0-9]))$/ },
{I:"ebe8292e-4b3c-4d19-9129-a9ed6e0ef5ea", C:"57", A:null, G:{C:-1, A:2, P:4, E:-1, D:-1}, R:/^((?:(?: *(?:\(|\.|_| |-) *)?))((?:[1245678]))((?:(?: *(?:\)|\.|_| |-) *)?))((?:[1-9][0-9][0-9][0-9][0-9][0-9][0-9])|(?:[1-9][0-9][0-9][\.\- ]?[0-9][0-9][0-9][0-9])|(?:[1-9][0-9][0-9][\.\- ]?[0-9][0-9][\.\- ]?[0-9][0-9]))$/ },
{I:"9d25e6e2-54a3-49b9-95cf-f37a280cea3e", C:"57", A:null, G:{C:-1, A:2, P:4, E:-1, D:-1}, R:/^((?:(?: *(?:\(|\.|_| |-) *)?))((?:3[0-9][0-9]))((?:(?: *(?:\)|\.|_| |-) *)?))((?:[1-9][0-9][0-9][0-9][0-9][0-9][0-9])|(?:[1-9][0-9][0-9][\.\- ]?[0-9][0-9][0-9][0-9])|(?:[1-9][0-9][0-9][\.\- ]?[0-9][0-9][\.\- ]?[0-9][0-9]))$/ },
{I:"648edac4-2144-4bc7-87b8-3a8c5a34e43e", C:null, A:null, G:{C:2, A:4, P:6, E:-1, D:-1}, R:/^((?:(?:\+|011|810|00)?))((?:57))((?:(?: *(?:\(|\.|_| |-) *)?))((?:[1245678]))((?:(?: *(?:\)|\.|_| |-) *)?))((?:[1-9][0-9][0-9][0-9][0-9][0-9][0-9])|(?:[1-9][0-9][0-9][\.\- ]?[0-9][0-9][0-9][0-9])|(?:[1-9][0-9][0-9][\.\- ]?[0-9][0-9][\.\- ]?[0-9][0-9]))$/ },
{I:"af0dfc2b-7781-492b-ab2c-b3fd2e7117d8", C:null, A:null, G:{C:2, A:4, P:6, E:-1, D:-1}, R:/^((?:(?:\+|011|810|00)?))((?:57))((?:(?: *(?:\(|\.|_| |-) *)?))((?:3[0-9][0-9]))((?:(?: *(?:\)|\.|_| |-) *)?))((?:[1-9][0-9][0-9][0-9][0-9][0-9][0-9])|(?:[1-9][0-9][0-9][\.\- ]?[0-9][0-9][0-9][0-9])|(?:[1-9][0-9][0-9][\.\- ]?[0-9][0-9][\.\- ]?[0-9][0-9]))$/ },
{I:"917e6fe7-bc14-4a8f-9b9d-0925b45c43fc", C:"33", A:null, G:{C:-1, A:3, P:5, E:-1, D:-1}, R:/^((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0(?: *(?:\)|\.|_| |-) *)?))((?:[1-9]))((?:(?: *(?:\)|\.|_| |-) *)?))((?:[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9])|(?:[0-9][0-9][0-9][0-9][\.\- ]?[0-9][0-9][0-9][0-9])|(?:[0-9][0-9][\.\- ]?[0-9][0-9][\.\- ]?[0-9][0-9][\.\- ]?[0-9][0-9]))$/ },
{I:"c7c8a376-dc30-4159-b6db-7581416376f0", C:null, A:null, G:{C:2, A:5, P:7, E:-1, D:-1}, R:/^((?:(?:\+|011|810|00)?))((?:33))((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0?(?: *(?:\)|\.|_| |-) *)?))((?:[1-9]))((?:(?: *(?:\)|\.|_| |-) *)?))((?:[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9])|(?:[0-9][0-9][0-9][0-9][\.\- ]?[0-9][0-9][0-9][0-9])|(?:[0-9][0-9][\.\- ]?[0-9][0-9][\.\- ]?[0-9][0-9][\.\- ]?[0-9][0-9]))$/ },
{I:"480bad5c-61f7-45b7-8e79-f54e5616a761", C:"49", A:null, G:{C:-1, A:3, P:5, E:-1, D:-1}, R:/^((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0?(?: *(?:\)|\.|_| |-) *)?))((?:800))((?:(?: *(?:\)|\.|_| |-) *)?[\.\- ]?))((?:[1-9][0-9][0-9][0-9][0-9][0-9][0-9]))$/ },
{I:"642893a3-480e-43dc-9b57-bc2cb5832a43", C:"49", A:null, G:{C:-1, A:3, P:5, E:-1, D:-1}, R:/^((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0?(?: *(?:\)|\.|_| |-) *)?))((?:1[567][0-9]))((?:(?: *(?:\)|\.|_| |-) *)?[\.\- ]?))((?:[1-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]?))$/ },
{I:"1e33bbad-3758-46f4-85ed-e6c571182bb2", C:"49", A:null, G:{C:-1, A:3, P:5, E:-1, D:-1}, R:/^((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0?(?: *(?:\)|\.|_| |-) *)?))((?:3[0-9][0-9][0-9][0-9]))((?:(?: *(?:\)|\.|_| |-) *)?[\.\- ]?))((?:[1-9][0-9][0-9][0-9][0-9][0-9]))$/ },
{I:"277b6c6d-4c77-40ac-a116-5a3194bf2986", C:"49", A:null, G:{C:-1, A:3, P:-1, E:-1, D:-1}, R:/^((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0(?: *(?:\)|\.|_| |-) *)??))((?:[1-9][0-9]))((?:(?: *(?:\)|\.|_| |-) *)?[\.\- ]?))((?:[1-9][0-9][0-9][0-9][0-9][0-9]?[0-9]?[0-9]?))$/ },
{I:"9f5c170a-77cb-4f2c-b21a-6dcd089d761d", C:"49", A:null, G:{C:-1, A:3, P:5, E:-1, D:-1}, R:/^((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0?(?: *(?:\)|\.|_| |-) *)?))((?:[1-9][0-9][0-9]))((?:(?: *(?:\)|\.|_| |-) *)?[\.\- ]?))((?:[1-9][0-9][0-9][0-9][0-9]?[0-9]?[0-9]?[0-9]?))$/ },
{I:"e63ea98b-2cbc-4536-b6d8-65e95570a48e", C:"49", A:null, G:{C:-1, A:3, P:5, E:-1, D:-1}, R:/^((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0?(?: *(?:\)|\.|_| |-) *)?))((?:[1-9][0-9][0-9][0-9]))((?:(?: *(?:\)|\.|_| |-) *)?[\.\- ]?))((?:[1-9][0-9][0-9][0-9]?[0-9]?[0-9]?[0-9]?))$/ },
{I:"9688eb91-f66f-4436-bd39-d7c0738f050a", C:null, A:null, G:{C:2, A:5, P:7, E:-1, D:-1}, R:/^((?:(?:\+|011|810|00)?))((?:49))((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0(?: *(?:\)|\.|_| |-) *)??))((?:1[567][0-9]))((?:(?: *(?:\)|\.|_| |-) *)?))((?:[1-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]?))$/ },
{I:"b5f385b7-784d-496e-b519-12b4884e1078", C:null, A:null, G:{C:2, A:5, P:7, E:-1, D:-1}, R:/^((?:(?:\+|011|810|00)?))((?:49))((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0?(?: *(?:\)|\.|_| |-) *)?))((?:3[0-9][0-9][0-9][0-9]))((?:(?: *(?:\)|\.|_| |-) *)?))((?:[1-9][0-9][0-9][0-9][0-9][0-9]))$/ },
{I:"144e0087-b873-41da-99be-453f8d2e5073", C:null, A:null, G:{C:2, A:5, P:7, E:-1, D:-1}, R:/^((?:(?:\+|011|810|00)?))((?:49))((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0?(?: *(?:\)|\.|_| |-) *)?))((?:[1-9][0-9]))((?:(?: *(?:\)|\.|_| |-) *)?))((?:[1-9][0-9][0-9][0-9][0-9][0-9]?[0-9]?[0-9]?))$/ },
{I:"79a2ea2a-79c7-44f4-aafd-0423d09b3720", C:null, A:null, G:{C:2, A:5, P:7, E:-1, D:-1}, R:/^((?:(?:\+|011|810|00)?))((?:49))((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0?(?: *(?:\)|\.|_| |-) *)?))((?:[1-9][0-9][0-9]))((?:(?: *(?:\)|\.|_| |-) *)?))((?:[1-9][0-9][0-9][0-9][0-9]?[0-9]?[0-9]?[0-9]?))$/ },
{I:"efd78736-5fa1-4ac9-8386-dbfe380bb276", C:null, A:null, G:{C:2, A:5, P:7, E:-1, D:-1}, R:/^((?:(?:\+|011|810|00)?))((?:49))((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0?(?: *(?:\)|\.|_| |-) *)?))((?:[1-9][0-9][0-9][0-9]))((?:(?: *(?:\)|\.|_| |-) *)?))((?:[1-9][0-9][0-9][0-9]?[0-9]?[0-9]?[0-9]?))$/ },
{I:"d246b205-4038-4c55-8282-90887d197216", C:"36", A:null, G:{C:-1, A:3, P:5, E:-1, D:-1}, R:/^((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0(?: *(?:\)|\.|_| |-) *)?))((?:1)|(?:[237]0))((?:(?: *(?:\)|\.|_| |-) *)?[\.\- ]?))((?:[1-9][0-9][0-9][0-9][0-9][0-9][0-9]))$/ },
{I:"e8e6e67d-9b07-4624-9a0f-94a4ef91f825", C:"36", A:null, G:{C:-1, A:3, P:5, E:-1, D:-1}, R:/^((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0(?: *(?:\)|\.|_| |-) *)?))((?:[23456789][0-9]))((?:(?: *(?:\)|\.|_| |-) *)?[\.\- ]?))((?:[1-9][0-9][0-9][0-9][0-9][0-9]))$/ },
{I:"83723b29-2b2b-43ad-bb69-52231571da69", C:null, A:null, G:{C:2, A:5, P:7, E:-1, D:-1}, R:/^((?:(?:\+|011|810|00)?))((?:36))((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0?(?: *(?:\)|\.|_| |-) *)?))((?:1)|(?:[237]0))((?:(?: *(?:\)|\.|_| |-) *)?[\.\- ]?))((?:[1-9][0-9][0-9][0-9][0-9][0-9][0-9]))$/ },
{I:"f87b6a1f-27d6-4e64-951b-b0acd5482d9a", C:null, A:null, G:{C:2, A:5, P:7, E:-1, D:-1}, R:/^((?:(?:\+|011|810|00)?))((?:36))((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0?(?: *(?:\)|\.|_| |-) *)?))((?:[23456789][0-9]))((?:(?: *(?:\)|\.|_| |-) *)?[\.\- ]?))((?:[1-9][0-9][0-9][0-9][0-9][0-9]))$/ },
{I:"603af8ee-f399-404d-86b2-8e11e9c94b8d", C:"353", A:null, G:{C:-1, A:3, P:5, E:-1, D:-1}, R:/^((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0?(?: *(?:\)|\.|_| |-) *)?))((?:1))((?:(?: *(?:\)|\.|_| |-) *)?))((?:[0-9][0-9][0-9][0-9][0-9][0-9]?[0-9]?))$/ },
{I:"8130fb8d-5bfd-405a-9031-a1263f638e85", C:"353", A:null, G:{C:-1, A:3, P:5, E:-1, D:-1}, R:/^((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0?(?: *(?:\)|\.|_| |-) *)?))((?:[245679][1-9])|(?:90))((?:(?: *(?:\)|\.|_| |-) *)?))((?:[0-9][0-9][0-9][0-9][0-9][0-9]?[0-9]?))$/ },
{I:"2e222f0f-6a55-4446-ac75-76fb784ed241", C:"353", A:null, G:{C:-1, A:3, P:5, E:-1, D:-1}, R:/^((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0?(?: *(?:\)|\.|_| |-) *)?))((?:[45]0[0-9]))((?:(?: *(?:\)|\.|_| |-) *)?))((?:[0-9][0-9][0-9][0-9][0-9][0-9]?[0-9]?))$/ },
{I:"0dd88408-34bf-492b-9142-15f7867ee2e2", C:"353", A:null, G:{C:-1, A:3, P:5, E:-1, D:-1}, R:/^((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0?(?: *(?:\)|\.|_| |-) *)?))((?:800)|(?:818)|(?:700)|(?:707))((?:(?: *(?:\)|\.|_| |-) *)?))((?:[0-9][0-9][0-9][0-9][0-9][0-9]?[0-9]?))$/ },
{I:"db180bd1-facc-4d6b-b671-3c89ede964e0", C:"353", A:null, G:{C:-1, A:3, P:5, E:-1, D:-1}, R:/^((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0?(?: *(?:\)|\.|_| |-) *)?))((?:8[3-9])|(?:82[1-9]))((?:(?: *(?:\)|\.|_| |-) *)?))((?:[0-9][0-9][0-9][0-9][0-9][0-9]?[0-9]?))$/ },
{I:"60f0f3de-c347-42ab-86e5-cca9a91f7a96", C:null, A:null, G:{C:2, A:5, P:7, E:-1, D:-1}, R:/^((?:(?:\+|011|810|00)?))((?:353))((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0?(?: *(?:\)|\.|_| |-) *)?))((?:1))((?:(?: *(?:\)|\.|_| |-) *)?))((?:[0-9][0-9][0-9][0-9][0-9][0-9]?[0-9]?))$/ },
{I:"5bd7b8ed-41c9-4e05-85bb-b2aba41eaefa", C:null, A:null, G:{C:2, A:5, P:7, E:-1, D:-1}, R:/^((?:(?:\+|011|810|00)?))((?:353))((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0?(?: *(?:\)|\.|_| |-) *)?))((?:[245679][1-9])|(?:90))((?:(?: *(?:\)|\.|_| |-) *)?))((?:[0-9][0-9][0-9][0-9][0-9][0-9][0-9]))$/ },
{I:"29ab7ffc-c4ff-4681-a067-633218329bf4", C:null, A:null, G:{C:2, A:5, P:7, E:-1, D:-1}, R:/^((?:(?:\+|011|810|00)?))((?:353))((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0?(?: *(?:\)|\.|_| |-) *)?))((?:[45]0[0-9]))((?:(?: *(?:\)|\.|_| |-) *)?))((?:[0-9][0-9][0-9][0-9][0-9][0-9]?[0-9]?))$/ },
{I:"5cf9c8c3-9028-4fff-a7ad-6d1ea187370d", C:null, A:null, G:{C:2, A:5, P:7, E:-1, D:-1}, R:/^((?:(?:\+|011|810|00)?))((?:353))((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0?(?: *(?:\)|\.|_| |-) *)?))((?:800)|(?:818)|(?:700)|(?:707))((?:(?: *(?:\)|\.|_| |-) *)?))((?:[0-9][0-9][0-9][0-9][0-9][0-9]?[0-9]?))$/ },
{I:"b1a1e4e9-a11d-4269-a7ed-c51916c85962", C:null, A:null, G:{C:2, A:5, P:7, E:-1, D:-1}, R:/^((?:(?:\+|011|810|00)?))((?:353))((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0?(?: *(?:\)|\.|_| |-) *)?))((?:8[3-9])|(?:82[1-9]))((?:(?: *(?:\)|\.|_| |-) *)?))((?:[0-9][0-9][0-9][0-9][0-9][0-9]?[0-9]?))$/ },
{I:"aae216c6-8435-4e9d-adfc-99fdc936f9a2", C:"972", A:null, G:{C:-1, A:3, P:5, E:-1, D:-1}, R:/^((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0(?: *(?:\)|\.|_| |-) *)?))((?:[57][0-9])|(?:[89]0)|(?:[23489]))((?:(?: *(?:\)|\.|_| |-) *)?))((?:[0-9][0-9][0-9][0-9][0-9][0-9][0-9]))$/ },
{I:"8c3c4633-1e6c-403c-b8b1-7368482aec1f", C:null, A:null, G:{C:2, A:5, P:7, E:-1, D:-1}, R:/^((?:(?:\+|011|810|00)?))((?:972))((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0?(?: *(?:\)|\.|_| |-) *)?))((?:[57][0-9])|(?:[89]0)|(?:[23489]))((?:(?: *(?:\)|\.|_| |-) *)?))((?:[0-9][0-9][0-9][0-9][0-9][0-9][0-9]))$/ },
{I:"b5356329-40d2-44ab-88f7-67c92eb81a57", C:"39", A:null, G:{C:-1, A:2, P:4, E:-1, D:-1}, R:/^((?:(?: *(?:\(|\.|_| |-) *)?))((?:3[0-9][0-9]))((?:(?: *(?:\)|\.|_| |-) *)?))((?:[0-9][0-9][0-9][0-9][0-9][0-9][0-9]))$/ },
{I:"5d475e79-d28c-44b6-b63c-c861a7357a30", C:"39", A:null, G:{C:-1, A:3, P:5, E:-1, D:-1}, R:/^((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0?(?: *(?:\)|\.|_| |-) *)?))((?:80[0-9]))((?:(?: *(?:\)|\.|_| |-) *)?))((?:[0-9][0-9][0-9][0-9][0-9][0-9][0-9]))$/ },
{I:"a0634152-067e-4c84-8cec-0323aaaa7614", C:"39", A:null, G:{C:-1, A:2, P:4, E:-1, D:-1}, R:/^((?:(?: *(?:\(|\.|_| |-) *)?))((?:0[26]))((?:(?: *(?:\)|\.|_| |-) *)?))((?:[0-9][0-9][0-9][0-9][0-9][0-9]?[0-9]?[0-9]?[0-9]?[0-9]?))$/ },
{I:"a858d0c7-2d3a-4353-b14f-93b60428fd07", C:"39", A:null, G:{C:-1, A:2, P:4, E:-1, D:-1}, R:/^((?:(?: *(?:\(|\.|_| |-) *)?))((?:0[1345789][0159]))((?:(?: *(?:\)|\.|_| |-) *)?))((?:[0-9][0-9][0-9][0-9][0-9]?[0-9]?[0-9]?[0-9]?[0-9]?))$/ },
{I:"923df194-91c7-4b0c-b57b-a58e139ec89e", C:"39", A:null, G:{C:-1, A:2, P:4, E:-1, D:-1}, R:/^((?:(?: *(?:\(|\.|_| |-) *)?))((?:0[1345789][234678][1-9]))((?:(?: *(?:\)|\.|_| |-) *)?))((?:[0-9][0-9][0-9][0-9]?[0-9]?[0-9]?[0-9]?[0-9]?))$/ },
{I:"d2a8e438-bdf5-4646-bb94-87a202ee2a22", C:null, A:null, G:{C:2, A:4, P:6, E:-1, D:-1}, R:/^((?:(?:\+|011|810|00)?))((?:39))((?:(?: *(?:\(|\.|_| |-) *)?))((?:3[0-9][0-9]))((?:(?: *(?:\)|\.|_| |-) *)?))((?:[0-9][0-9][0-9][0-9][0-9][0-9][0-9]))$/ },
{I:"c7abb3c5-370b-4092-8f10-77161176c53f", C:null, A:null, G:{C:2, A:4, P:6, E:-1, D:-1}, R:/^((?:(?:\+|011|810|00)?))((?:39))((?:(?: *(?:\(|\.|_| |-) *)?))((?:0[26]))((?:(?: *(?:\)|\.|_| |-) *)?))((?:[0-9][0-9][0-9][0-9][0-9][0-9]?[0-9]?[0-9]?[0-9]?[0-9]?))$/ },
{I:"4064d863-6514-400f-b4d2-955698fc8cfe", C:null, A:null, G:{C:2, A:4, P:6, E:-1, D:-1}, R:/^((?:(?:\+|011|810|00)?))((?:39))((?:(?: *(?:\(|\.|_| |-) *)?))((?:0[1345789][0159]))((?:(?: *(?:\)|\.|_| |-) *)?))((?:[0-9][0-9][0-9][0-9][0-9]?[0-9]?[0-9]?[0-9]?[0-9]?))$/ },
{I:"73b0f361-0f42-4a6d-8c00-288b46fcfd86", C:null, A:null, G:{C:2, A:4, P:6, E:-1, D:-1}, R:/^((?:(?:\+|011|810|00)?))((?:39))((?:(?: *(?:\(|\.|_| |-) *)?))((?:0[1345789][234678][1-9]))((?:(?: *(?:\)|\.|_| |-) *)?))((?:[0-9][0-9][0-9][0-9]?[0-9]?[0-9]?[0-9]?[0-9]?))$/ },
{I:"649c31fd-be99-4dfb-988e-ecdec9e0ca70", C:"52", A:null, G:{C:-1, A:2, P:4, E:-1, D:-1}, R:/^((?:(?: *(?:\(|\.|_| |-) *)?))((?:33)|(?:55)|(?:81))((?:(?: *(?:\)|\.|_| |-) *)?[\.\- ]?))((?:[1-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]))$/ },
{I:"43b2947e-e080-490b-91f5-bf4680d3e6f0", C:"52", A:null, G:{C:-1, A:2, P:4, E:-1, D:-1}, R:/^((?:(?: *(?:\(|\.|_| |-) *)?))((?:[1234567][0-9][0-9])|(?:[89][1-9][0-9]))((?:(?: *(?:\)|\.|_| |-) *)?[\.\- ]?))((?:[1-9][0-9][0-9][0-9][0-9][0-9][0-9]))$/ },
{I:"98f2cd1f-66ec-4a53-97eb-b7c878e3d54c", C:null, A:null, G:{C:2, A:4, P:6, E:-1, D:-1}, R:/^((?:(?:\+|011|810|00)?))((?:52))((?:(?: *(?:\(|\.|_| |-) *)?))((?:33)|(?:55)|(?:81))((?:(?: *(?:\)|\.|_| |-) *)?[\.\- ]?))((?:[1-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]))$/ },
{I:"4e3625b1-a137-4bf6-9ee3-f59af5e0b1fe", C:null, A:null, G:{C:2, A:4, P:6, E:-1, D:-1}, R:/^((?:(?:\+|011|810|00)?))((?:52))((?:(?: *(?:\(|\.|_| |-) *)?))((?:[1234567][0-9][0-9])|(?:[89][1-9][0-9]))((?:(?: *(?:\)|\.|_| |-) *)?[\.\- ]?))((?:[1-9][0-9][0-9][0-9][0-9][0-9][0-9]))$/ },
{I:"9a4b7d66-af4b-4ed8-8a6b-e8042269e278", C:"31", A:null, G:{C:-1, A:3, P:5, E:-1, D:-1}, R:/^((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0?(?: *(?:\)|\.|_| |-) *)?))((?:6))((?:(?: *(?:\)|\.|_| |-) *)?))((?:[1-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]))$/ },
{I:"215bf9cb-12fa-4664-9204-f88bf175572e", C:"31", A:null, G:{C:-1, A:3, P:5, E:-1, D:-1}, R:/^((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0(?: *(?:\)|\.|_| |-) *)?))((?:800))((?:(?: *(?:\)|\.|_| |-) *)?))((?:[1-9][0-9][0-9][0-9][0-9][0-9][0-9]?))$/ },
{I:"3f7e8b9a-cccc-46ac-ac95-10db99a4511a", C:"31", A:null, G:{C:-1, A:3, P:5, E:-1, D:-1}, R:/^((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0(?: *(?:\)|\.|_| |-) *)?))((?:1[035])|(?:2[0346])|(?:3[03568])|(?:4[0356])|(?:5[0358])|(?:7[0-9]))((?:(?: *(?:\)|\.|_| |-) *)?))((?:[1-9][0-9][0-9][0-9][0-9][0-9][0-9]))$/ },
{I:"56bbf6a9-4766-4e8a-8641-bc3223082f70", C:"31", A:null, G:{C:-1, A:3, P:5, E:-1, D:-1}, R:/^((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0(?: *(?:\)|\.|_| |-) *)?))((?:1[1678][0-9])|(?:2[259][0-9])|(?:3[124][0-9])|(?:4[1789][0-9])|(?:5[124679][0-9]))((?:(?: *(?:\)|\.|_| |-) *)?))((?:[1-9][0-9][0-9][0-9][0-9][0-9]))$/ },
{I:"bfca48c6-cba7-4bb8-b0e8-d16642dba0bf", C:null, A:null, G:{C:2, A:5, P:7, E:-1, D:-1}, R:/^((?:(?:\+|011|810|00)?))((?:31))((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0?(?: *(?:\)|\.|_| |-) *)?))((?:6))((?:(?: *(?:\)|\.|_| |-) *)?))((?:[1-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]))$/ },
{I:"f47496e9-954b-47ff-a22e-28507f7b3ae7", C:null, A:null, G:{C:2, A:5, P:7, E:-1, D:-1}, R:/^((?:(?:\+|011|810|00)?))((?:31))((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0?(?: *(?:\)|\.|_| |-) *)?))((?:1[035])|(?:2[0346])|(?:3[03568])|(?:4[0356])|(?:5[0358])|(?:7[0-9]))((?:(?: *(?:\)|\.|_| |-) *)?))((?:[1-9][0-9][0-9][0-9][0-9][0-9][0-9]))$/ },
{I:"49a4e3e1-290d-4217-97b1-a4672bd8a70b", C:null, A:null, G:{C:2, A:5, P:7, E:-1, D:-1}, R:/^((?:(?:\+|011|810|00)?))((?:31))((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0?(?: *(?:\)|\.|_| |-) *)?))((?:1[1678][0-9])|(?:2[259][0-9])|(?:3[124][0-9])|(?:4[1789][0-9])|(?:5[124679][0-9]))((?:(?: *(?:\)|\.|_| |-) *)?))((?:[1-9][0-9][0-9][0-9][0-9][0-9]))$/ },
{I:"9ded538b-1a7d-4bf7-8d4e-c27ca73d702d", C:"1", A:null, G:{C:-1, A:2, P:4, E:-1, D:-1}, R:/^((?:(?: *(?:\(|\.|_| |-) *)?))((?:800)|(?:822)|(?:833)|(?:844)|(?:855)|(?:866)|(?:877)|(?:880)|(?:881)|(?:882)|(?:888))((?:(?: *(?:\)|\.|_| |-) *)?[\.\- ]?))((?:[A-Z0-9][\.\- ]?[A-Z0-9][\.\- ]?[A-Z0-9][\.\- ]?[A-Z0-9][\.\- ]?[A-Z0-9][\.\- ]?[A-Z0-9][\.\- ]?[A-Z0-9][\.\- ]?[A-Z0-9]?[\.\- ]?[A-Z0-9]?[\.\- ]?[A-Z0-9]?[\.\- ]?[A-Z0-9]?))$/ },
{I:"702658b1-9f4d-4830-9664-95107b98c430", C:"1", A:null, G:{C:-1, A:2, P:4, E:-1, D:-1}, R:/^((?:(?: *(?:\(|\.|_| |-) *)?))((?:[2-9][0-9][0-9]))((?:(?: *(?:\)|\.|_| |-) *)?[\.\- ]?))((?:[2-9][0-9][0-9][0-9][0-9][0-9][0-9])|(?:[2-9][0-9][0-9][\.\- ]?[0-9][0-9][0-9][0-9])|(?:[2-9][0-9][0-9][\.\- ]?[0-9][0-9][\.\- ]?[0-9][0-9]))$/ },
{I:"edfedf1a-1f83-4289-8fd9-c5b08212a615", C:null, A:null, G:{C:2, A:4, P:6, E:-1, D:-1}, R:/^((?:(?:\+|011|810|00)?))((?:1))((?:(?: *(?:\(|\.|_| |-) *)?))((?:800)|(?:822)|(?:833)|(?:844)|(?:855)|(?:866)|(?:877)|(?:880)|(?:881)|(?:882)|(?:888))((?:(?: *(?:\)|\.|_| |-) *)?[\.\- ]?))((?:[A-Z0-9][\.\- ]?[A-Z0-9][\.\- ]?[A-Z0-9][\.\- ]?[A-Z0-9][\.\- ]?[A-Z0-9][\.\- ]?[A-Z0-9][\.\- ]?[A-Z0-9][\.\- ]?[A-Z0-9]?[\.\- ]?[A-Z0-9]?[\.\- ]?[A-Z0-9]?[\.\- ]?[A-Z0-9]?))$/ },
{I:"69315d0a-91d8-4209-937a-dc6adbce88e2", C:null, A:null, G:{C:2, A:4, P:6, E:-1, D:-1}, R:/^((?:(?:\+|011|810|00)?))((?:1))((?:(?: *(?:\(|\.|_| |-) *)?))((?:[2-9][0-9][0-9]))((?:(?: *(?:\)|\.|_| |-) *)?))((?:[2-9][0-9][0-9][0-9][0-9][0-9][0-9])|(?:[2-9][0-9][0-9][\.\- ]?[0-9][0-9][0-9][0-9])|(?:[2-9][0-9][0-9][\.\- ]?[0-9][0-9][\.\- ]?[0-9][0-9]))$/ },
{I:"453be339-0d14-4f87-a508-b30c99d87d0b", C:"351", A:null, G:{C:-1, A:2, P:4, E:-1, D:-1}, R:/^((?:(?: *(?:\(|\.|_| |-) *)?))((?:9[0-9]))((?:(?: *(?:\)|\.|_| |-) *)?[\.\- ]?))((?:[1-9][0-9][0-9][0-9][0-9][0-9][0-9]))$/ },
{I:"d3fe1971-8c5d-4bf9-98ea-e4edbd1e6453", C:"351", A:null, G:{C:-1, A:2, P:4, E:-1, D:-1}, R:/^((?:(?: *(?:\(|\.|_| |-) *)?))((?:800))((?:(?: *(?:\)|\.|_| |-) *)?[\.\- ]?))((?:[1-9][0-9][0-9][0-9][0-9][0-9][0-9]))$/ },
{I:"03621802-8efc-452b-ab06-23852627b892", C:"351", A:null, G:{C:-1, A:2, P:4, E:-1, D:-1}, R:/^((?:(?: *(?:\(|\.|_| |-) *)?))((?:2[12]))((?:(?: *(?:\)|\.|_| |-) *)?[\.\- ]?))((?:[1-9][0-9][0-9][0-9][0-9][0-9][0-9]))$/ },
{I:"c1b595ad-9c1e-404e-bdbc-ff20d34b212d", C:"351", A:null, G:{C:-1, A:2, P:4, E:-1, D:-1}, R:/^((?:(?: *(?:\(|\.|_| |-) *)?))((?:2[3456789][0-9]))((?:(?: *(?:\)|\.|_| |-) *)?[\.\- ]?))((?:[1-9][0-9][0-9][0-9][0-9][0-9]))$/ },
{I:"637f0876-1a2d-4a26-b274-d5765edd74e5", C:null, A:null, G:{C:2, A:4, P:6, E:-1, D:-1}, R:/^((?:(?:\+|011|810|00)?))((?:351))((?:(?: *(?:\(|\.|_| |-) *)?))((?:9[0-9]))((?:(?: *(?:\)|\.|_| |-) *)?[\.\- ]?))((?:[1-9][0-9][0-9][0-9][0-9][0-9][0-9]))$/ },
{I:"68092710-0d16-4bbe-b47a-6cbe57e692e8", C:null, A:null, G:{C:2, A:4, P:6, E:-1, D:-1}, R:/^((?:(?:\+|011|810|00)?))((?:351))((?:(?: *(?:\(|\.|_| |-) *)?))((?:2[12]))((?:(?: *(?:\)|\.|_| |-) *)?[\.\- ]?))((?:[1-9][0-9][0-9][0-9][0-9][0-9][0-9]))$/ },
{I:"e6f4d90c-1fd5-4f1f-abe6-dd6d43596500", C:null, A:null, G:{C:2, A:4, P:6, E:-1, D:-1}, R:/^((?:(?:\+|011|810|00)?))((?:351))((?:(?: *(?:\(|\.|_| |-) *)?))((?:2[3456789][0-9]))((?:(?: *(?:\)|\.|_| |-) *)?[\.\- ]?))((?:[1-9][0-9][0-9][0-9][0-9][0-9]))$/ },
{I:"a9b6a925-63a2-4103-bfc8-b9ae2fa68248", C:"7", A:null, G:{C:-1, A:2, P:4, E:-1, D:-1}, R:/^((?:(?: *(?:\(|\.|_| |-) *)?))((?:[1-9][0-9][0-9]))((?:(?: *(?:\)|\.|_| |-) *)?[\.\- ]?))((?:[1-9][0-9][0-9][0-9][0-9][0-9][0-9])|(?:[1-9][0-9][0-9][\.\- ]?[0-9][0-9][0-9][0-9])|(?:[1-9][0-9][0-9][\.\- ]?[0-9][0-9][\.\- ]?[0-9][0-9]))$/ },
{I:"e0ffb55f-42dc-4b82-b109-a29a77c98030", C:"7", A:null, G:{C:-1, A:2, P:4, E:-1, D:-1}, R:/^((?:(?: *(?:\(|\.|_| |-) *)?))((?:[1-9][0-9][0-9][0-9]))((?:(?: *(?:\)|\.|_| |-) *)?[\.\- ]?))((?:[1-9][0-9][0-9][0-9][0-9][0-9])|(?:[1-9][0-9][0-9][\.\- ]?[0-9][0-9][0-9])|(?:[1-9][0-9][\.\- ]?[0-9][0-9][\.\- ]?[0-9][0-9]))$/ },
{I:"8e1d71b5-783f-4474-92a1-b6c38d03169a", C:"7", A:null, G:{C:-1, A:2, P:4, E:-1, D:-1}, R:/^((?:(?: *(?:\(|\.|_| |-) *)?))((?:[1-9][0-9][0-9][0-9][0-9]))((?:(?: *(?:\)|\.|_| |-) *)?[\.\- ]?))((?:[1-9][0-9][0-9][0-9][0-9])|(?:[1-9][0-9][\.\- ]?[0-9][0-9][0-9])|(?:[1-9][\.\- ]?[0-9][0-9][\.\- ]?[0-9][0-9]))$/ },
{I:"d79751fe-ddd9-4c99-93ce-2b84b50c843d", C:null, A:null, G:{C:2, A:4, P:6, E:-1, D:-1}, R:/^((?:(?:\+|011|810|00)?))((?:7))((?:(?: *(?:\(|\.|_| |-) *)?))((?:[1-9][0-9][0-9]))((?:(?: *(?:\)|\.|_| |-) *)?))((?:[1-9][0-9][0-9][0-9][0-9][0-9][0-9])|(?:[1-9][0-9][0-9][\.\- ]?[0-9][0-9][0-9][0-9])|(?:[1-9][0-9][0-9][\.\- ]?[0-9][0-9][\.\- ]?[0-9][0-9]))$/ },
{I:"a00c55ab-97e4-4ed8-9b77-a58f35a1ecff", C:null, A:null, G:{C:2, A:4, P:6, E:-1, D:-1}, R:/^((?:(?:\+|011|810|00)?))((?:7))((?:(?: *(?:\(|\.|_| |-) *)?))((?:[1-9][0-9][0-9][0-9]))((?:(?: *(?:\)|\.|_| |-) *)?))((?:[1-9][0-9][0-9][0-9][0-9][0-9])|(?:[1-9][0-9][0-9][\.\- ]?[0-9][0-9][0-9])|(?:[1-9][0-9][\.\- ]?[0-9][0-9][\.\- ]?[0-9][0-9]))$/ },
{I:"d413f59b-acf8-428c-b9cd-79788660d3f6", C:null, A:null, G:{C:2, A:4, P:6, E:-1, D:-1}, R:/^((?:(?:\+|011|810|00)?))((?:7))((?:(?: *(?:\(|\.|_| |-) *)?))((?:[1-9][0-9][0-9][0-9][0-9]))((?:(?: *(?:\)|\.|_| |-) *)?))((?:[1-9][0-9][0-9][0-9][0-9])|(?:[1-9][0-9][\.\- ]?[0-9][0-9][0-9])|(?:[1-9][\.\- ]?[0-9][0-9][\.\- ]?[0-9][0-9]))$/ },
{I:"4c2e9f67-204a-47eb-95c2-36256c512f76", C:"966", A:null, G:{C:-1, A:3, P:5, E:-1, D:-1}, R:/^((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0(?: *(?:\)|\.|_| |-) *)?))((?:[123467])|(?:5[0345689]))((?:(?: *(?:\)|\.|_| |-) *)?))((?:[0-9][0-9][0-9][0-9][0-9][0-9][0-9]))$/ },
{I:"461a935f-925e-4c53-81d0-93dcd19dfcf3", C:"966", A:null, G:{C:-1, A:3, P:5, E:-1, D:-1}, R:/^((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0(?: *(?:\)|\.|_| |-) *)?))((?:8))((?:(?: *(?:\)|\.|_| |-) *)?))((?:111[0-9][0-9][0-9][0-9][0-9][0-9]))$/ },
{I:"e0fae84e-fe77-4528-be37-7e581acfe2b8", C:null, A:null, G:{C:2, A:5, P:7, E:-1, D:-1}, R:/^((?:(?:\+|011|810|00)?))((?:966))((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0?(?: *(?:\)|\.|_| |-) *)?))((?:[123467])|(?:5[0345689]))((?:(?: *(?:\)|\.|_| |-) *)?))((?:[0-9][0-9][0-9][0-9][0-9][0-9][0-9]))$/ },
{I:"9a4e499f-dc04-474b-a8a2-c94114f83075", C:null, A:null, G:{C:2, A:5, P:7, E:-1, D:-1}, R:/^((?:(?:\+|011|810|00)?))((?:966))((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0?(?: *(?:\)|\.|_| |-) *)?))((?:8))((?:(?: *(?:\)|\.|_| |-) *)?))((?:111[0-9][0-9][0-9][0-9][0-9][0-9]))$/ },
{I:"b995edce-b91b-494d-a7c4-668df22ab38b", C:"34", A:null, G:{C:-1, A:2, P:4, E:-1, D:-1}, R:/^((?:(?: *(?:\(|\.|_| |-) *)?))((?:[67][0-9][0-9]))((?:(?: *(?:\)|\.|_| |-) *)?[\.\- ]?))((?:[0-9][0-9][0-9][0-9][0-9][0-9]))$/ },
{I:"56d348d4-d614-44c0-a785-f753257df355", C:"34", A:null, G:{C:-1, A:2, P:4, E:-1, D:-1}, R:/^((?:(?: *(?:\(|\.|_| |-) *)?))((?:800))((?:(?: *(?:\)|\.|_| |-) *)?[\.\- ]?))((?:[0-9][0-9][0-9][0-9][0-9][0-9]))$/ },
{I:"a3aab9f3-136c-482e-97b0-83376f09be00", C:"34", A:null, G:{C:-1, A:2, P:4, E:-1, D:-1}, R:/^((?:(?: *(?:\(|\.|_| |-) *)?))((?:8[245678][0-9])|(?:9[12345678][0-9]))((?:(?: *(?:\)|\.|_| |-) *)?[\.\- ]?))((?:[0-9][0-9][0-9][0-9][0-9][0-9]))$/ },
{I:"3ef9b706-c157-499e-b0b3-2cbe2f39f149", C:null, A:null, G:{C:2, A:4, P:6, E:-1, D:-1}, R:/^((?:(?:\+|011|810|00)?))((?:34))((?:(?: *(?:\(|\.|_| |-) *)?))((?:[67][0-9][0-9]))((?:(?: *(?:\)|\.|_| |-) *)?[\.\- ]?))((?:[0-9][0-9][0-9][0-9][0-9][0-9]))$/ },
{I:"5b8ab85c-3de6-434a-bfc9-14123464b1af", C:null, A:null, G:{C:2, A:4, P:6, E:-1, D:-1}, R:/^((?:(?:\+|011|810|00)?))((?:34))((?:(?: *(?:\(|\.|_| |-) *)?))((?:8[245678][0-9])|(?:9[12345678][0-9]))((?:(?: *(?:\)|\.|_| |-) *)?[\.\- ]?))((?:[0-9][0-9][0-9][0-9][0-9][0-9]))$/ },
{I:"9715f194-058d-4fd8-b845-7e95331d0b90", C:"46", A:null, G:{C:-1, A:3, P:5, E:-1, D:-1}, R:/^((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0(?: *(?:\)|\.|_| |-) *)?))((?:1[013689])|(?:2[0136])|(?:3[1356])|(?:4[0246])|(?:5[4])|(?:6[03])|(?:7[01236])|(?:8)|(?:90))((?:(?: *(?:\)|\.|_| |-) *)?[\.\- ]?))((?:[1-9][0-9][0-9][0-9][0-9][0-9][0-9]?[0-9]?))$/ },
{I:"8a069872-de1a-477e-addf-f42ff9ceacd5", C:"46", A:null, G:{C:-1, A:3, P:5, E:-1, D:-1}, R:/^((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0(?: *(?:\)|\.|_| |-) *)?))((?:[1-9][0-9][0-9]))((?:(?: *(?:\)|\.|_| |-) *)?[\.\- ]?))((?:[1-9][0-9][0-9][0-9][0-9][0-9][0-9]?[0-9]?))$/ },
{I:"2352a73c-29d7-42fe-9a54-14fe9425b9ec", C:null, A:null, G:{C:2, A:5, P:7, E:-1, D:-1}, R:/^((?:(?:\+|011|810|00)?))((?:46))((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0?(?: *(?:\)|\.|_| |-) *)?))((?:1[013689])|(?:2[0136])|(?:3[1356])|(?:4[0246])|(?:5[4])|(?:6[03])|(?:7[01236])|(?:8)|(?:90))((?:(?: *(?:\)|\.|_| |-) *)?[\.\- ]?))((?:[1-9][0-9][0-9][0-9][0-9][0-9][0-9]?[0-9]?))$/ },
{I:"68b0a15f-211f-499f-827a-f8adeab44aae", C:null, A:null, G:{C:2, A:5, P:7, E:-1, D:-1}, R:/^((?:(?:\+|011|810|00)?))((?:46))((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0?(?: *(?:\)|\.|_| |-) *)?))((?:[1-9][0-9][0-9]))((?:(?: *(?:\)|\.|_| |-) *)?[\.\- ]?))((?:[1-9][0-9][0-9][0-9][0-9][0-9][0-9]?[0-9]?))$/ },
{I:"9b6f854f-11da-4a81-ac3c-e0a617199ed4", C:"41", A:null, G:{C:-1, A:3, P:5, E:-1, D:-1}, R:/^((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0?(?: *(?:\)|\.|_| |-) *)?))((?:800)|(?:84[0248])|(?:86[089])|(?:878)|(?:90[016]))((?:(?: *(?:\)|\.|_| |-) *)?))((?:[0-9][0-9][0-9][0-9][0-9][0-9][0-9]?[0-9]?[0-9]?))$/ },
{I:"a2f7bb85-de18-48f5-a9ec-42f947110a44", C:"41", A:null, G:{C:-1, A:3, P:5, E:-1, D:-1}, R:/^((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0?(?: *(?:\)|\.|_| |-) *)?))((?:2[12467])|(?:3[1234])|(?:4[134])|(?:5[12568])|(?:6[12])|(?:7[146789])|(?:81)|(?:9[189]))((?:(?: *(?:\)|\.|_| |-) *)?[\.\- ]?))((?:[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]?[0-9]?[0-9]?)|(?:[0-9][0-9][0-9][\.\- ]?[0-9][0-9][0-9][0-9])|(?:[0-9][0-9][0-9][\.\- ]?[0-9][0-9][\.\- ]?[0-9][0-9]))$/ },
{I:"0208e8bc-beb0-41e8-8b73-b972dddaccb5", C:null, A:null, G:{C:2, A:5, P:7, E:-1, D:-1}, R:/^((?:(?:\+|011|810|00)?))((?:41))((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0?(?: *(?:\)|\.|_| |-) *)?))((?:2[12467])|(?:3[1234])|(?:4[134])|(?:5[12568])|(?:6[12])|(?:7[146789])|(?:81)|(?:9[189]))((?:(?: *(?:\)|\.|_| |-) *)?))((?:[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]?[0-9]?[0-9]?)|(?:[0-9][0-9][0-9][\.\- ]?[0-9][0-9][0-9][0-9])|(?:[0-9][0-9][0-9][\.\- ]?[0-9][0-9][\.\- ]?[0-9][0-9]))$/ },
{I:"f522b775-179e-438d-ad67-f455648e9d42", C:null, A:null, G:{C:2, A:5, P:7, E:-1, D:-1}, R:/^((?:(?:\+|011|810|00)?))((?:41))((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0?(?: *(?:\)|\.|_| |-) *)?))((?:800)|(?:84[0248])|(?:86[089])|(?:878)|(?:90[016]))((?:(?: *(?:\)|\.|_| |-) *)?))((?:[0-9][0-9][0-9][0-9][0-9][0-9][0-9]?[0-9]?[0-9]?))$/ },
{I:"c68ee551-9217-4d6c-843f-5eb5e5e847ad", C:"44", A:null, G:{C:-1, A:-1, P:2, E:-1, D:-1}, R:/^((?:(?: *(?:\(|\.|_| |-) *)?0?(?: *(?:\)|\.|_| |-) *)?0?))((?:7[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]?))$/ },
{I:"63ad3f67-e6cd-49a5-92dd-6f19324b8524", C:"44", A:null, G:{C:-1, A:3, P:5, E:-1, D:-1}, R:/^((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0(?: *(?:\)|\.|_| |-) *)?))((?:11[0-9]))((?:(?: *(?:\)|\.|_| |-) *)?[\.\- ]?))((?:[0-9][0-9][0-9][0-9][0-9][0-9][0-9]))$/ },
{I:"61a9e982-333d-4937-94e1-28f5de30d956", C:"44", A:null, G:{C:-1, A:3, P:5, E:-1, D:-1}, R:/^((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0(?: *(?:\)|\.|_| |-) *)?))((?:1[0-9]1))((?:(?: *(?:\)|\.|_| |-) *)?[\.\- ]?))((?:[0-9][0-9][0-9][0-9][0-9][0-9][0-9]))$/ },
{I:"86b82eef-3e2e-49f3-ab99-6b1363f1ae80", C:"44", A:null, G:{C:-1, A:3, P:5, E:-1, D:-1}, R:/^((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0(?: *(?:\)|\.|_| |-) *)?))((?:1[0-9][0-9][0-9]))((?:(?: *(?:\)|\.|_| |-) *)?[\.\- ]?))((?:[0-9][0-9][0-9][0-9][0-9][0-9][0-9]?))$/ },
{I:"cd781fff-8d32-4172-9d79-8f489e8c0fc2", C:"44", A:null, G:{C:-1, A:3, P:5, E:-1, D:-1}, R:/^((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0(?: *(?:\)|\.|_| |-) *)?))((?:[2357][0-9]))((?:(?: *(?:\)|\.|_| |-) *)?[\.\- ]?))((?:[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]?))$/ },
{I:"f5cb8e58-6505-436f-b374-74d73a262c04", C:"44", A:null, G:{C:-1, A:3, P:5, E:-1, D:-1}, R:/^((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0(?: *(?:\)|\.|_| |-) *)?))((?:[89][0-9][0-9]))((?:(?: *(?:\)|\.|_| |-) *)?[\.\- ]?))((?:[0-9][0-9][0-9][0-9][0-9][0-9][0-9]?))$/ },
{I:"e69dcf4a-fccb-45b3-a844-956370249c99", C:null, A:null, G:{C:2, A:-1, P:4, E:-1, D:-1}, R:/^((?:(?:\+|011|810|00)?))((?:44))((?:(?: *(?:\(|\.|_| |-) *)?0?(?: *(?:\)|\.|_| |-) *)?0?))((?:7[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]?))$/ },
{I:"d461c7ba-4358-43c5-a348-1c08b896cebf", C:null, A:null, G:{C:2, A:5, P:7, E:-1, D:-1}, R:/^((?:(?:\+|011|810|00)?))((?:44))((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0?(?: *(?:\)|\.|_| |-) *)?))((?:11[0-9]))((?:(?: *(?:\)|\.|_| |-) *)?[\.\- ]?))((?:[1-9][0-9][0-9][0-9][0-9][0-9][0-9]))$/ },
{I:"b855f67c-d721-4883-9680-026b59818ecc", C:null, A:null, G:{C:2, A:5, P:7, E:-1, D:-1}, R:/^((?:(?:\+|011|810|00)?))((?:44))((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0?(?: *(?:\)|\.|_| |-) *)?))((?:1[0-9]1))((?:(?: *(?:\)|\.|_| |-) *)?[\.\- ]?))((?:[1-9][0-9][0-9][0-9][0-9][0-9][0-9]))$/ },
{I:"0f01eeae-a98b-4f62-b714-3c091f43331d", C:null, A:null, G:{C:2, A:5, P:7, E:-1, D:-1}, R:/^((?:(?:\+|011|810|00)?))((?:44))((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0?(?: *(?:\)|\.|_| |-) *)?))((?:1[0-9][0-9][0-9]))((?:(?: *(?:\)|\.|_| |-) *)?[\.\- ]?))((?:[0-9][0-9][0-9][0-9][0-9][0-9][0-9]?))$/ },
{I:"dde2b7bc-3f9f-4eab-9e3f-ccb35cd603f2", C:null, A:null, G:{C:2, A:5, P:7, E:-1, D:-1}, R:/^((?:(?:\+|011|810|00)?))((?:44))((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0?(?: *(?:\)|\.|_| |-) *)?))((?:[2357][0-9]))((?:(?: *(?:\)|\.|_| |-) *)?[\.\- ]?))((?:[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]?))$/ },
{I:"858be6a8-466e-4b8b-81bb-27ca5ea8a1b5", C:null, A:null, G:{C:2, A:5, P:7, E:-1, D:-1}, R:/^((?:(?:\+|011|810|00)?))((?:44))((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0?(?: *(?:\)|\.|_| |-) *)?))((?:[89][0-9][0-9]))((?:(?: *(?:\)|\.|_| |-) *)?[\.\- ]?))((?:[1-9][0-9][0-9][0-9][0-9][0-9][0-9]?))$/ },
{I:"ca2e9595-d536-43f6-9b25-996dcfe4e378", C:"971", A:null, G:{C:-1, A:3, P:5, E:-1, D:-1}, R:/^((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0(?: *(?:\)|\.|_| |-) *)?))((?:[234679]))((?:(?: *(?:\)|\.|_| |-) *)?[\.\- ]?))((?:[1-9][0-9][0-9][0-9][0-9][0-9][0-9]?))$/ },
{I:"1cefb914-a9be-4386-baa6-1ae4cce4cb58", C:"971", A:null, G:{C:-1, A:3, P:5, E:-1, D:-1}, R:/^((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0(?: *(?:\)|\.|_| |-) *)?))((?:5[0-9]))((?:(?: *(?:\)|\.|_| |-) *)?[\.\- ]?))((?:[1-9][0-9][0-9][0-9][0-9][0-9][0-9]?))$/ },
{I:"0803c160-b4e2-44d2-8435-767a8c72d86e", C:"971", A:null, G:{C:-1, A:2, P:4, E:-1, D:-1}, R:/^((?:(?: *(?:\(|\.|_| |-) *)?))((?:[23456789]00))((?:(?: *(?:\)|\.|_| |-) *)?[\.\- ]?))((?:[0-9][0-9][0-9][0-9]))$/ },
{I:"87591719-a6b6-4a56-8435-f15affbffa5b", C:null, A:null, G:{C:2, A:5, P:7, E:-1, D:-1}, R:/^((?:(?:\+|011|810|00)?))((?:971))((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0?(?: *(?:\)|\.|_| |-) *)?))((?:[234679]))((?:(?: *(?:\)|\.|_| |-) *)?[\.\- ]?))((?:[1-9][0-9][0-9][0-9][0-9][0-9][0-9]))$/ },
{I:"7eca0ae5-2038-4f92-a3ce-c0aac6525d30", C:null, A:null, G:{C:2, A:5, P:7, E:-1, D:-1}, R:/^((?:(?:\+|011|810|00)?))((?:971))((?:(?: *(?:\(|\.|_| |-) *)?))((?:(?: *(?:\(|\.|_| |-) *)?0?(?: *(?:\)|\.|_| |-) *)?))((?:5[0-9]))((?:(?: *(?:\)|\.|_| |-) *)?[\.\- ]?))((?:[1-9][0-9][0-9][0-9][0-9][0-9][0-9]?))$/ },
{I:"6809669a-02cf-473f-8d2f-a94591a3af5a", C:null, A:null, G:{C:2, A:4, P:6, E:-1, D:-1}, R:/^((?:(?:\+|011|810|00)?))((?:971))((?:(?: *(?:\(|\.|_| |-) *)?))((?:[23456789]00))((?:(?: *(?:\)|\.|_| |-) *)?))((?:[0-9][0-9][0-9][0-9]))$/ },
{I:"13a477a6-a84f-481d-ab9b-5440c27596bb", C:null, A:null, G:{C:-1, A:-1, P:-1, E:-1, D:2}, R:/^((?:\#))((?:[0-9\*\#\,][0-9\*\#\,]?[0-9\*\#\,]?[0-9\*\#\,]?[0-9\*\#\,]?[0-9\*\#\,]?[0-9\*\#\,]?[0-9\*\#\,]?[0-9\*\#\,]?[0-9\*\#\,]?[0-9\*\#\,]?[0-9\*\#\,]?[0-9\*\#\,]?[0-9\*\#\,]?[0-9\*\#\,]?[0-9\*\#\,]?[0-9\*\#\,]?[0-9\*\#\,]?[0-9\*\#\,]?[0-9\*\#\,]?))$/ },
{I:"4f5c4f61-32fc-412e-aca2-4f5811c71824", C:null, A:null, G:{C:2, A:4, P:6, E:-1, D:-1}, R:/^((?:(?:\+|011|810|00)?))((?:2[07])|(?:2[0-9][0-9])|(?:3[0])|(?:35[023456789])|(?:4[023578])|(?:5[134568])|(?:5[09][0-9])|(?:6[0-6])|(?:6[78][0-9])|(?:69[012])|(?:8[124])|(?:85[02356])|(?:866)|(?:800)|(?:888)|(?:9[0123458])|(?:96[01234578])|(?:97[34567])|(?:99[45]))((?:(?: *(?:\(|\.|_| |-) *)?))((?:[1-9][0-9]?[0-9]?))((?:(?: *(?:\)|\.|_| |-) *)?))((?:[1-9][0-9][0-9][0-9][0-9][0-9][0-9]?[0-9]?[0-9]?))$/ },
{I:"a673cae4-8a83-4fd3-87ab-a80679beed81", C:null, A:null, G:{C:2, A:4, P:6, E:-1, D:-1}, R:/^((?:(?:\+|011|810|00)?))((?:2[07])|(?:2[0-9][0-9])|(?:3[0])|(?:35[023456789])|(?:4[023578])|(?:5[134568])|(?:5[09][0-9])|(?:6[0-6])|(?:6[78][0-9])|(?:69[012])|(?:8[124])|(?:85[02356])|(?:866)|(?:800)|(?:888)|(?:9[0123458])|(?:96[01234578])|(?:97[34567])|(?:99[45]))((?:(?: *(?:\(|\.|_| |-) *)))((?:[0-9][0-9]?[0-9]?[0-9]?[0-9]?))((?:(?: *(?:\)|\.|_| |-) *)))((?:[0-9][0-9][0-9][0-9][0-9][0-9]?[0-9]?[0-9]?[0-9]?[0-9]?[0-9]?))$/ },
{I:"3bb08a51-5a6c-45db-b4b4-70e3061d5191", C:null, A:null, G:{C:-1, A:-1, P:-1, E:1, D:-1}, R:/^((?:[0-9][0-9][0-9][0-9]?[0-9]?[0-9]?[0-9]?[0-9]?[0-9]?[0-9]?))$/ }
]
};
function Phone(p,c,a,n)
{
  var _c = "";
  var _a = "";
  var _p = "";
  var _e = "";
  var _d = "";

  function getImageIndex()
  {
    if (_c.length != 0)
    {
      switch (_c)
      {
        case "1":
          return 221;
        case "7":
          return 172;
        case "32":
          return 20;
        case "86":
          return 44;
        case "57":
          return 45;
        case "33":
          return 74;
        case "49":
          return 80;
        case "36":
          return 96;
        case "41":
          return 202
        case "39":
          return 105;
        case "972":
          return 104;
        case "52":
          return 136;
        case "31":
          return 147;
        case "351":
          return 168;
        case "966":
          return 182;
        case "34":
          return 196;
        case "46":
          return 201;
        case "44":
          return 83;
        case "971":
          return 219
        default:
          return 78;
      }
    }
    else
    {
      return 256;
    }
  }

  function toString()
  {
    var r = "";
    if (_p.length != 0)
    {
      r += "+";
      r += _c;
      r += " ";
      r += _a;
      r += _p;
    }
    else if (_e.length != 0)
    {
      r += "ext. ";
      r += _e;
    }
    else if (_d.length != 0)
    {
      r += "#";
      r += _d;
    }
    else
    {
      r += "?";
    }

    return r;
  }

  this.toString = toString;
  this.getImageIndex = getImageIndex;

  var re = /[\-\ \.]/gi;
  var pp = p.replace(re, "");
  p = pp;
  //alert(p);

  init();

  function init()
  {
    if (!c) c = uc_country;
    for (i = 0; i < uc_rules.R.length; i++)
    {
      if ((uc_rules.R[i].C != null) && ((c == null) || (c.indexOf(uc_rules.R[i].C) != 0)))
        continue;

      var m = p.match(uc_rules.R[i].R);
      if (m != null)
      {
        if (uc_rules.R[i].G.C > 0)
          _c = m[uc_rules.R[i].G.C];
        if (_c.length == 0)
          _c = c;
        if (uc_rules.R[i].G.A > 0)
          _a = m[uc_rules.R[i].G.A];
        if (uc_rules.R[i].G.P > 0)
          _p = m[uc_rules.R[i].G.P];
        if (uc_rules.R[i].G.E > 0)
          _e = m[uc_rules.R[i].G.E];
        if (uc_rules.R[i].G.D > 0)
          _d = m[uc_rules.R[i].G.D];
        break;
      }
    }
  }
}

</script><img src ="http://www.blogjava.net/yglwxl/aggbug/375434.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yglwxl/" target="_blank">九宝</a> 2012-04-21 02:41 <a href="http://www.blogjava.net/yglwxl/archive/2012/04/21/375434.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Observer模式在J2EE中的实现 [http://35java.com/zhibo/forum.php?mod=viewthread&amp;tid=108&amp;extra=page%3D3]</title><link>http://www.blogjava.net/yglwxl/archive/2011/02/13/344203.html</link><dc:creator>九宝</dc:creator><author>九宝</author><pubDate>Sun, 13 Feb 2011 11:24:00 GMT</pubDate><guid>http://www.blogjava.net/yglwxl/archive/2011/02/13/344203.html</guid><wfw:comment>http://www.blogjava.net/yglwxl/comments/344203.html</wfw:comment><comments>http://www.blogjava.net/yglwxl/archive/2011/02/13/344203.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yglwxl/comments/commentRss/344203.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yglwxl/services/trackbacks/344203.html</trackback:ping><description><![CDATA[<span  style="border-collapse: collapse; color: #444444; font-family: Tahoma, Helvetica, SimSun, sans-serif, Hei; font-size: 14px; line-height: 21px; ">引言：</span><span  style="border-collapse: collapse; color: #444444; font-family: Tahoma, Helvetica, SimSun, sans-serif, Hei; font-size: 14px; line-height: 21px; "><br style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; word-wrap: break-word; " />
</span><span  style="border-collapse: collapse; color: #444444; font-family: Tahoma, Helvetica, SimSun, sans-serif, Hei; font-size: 14px; line-height: 21px; ">&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;设计模式是经验的文档化。它是对被用来在特定场景下解决一般设计问题的类和相互通信的对象的描述。更通俗的来说，它是一个问题/解决方案对。一旦我们掌握了设计模式，就等于拥有了一支强有力的专家队伍。它甚至能够使面向对象的新手利用前人的经验找出职责明确的类和对象，从而获得优雅的解决方案。由于设计模式也是重构的目标，如果在设计的初期适当地引入设计模式，可以减少重构的工作量。</span><span  style="border-collapse: collapse; color: #444444; font-family: Tahoma, Helvetica, SimSun, sans-serif, Hei; font-size: 14px; line-height: 21px; "><br style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; word-wrap: break-word; " />
</span><span  style="border-collapse: collapse; color: #444444; font-family: Tahoma, Helvetica, SimSun, sans-serif, Hei; font-size: 14px; line-height: 21px; ">&nbsp; &nbsp;&nbsp; &nbsp;但是，我们也不能陷入模式的陷阱，为了使用模式而去套模式，那样会陷入形式主义。我们在使用模式的时候，一定要注意模式的意图（intent），而不要过多的去关注模式的实现细节，因为这些实现细节在特定情况下，可能会发生一些改变。不要顽固地认为设计模式一书中的类图或实现代码就代表了模式本身。</span><span  style="border-collapse: collapse; color: #444444; font-family: Tahoma, Helvetica, SimSun, sans-serif, Hei; font-size: 14px; line-height: 21px; "><br style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; word-wrap: break-word; " />
</span><span  style="border-collapse: collapse; color: #444444; font-family: Tahoma, Helvetica, SimSun, sans-serif, Hei; font-size: 14px; line-height: 21px; ">&nbsp; &nbsp;&nbsp; &nbsp;下面，我们来讨论一下为什么要在分布式、多层系统中使用Observer模式。</span><span  style="border-collapse: collapse; color: #444444; font-family: Tahoma, Helvetica, SimSun, sans-serif, Hei; font-size: 14px; line-height: 21px; "><br style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; word-wrap: break-word; " />
</span><span  style="border-collapse: collapse; color: #444444; font-family: Tahoma, Helvetica, SimSun, sans-serif, Hei; font-size: 14px; line-height: 21px; ">&nbsp; &nbsp;&nbsp; &nbsp;</span><hr class="l" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; word-wrap: break-word; display: block; clear: both; height: 1px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; background-image: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: #cdcdcd; color: #cdcdcd; border-collapse: collapse; font-family: Tahoma, Helvetica, SimSun, sans-serif, Hei; font-size: 14px; line-height: 21px; " />
<span  style="border-collapse: collapse; color: #444444; font-family: Tahoma, Helvetica, SimSun, sans-serif, Hei; font-size: 14px; line-height: 21px; "><br style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; word-wrap: break-word; " />
</span><span  style="border-collapse: collapse; color: #444444; font-family: Tahoma, Helvetica, SimSun, sans-serif, Hei; font-size: 14px; line-height: 21px; ">多层体系结构（multi-tier architecture）：</span><span  style="border-collapse: collapse; color: #444444; font-family: Tahoma, Helvetica, SimSun, sans-serif, Hei; font-size: 14px; line-height: 21px; "><br style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; word-wrap: break-word; " />
</span><span  style="border-collapse: collapse; color: #444444; font-family: Tahoma, Helvetica, SimSun, sans-serif, Hei; font-size: 14px; line-height: 21px; ">&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;三层体系结构是多层体系结构中最简单的一种，它一般包括：</span><span  style="border-collapse: collapse; color: #444444; font-family: Tahoma, Helvetica, SimSun, sans-serif, Hei; font-size: 14px; line-height: 21px; "><br style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; word-wrap: break-word; " />
</span><span  style="border-collapse: collapse; color: #444444; font-family: Tahoma, Helvetica, SimSun, sans-serif, Hei; font-size: 14px; line-height: 21px; ">&nbsp; &nbsp;&nbsp; &nbsp;</span>
<ul type="1" class="litype_1" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 14px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; word-wrap: break-word; border-collapse: collapse; color: #444444; font-family: Tahoma, Helvetica, SimSun, sans-serif, Hei; font-size: 14px; line-height: 21px; ">
    <li style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 2em; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; word-wrap: break-word; list-style-type: decimal; list-style-position: initial; list-style-image: initial; ">表示层(presentation)－窗口、报表-</li>
    <li style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 2em; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; word-wrap: break-word; list-style-type: decimal; list-style-position: initial; list-style-image: initial; ">业务逻辑层(business logic)－管理业务过程的任务和规则。它又可以细分为领域对象层（代表领域概念）和服务层（提供数据库交互、安全性、打印报表）。</li>
    <li style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 2em; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; word-wrap: break-word; list-style-type: decimal; list-style-position: initial; list-style-image: initial; ">存储层(storage)－持久化存储机制。如数据库服务器等。<br style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; word-wrap: break-word; " />
    </li>
</ul>
<span  style="border-collapse: collapse; color: #444444; font-family: Tahoma, Helvetica, SimSun, sans-serif, Hei; font-size: 14px; line-height: 21px; ">&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;</span><span  style="border-collapse: collapse; color: #444444; font-family: Tahoma, Helvetica, SimSun, sans-serif, Hei; font-size: 14px; line-height: 21px; "><br style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; word-wrap: break-word; " />
</span><span  style="border-collapse: collapse; color: #444444; font-family: Tahoma, Helvetica, SimSun, sans-serif, Hei; font-size: 14px; line-height: 21px; "><strong style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; word-wrap: break-word; font-weight: 700; ">图一：三层体系结构</strong></span><span  style="border-collapse: collapse; color: #444444; font-family: Tahoma, Helvetica, SimSun, sans-serif, Hei; font-size: 14px; line-height: 21px; "><br style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; word-wrap: break-word; " />
</span><span  style="border-collapse: collapse; color: #444444; font-family: Tahoma, Helvetica, SimSun, sans-serif, Hei; font-size: 14px; line-height: 21px; ">&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;</span><span  style="border-collapse: collapse; color: #444444; font-family: Tahoma, Helvetica, SimSun, sans-serif, Hei; font-size: 14px; line-height: 21px; "><img width="157" height="197" src="http://www.ibm.com/developerworks/cn/java/l-observerinj2ee/1.gif" border="0" alt="" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; word-wrap: break-word; " /></span><span  style="border-collapse: collapse; color: #444444; font-family: Tahoma, Helvetica, SimSun, sans-serif, Hei; font-size: 14px; line-height: 21px; ">&nbsp; &nbsp;&nbsp; &nbsp;</span><span  style="border-collapse: collapse; color: #444444; font-family: Tahoma, Helvetica, SimSun, sans-serif, Hei; font-size: 14px; line-height: 21px; "><br style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; word-wrap: break-word; " />
</span><span  style="border-collapse: collapse; color: #444444; font-family: Tahoma, Helvetica, SimSun, sans-serif, Hei; font-size: 14px; line-height: 21px; ">&nbsp; &nbsp;&nbsp; &nbsp;而Java 2平台企业版（J2EE）是一种利用Java 2平台来简化诸多与多级企业解决方案的开发、部署和管理相关的复杂问题的体系结构。它是开放的、基于标准的平台，用以开发、部署和管理N层结构、面向Web的，以服务器为中心的企业级应用。</span><span  style="border-collapse: collapse; color: #444444; font-family: Tahoma, Helvetica, SimSun, sans-serif, Hei; font-size: 14px; line-height: 21px; "><br style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; word-wrap: break-word; " />
</span><span  style="border-collapse: collapse; color: #444444; font-family: Tahoma, Helvetica, SimSun, sans-serif, Hei; font-size: 14px; line-height: 21px; ">&nbsp; &nbsp;&nbsp; &nbsp;为了支持领域对象的复用，并且使领域对象的接口变更所带来的影响最小化。我们将领域层（模型）和表示层（视图）相分离。</span><span  style="border-collapse: collapse; color: #444444; font-family: Tahoma, Helvetica, SimSun, sans-serif, Hei; font-size: 14px; line-height: 21px; "><br style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; word-wrap: break-word; " />
</span><span  style="border-collapse: collapse; color: #444444; font-family: Tahoma, Helvetica, SimSun, sans-serif, Hei; font-size: 14px; line-height: 21px; ">&nbsp; &nbsp;&nbsp; &nbsp;采用模型－视图模式的意义在于：</span><span  style="border-collapse: collapse; color: #444444; font-family: Tahoma, Helvetica, SimSun, sans-serif, Hei; font-size: 14px; line-height: 21px; "><br style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; word-wrap: break-word; " />
</span><span  style="border-collapse: collapse; color: #444444; font-family: Tahoma, Helvetica, SimSun, sans-serif, Hei; font-size: 14px; line-height: 21px; ">&nbsp; &nbsp;&nbsp; &nbsp;</span>
<ul type="1" class="litype_1" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 14px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; word-wrap: break-word; border-collapse: collapse; color: #444444; font-family: Tahoma, Helvetica, SimSun, sans-serif, Hei; font-size: 14px; line-height: 21px; ">
    <li style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 2em; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; word-wrap: break-word; list-style-type: decimal; list-style-position: initial; list-style-image: initial; ">支持聚合度更高的模型定义，使模型的定义可以集中在领域过程的定义，而不是图形界面上。</li>
    <li style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 2em; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; word-wrap: break-word; list-style-type: decimal; list-style-position: initial; list-style-image: initial; ">允许将模型和用户界面并行开发。</li>
    <li style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 2em; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; word-wrap: break-word; list-style-type: decimal; list-style-position: initial; list-style-image: initial; ">使用户界面的需求变化对领域层所造成的影响最小化。</li>
    <li style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 2em; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; word-wrap: break-word; list-style-type: decimal; list-style-position: initial; list-style-image: initial; ">允许建立与一个现有的领域层对象相连接的新视图，同时不影响领域层。</li>
    <li style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 2em; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; word-wrap: break-word; list-style-type: decimal; list-style-position: initial; list-style-image: initial; ">允许一个模型同时有多个视图，例如使用SVG和表格。</li>
    <li style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 2em; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; word-wrap: break-word; list-style-type: decimal; list-style-position: initial; list-style-image: initial; ">允许模型层独立于用户界面层执行。<br style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; word-wrap: break-word; " />
    </li>
</ul>
<span  style="border-collapse: collapse; color: #444444; font-family: Tahoma, Helvetica, SimSun, sans-serif, Hei; font-size: 14px; line-height: 21px; ">&nbsp; &nbsp;&nbsp; &nbsp;而这恰恰与Observer模式的意图相吻合。因此我们有必要跨层来实现Observer模式。</span><span  style="border-collapse: collapse; color: #444444; font-family: Tahoma, Helvetica, SimSun, sans-serif, Hei; font-size: 14px; line-height: 21px; "><br style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; word-wrap: break-word; " />
</span><span  style="border-collapse: collapse; color: #444444; font-family: Tahoma, Helvetica, SimSun, sans-serif, Hei; font-size: 14px; line-height: 21px; ">&nbsp; &nbsp;&nbsp; &nbsp;其实，在应用中更多的是采用MVC框架来架构整个企业应用的。在MVC框架中，Model和View之间存在着依赖关系，是Observer模式的典型应用。当然MVC框架还包括其它模式如Composite模式和Strategy模式。在J2EE平台中，我们可以把Web Tier（包括Jsp和servelet和JavaBean）看作是表示层，EJB Tier看作是领域层。而controller可能跨距Web Tier和 EJB Tier。</span><span  style="border-collapse: collapse; color: #444444; font-family: Tahoma, Helvetica, SimSun, sans-serif, Hei; font-size: 14px; line-height: 21px; "><br style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; word-wrap: break-word; " />
</span><span  style="border-collapse: collapse; color: #444444; font-family: Tahoma, Helvetica, SimSun, sans-serif, Hei; font-size: 14px; line-height: 21px; ">&nbsp; &nbsp;&nbsp; &nbsp;在Java类库中采用Java.util.Observable类和Java.util.Observer接口来实现Observer模式，它们在单个的Java VM.中运行的很好，但如果想在EJB中使用它们就会有一些问题。这正如我们引言中提到的，模式的具体实现在特定情况下，可能会发生一些改变。</span><span  style="border-collapse: collapse; color: #444444; font-family: Tahoma, Helvetica, SimSun, sans-serif, Hei; font-size: 14px; line-height: 21px; "><br style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; word-wrap: break-word; " />
</span><span  style="border-collapse: collapse; color: #444444; font-family: Tahoma, Helvetica, SimSun, sans-serif, Hei; font-size: 14px; line-height: 21px; ">&nbsp; &nbsp;&nbsp; &nbsp;</span><hr class="l" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; word-wrap: break-word; display: block; clear: both; height: 1px; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; border-width: initial; border-color: initial; background-image: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: #cdcdcd; color: #cdcdcd; border-collapse: collapse; font-family: Tahoma, Helvetica, SimSun, sans-serif, Hei; font-size: 14px; line-height: 21px; " />
<span  style="border-collapse: collapse; color: #444444; font-family: Tahoma, Helvetica, SimSun, sans-serif, Hei; font-size: 14px; line-height: 21px; "><br style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; word-wrap: break-word; " />
</span><span  style="border-collapse: collapse; color: #444444; font-family: Tahoma, Helvetica, SimSun, sans-serif, Hei; font-size: 14px; line-height: 21px; ">值传递还是远程引用传递？</span><span  style="border-collapse: collapse; color: #444444; font-family: Tahoma, Helvetica, SimSun, sans-serif, Hei; font-size: 14px; line-height: 21px; "><br style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; word-wrap: break-word; " />
</span><span  style="border-collapse: collapse; color: #444444; font-family: Tahoma, Helvetica, SimSun, sans-serif, Hei; font-size: 14px; line-height: 21px; ">&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;</span><span  style="border-collapse: collapse; color: #444444; font-family: Tahoma, Helvetica, SimSun, sans-serif, Hei; font-size: 14px; line-height: 21px; "><strong style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; word-wrap: break-word; font-weight: 700; ">值传递：</strong></span><span  style="border-collapse: collapse; color: #444444; font-family: Tahoma, Helvetica, SimSun, sans-serif, Hei; font-size: 14px; line-height: 21px; ">&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;</span><span  style="border-collapse: collapse; color: #444444; font-family: Tahoma, Helvetica, SimSun, sans-serif, Hei; font-size: 14px; line-height: 21px; "><br style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; word-wrap: break-word; " />
</span><span  style="border-collapse: collapse; color: #444444; font-family: Tahoma, Helvetica, SimSun, sans-serif, Hei; font-size: 14px; line-height: 21px; ">在Java RMI中要求所有的参数和返回类型是JAVA的基本类型或实现Java.io.Serilizable的对象。串行化对象通过值传递（又名拷贝传递），而不是引用传递，这意味着在某一层中串行化对象的更并不自动影响到其它的对象。&nbsp; &nbsp;&nbsp; &nbsp;</span><span  style="border-collapse: collapse; color: #444444; font-family: Tahoma, Helvetica, SimSun, sans-serif, Hei; font-size: 14px; line-height: 21px; "><br style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; word-wrap: break-word; " />
</span><span  style="border-collapse: collapse; color: #444444; font-family: Tahoma, Helvetica, SimSun, sans-serif, Hei; font-size: 14px; line-height: 21px; ">&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;</span><span  style="border-collapse: collapse; color: #444444; font-family: Tahoma, Helvetica, SimSun, sans-serif, Hei; font-size: 14px; line-height: 21px; "><strong style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; word-wrap: break-word; font-weight: 700; ">远程引用传递：</strong></span><span  style="border-collapse: collapse; color: #444444; font-family: Tahoma, Helvetica, SimSun, sans-serif, Hei; font-size: 14px; line-height: 21px; ">&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;</span><span  style="border-collapse: collapse; color: #444444; font-family: Tahoma, Helvetica, SimSun, sans-serif, Hei; font-size: 14px; line-height: 21px; "><br style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; word-wrap: break-word; " />
</span><span  style="border-collapse: collapse; color: #444444; font-family: Tahoma, Helvetica, SimSun, sans-serif, Hei; font-size: 14px; line-height: 21px; ">对于EJB对象而言，它由两个接口（home接口和remote接口）和一个类组成。容器会根据ejb规范来生成实现上面两个接口的类（我们分别称为xxxEJBHome对象和xxxEjbObject对象）。在较多的容器的实现方案中，xxxEJBHome对象使用了factory模式来创建xxxEjbObject对象；xxxEjbObject对象则采用proxy模式，作为xxxBean的代理类。在生成以上两个对象的同时，容器会从部署文件中读取关于安全、事务、持久性等服务并在xxxEjbObject对象和xxxEJBHome对象中添加以上服务的代码。而且xxxEJBHome对象和xxxEjbObject对象都是分布式对象，我们在此只讨论xxxEjbObject对象。所谓分布式对象，从本质上来讲，分为3个部分：object server、skeleton、stub。其中object server和skeleton位于服务器端，而stub位于客户端。Object server负责实现业务逻辑，skeleton负责marshal和unmarshal方法签名。&nbsp; &nbsp;&nbsp; &nbsp;</span><span  style="border-collapse: collapse; color: #444444; font-family: Tahoma, Helvetica, SimSun, sans-serif, Hei; font-size: 14px; line-height: 21px; "><br style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; word-wrap: break-word; " />
</span><span  style="border-collapse: collapse; color: #444444; font-family: Tahoma, Helvetica, SimSun, sans-serif, Hei; font-size: 14px; line-height: 21px; ">&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;</span><span  style="border-collapse: collapse; color: #444444; font-family: Tahoma, Helvetica, SimSun, sans-serif, Hei; font-size: 14px; line-height: 21px; "><br style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; word-wrap: break-word; " />
</span><span  style="border-collapse: collapse; color: #444444; font-family: Tahoma, Helvetica, SimSun, sans-serif, Hei; font-size: 14px; line-height: 21px; "><strong style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; word-wrap: break-word; font-weight: 700; ">图二：分布式对象</strong></span><span  style="border-collapse: collapse; color: #444444; font-family: Tahoma, Helvetica, SimSun, sans-serif, Hei; font-size: 14px; line-height: 21px; "><br style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; word-wrap: break-word; " />
</span><span  style="border-collapse: collapse; color: #444444; font-family: Tahoma, Helvetica, SimSun, sans-serif, Hei; font-size: 14px; line-height: 21px; ">&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;</span><span  style="border-collapse: collapse; color: #444444; font-family: Tahoma, Helvetica, SimSun, sans-serif, Hei; font-size: 14px; line-height: 21px; "><img width="576" height="310" src="http://www.ibm.com/developerworks/cn/java/l-observerinj2ee/2.gif" border="0" alt="" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; word-wrap: break-word; " /></span><span  style="border-collapse: collapse; color: #444444; font-family: Tahoma, Helvetica, SimSun, sans-serif, Hei; font-size: 14px; line-height: 21px; ">&nbsp; &nbsp;&nbsp; &nbsp;</span><span  style="border-collapse: collapse; color: #444444; font-family: Tahoma, Helvetica, SimSun, sans-serif, Hei; font-size: 14px; line-height: 21px; "><br style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; word-wrap: break-word; " />
</span><span  style="border-collapse: collapse; color: #444444; font-family: Tahoma, Helvetica, SimSun, sans-serif, Hei; font-size: 14px; line-height: 21px; ">&nbsp; &nbsp;&nbsp; &nbsp;显然，EJB的客户（调用EJB的对象）可以是任何对象，包括EJB和一般的Java类甚至是用任何语言写的corba客户端。</span><span  style="border-collapse: collapse; color: #444444; font-family: Tahoma, Helvetica, SimSun, sans-serif, Hei; font-size: 14px; line-height: 21px; "><br style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; word-wrap: break-word; " />
</span><span  style="border-collapse: collapse; color: #444444; font-family: Tahoma, Helvetica, SimSun, sans-serif, Hei; font-size: 14px; line-height: 21px; ">&nbsp; &nbsp;&nbsp; &nbsp;从EJB的客户视角来看的话，我们只能看到一个home接口、一个remote接口（对于实体bean的话，还可以看见一个主键类，而bean类对客户是不可见的）。但我们从上面的论述，我们可以知道，对于remote接口中地方法调用，实际上是多态地调用XXX_Stub类。即XXX_Stub对象对客户具有可见性（但这种可见性是透明的，即客户不知道这种可见性的存在）。由于，XXX_Stub对象和Object Server实现了相同的接口，并且Object server真正实现了业务逻辑。所以，当在客户端调用XXX_Stub对象的方法时候，XXX_Stub对象通过socket通信机制将方法签名传给XXX_Skeleton对象，XXX_Skeleton对象在去委托Object Server完成业务处理逻辑。因此，Object Server本身发生了改变。我们称XXX_Stub对象是Object Server对象的远程引用，并认为当分布式对象作为参数传递的时候，是通过引用传递的（会产生副作用</span>
<img src ="http://www.blogjava.net/yglwxl/aggbug/344203.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yglwxl/" target="_blank">九宝</a> 2011-02-13 19:24 <a href="http://www.blogjava.net/yglwxl/archive/2011/02/13/344203.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>配置SWT开发环境 -Djava.library.path=.\exe </title><link>http://www.blogjava.net/yglwxl/archive/2009/07/22/287868.html</link><dc:creator>九宝</dc:creator><author>九宝</author><pubDate>Wed, 22 Jul 2009 08:22:00 GMT</pubDate><guid>http://www.blogjava.net/yglwxl/archive/2009/07/22/287868.html</guid><wfw:comment>http://www.blogjava.net/yglwxl/comments/287868.html</wfw:comment><comments>http://www.blogjava.net/yglwxl/archive/2009/07/22/287868.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yglwxl/comments/commentRss/287868.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yglwxl/services/trackbacks/287868.html</trackback:ping><description><![CDATA[<p>本文假定读者使用Windows操作系统+JDK 1.4，其他平台和JDK版本应该也是八九不离十。</p>
<p>为了编译和运行SWT程序，我们有两种选择：1- 使用Eclipse SDK；2- 下载单独的SWT二进制文件和源文件。</p>
<p>随Eclipse SDK，我们可以在它的plugins目录下找到SWT的二进制文件，通常的目录名称是：org.eclipse.swt.win32_xxxx，后缀是版本号，在这个目录下有os和ws两个子目录，内容分别是SWT的JNI库和swt.jar。</p>
<p>如果不是使用Eclipse来开发，或者需要SWT的源文件，那么需要下载单独的SWT二进制和源文件包，在下面的地址可以找到：</p>
<p>http://mirror.pacific.net.au/eclipse/eclipse/downloads/drops/R-3.0.1-200409161125/swt-3.0.1-win32.zip </p>
<p><br />
这个zip文件解包以后包含JNI库（一些DLL）和swt.jar，以及swtsrc.zip，这个swtsrc就是我们SWT的源文件了，包括C和Java的源代码。</p>
<p>为了运行SWT程序，我们需要首先编译我们SWT的代码，这个时候需要告诉编译器swt.jar的位置；编译成功以后，我们除了指明classpath包含swt.jar之外，需要在命令行告诉java.exe另一个参数，那就是java.library.path，看上去大概是这个样子：</p>
<p>java -cp %SWT_HOME%\swt.jar SimplestSWT -Djava.library.path=%SWT_HOME%</p>
<p>如果你使用的是Eclipse SDK 3.1M5a或者更新的版本，你可以直接右键.java文件选择Run As -&gt; SWT Application，则不用在命令行写那么长的参数了。</p>
<p>比较有意思的是，我们可以在eclipse.org的SWT下载页面看到目前SWT支持的平台：</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Windows 98/ME/2000/XP <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Windows CE (ARM PocketPC) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Windows CE (ARM PocketPC, J2ME profile) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Linux (x86/Motif) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Linux (x86/GTK 2) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Linux (AMD 64/GTK 2) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Solaris 8 (SPARC/Motif) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; QNX (x86/Photon) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AIX (PPC/Motif) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HP-UX (HP9000/Motif)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Mac OSX (Mac/Carbon)<br />
呵呵，支持的平台虽然有限，不过还是蛮多了。</p>
<p><br />
本文来自CSDN博客，转载请标明出处：http://blog.csdn.net/tiney/archive/2008/09/12/2916785.aspx</p>
<img src ="http://www.blogjava.net/yglwxl/aggbug/287868.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yglwxl/" target="_blank">九宝</a> 2009-07-22 16:22 <a href="http://www.blogjava.net/yglwxl/archive/2009/07/22/287868.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java中的sizeof（转）</title><link>http://www.blogjava.net/yglwxl/archive/2009/06/24/283968.html</link><dc:creator>九宝</dc:creator><author>九宝</author><pubDate>Wed, 24 Jun 2009 09:02:00 GMT</pubDate><guid>http://www.blogjava.net/yglwxl/archive/2009/06/24/283968.html</guid><wfw:comment>http://www.blogjava.net/yglwxl/comments/283968.html</wfw:comment><comments>http://www.blogjava.net/yglwxl/archive/2009/06/24/283968.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yglwxl/comments/commentRss/283968.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yglwxl/services/trackbacks/283968.html</trackback:ping><description><![CDATA[16位机器，c++，sizeof(int)=2byte长度<br />
32位机器，c++，sizeof(int)=4byte长度<br />
&nbsp;在C/C++中，当我们想知道一个对象或者一个原始数据类型所占用的内存大小时，只需简单调用<span class="hilite2">sizeof</span>操作符即可，但是，在<span class="hilite1">java</span>中是没有相应的操作符或者方法来直接完成相应功能的。<span class="hilite2">sizeof</span> 在C/C++得到大量的运用，是程序员必不可少的工具之一，那么为什么<span class="hilite1">java</span>却不提供呢？要回答这个问题，我们可以从另外一个角度来看，那就是为什么C/C++中要使用<span class="hilite2">sizeof</span>。C中要使用<span class="hilite2">sizeof</span>主要是因为C程序员要自己管理堆内存的分配和释放，在使用malloc来获取堆内存时，我们必须知道要创建的对象的具体大小，才能根据对象的具体大小从堆中分配相应大小的动态内存，而获取对象大小这个工作就是通过<span class="hilite2">sizeof</span>来完成的。到了C++，我们可以使用操作符new来动态分配内存，这时，对于<span class="hilite2">sizeof</span>的依赖也没有在C时代时那么严重了。在C++中保留<span class="hilite2">sizeof</span>，主要是为了跟C保持兼容。说到这里，我们也可以明白为什么<span class="hilite1">java</span>中为什么没有<span class="hilite2">sizeof</span>了：<span class="hilite1">java</span>中的内存管理任务直接交给了JVM，这比C++更为彻底。同时，<span class="hilite1">java</span>是一个全新设计的完全面向对象语言，不存在C++向下兼容的问题，因此，<span class="hilite1">java</span>中不存在类似<span class="hilite2">sizeof</span>的操作符。（存在即合理，不存在也有它的道理：））。<br />
&nbsp;&nbsp;&nbsp; 但是，有些时候事情并不没有想象中那么简单。当我们用<span class="hilite1">Java</span>编写应用程序时，虽然很多时候我们都不需要了解内存的使用情况，因为JVM已经帮我们照顾好这些珍贵的资源，但是，某些时候，譬如我们要编写一个性能监测工具或者在调试时我们需要知道某个对象所占用的内存大小的。怎么办呢？是不是很怀念我们的<span class="hilite2">sizeof</span>呢。<br />
&nbsp;&nbsp; 不用担心，所谓天无绝人之路。如果我们使用的JDK的版本是5.0或以上，那么，我们可以使用新提供的Instrument包。通过这个包提供的接口和类，我们可以很容易获取一个对象实际占用的内存大小。Instrument的具体描述可以参看JDK文档，【1】提供了一个很好的例子。<br />
&nbsp;&nbsp; 但是，上述方法只能获取对象的占用内存的大小，对于int ，long等原始类型是没有办法得知其内存大小的。有的人可能会问，这些原始类型在<span class="hilite1">java</span>的specification中定义好的吗？我们都知道，int用4个字节，long占用8个字节。对，<span class="hilite1">java</span>规范是对原是类型的大小作出了定义，但是这仅仅是对该类型逻辑上所需的字节作出了规定，具体到每个JVM实现中用到的实际内存大小是没有限制的，我们完全可以实现一个JVM使用8个字节来保存一个int（不知道现在64位CPU机子上是不是使用8个字节（64位）来保存一个int，我这里没有机器可以进行试验）。因此，要知道一个原始类型到底占用多少内存，我们还需另外想办法。【2】【3】【4】【5】提供了相关的信息，有兴趣的朋友可以参考一下。这里，贴出各个基本类型所占用内存的实际大小，看跟你想象中是否一致。（from 【5】Sun JRE 1.4.2 Client Hotspot JVM on Windows）<br />
<table border="0">
    <tbody>
        <tr>
            <td style="font-weight: bold">Type</td>
            <td style="font-weight: bold">Size (bytes)</td>
        </tr>
        <tr>
            <td><span class="hilite1">java</span>.lang.Object</td>
            <td>8</td>
        </tr>
        <tr>
            <td><span class="hilite1">java</span>.lang.Float</td>
            <td>16</td>
        </tr>
        <tr>
            <td><span class="hilite1">java</span>.lang.Double</td>
            <td>16</td>
        </tr>
        <tr>
            <td><span class="hilite1">java</span>.lang.Integer</td>
            <td>16</td>
        </tr>
        <tr>
            <td><span class="hilite1">java</span>.lang.Long</td>
            <td>16</td>
        </tr>
        <tr>
            <td><span class="hilite1">java</span>.math.BigInteger</td>
            <td>56 (*)<br />
            </td>
        </tr>
        <tr>
            <td><span class="hilite1">java</span>.lang.BigDecimal</td>
            <td>72 (*)<br />
            </td>
        </tr>
        <tr>
            <td style="vertical-align: top"><span class="hilite1">java</span>.lang.String<br />
            </td>
            <td style="vertical-align: top">2*(Length) + 38 &#177; 2<br />
            </td>
        </tr>
        <tr>
            <td style="vertical-align: top">empty <span class="hilite1">java</span>.util.Vector<br />
            </td>
            <td style="vertical-align: top">80<br />
            </td>
        </tr>
        <tr>
            <td style="vertical-align: top">object reference<br />
            </td>
            <td style="vertical-align: top">4<br />
            </td>
        </tr>
        <tr>
            <td style="vertical-align: top">float array<br />
            </td>
            <td style="vertical-align: top">4*(Length) + 14 &#177; 2<br />
            </td>
        </tr>
    </tbody>
</table>
<img src ="http://www.blogjava.net/yglwxl/aggbug/283968.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yglwxl/" target="_blank">九宝</a> 2009-06-24 17:02 <a href="http://www.blogjava.net/yglwxl/archive/2009/06/24/283968.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>制作数字签名(转)</title><link>http://www.blogjava.net/yglwxl/archive/2009/05/19/271559.html</link><dc:creator>九宝</dc:creator><author>九宝</author><pubDate>Tue, 19 May 2009 08:40:00 GMT</pubDate><guid>http://www.blogjava.net/yglwxl/archive/2009/05/19/271559.html</guid><wfw:comment>http://www.blogjava.net/yglwxl/comments/271559.html</wfw:comment><comments>http://www.blogjava.net/yglwxl/archive/2009/05/19/271559.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yglwxl/comments/commentRss/271559.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yglwxl/services/trackbacks/271559.html</trackback:ping><description><![CDATA[<p>一、服务器端： &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1．将程序需要用到的各种包文件全部解压，然后使用JDK的打包命令将编译好的监控程序.class和刚才解压的包一起打包到一个包中。都是dos状态下的命令，具体命令见jdk1.4的bin目录下，（这里的文件包括JDBC驱动的三个文件） &nbsp; <br />
&nbsp; &nbsp; 命令如下： &nbsp; <br />
&nbsp; jar &nbsp; cvf &nbsp; &nbsp; monitor.jar &nbsp; *.class &nbsp; <br />
&nbsp; 此命令生成一个名为monitor.jar的包 &nbsp; <br />
&nbsp; 2．为刚才创建的包文件（monitor.jar）创建keystore和keys。其中 &nbsp; <br />
&nbsp; keystore将用来存放密匙(private &nbsp; keys)和公共钥匙的认证，alias别名这儿取为monitor。 &nbsp; <br />
&nbsp; 命令如下： &nbsp; <br />
&nbsp; keytool &nbsp; -genkey &nbsp; -keystore &nbsp; monitor.keystore &nbsp; &#8211;alias &nbsp; monitor &nbsp; -validity &nbsp; 4000 &nbsp; <br />
&nbsp; &nbsp; &nbsp; 此命令生成了一个名为monitor.keystore的keystore文件， &nbsp; <br />
&nbsp; 接着这条命令，系统会问你好多问题，比如你的公司名称，你 &nbsp; <br />
&nbsp; 的地址，你要设定的密码等等，都由自己的随便写。 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; 3．使用刚才生成的钥匙来对jar文件进行签名 &nbsp; <br />
&nbsp; 命令如下： &nbsp; <br />
&nbsp; &nbsp; &nbsp; jarsigner &nbsp; &nbsp; -keystore &nbsp; &nbsp; monitor.keystore &nbsp; &nbsp; monitor.jar &nbsp; monitor &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 这个命令将对monitor.jar文件进行签名，不会生成新文件。 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; 4．将公共钥匙导入到一个cer文件中，这个cer文件就是要拷贝到客户端的唯一文件 &nbsp; 。 &nbsp; <br />
&nbsp; 命令如下： &nbsp; <br />
&nbsp; keytool &nbsp; &nbsp; -export &nbsp; &nbsp; -keystore &nbsp; &nbsp; monitor.keystore &nbsp; -alias &nbsp; monitor &nbsp; &nbsp; -file &nbsp; &nbsp; monitor.cer &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 此条命令将生成monitor.cer认证文件，当然这几步都有可能问你刚 &nbsp; <br />
&nbsp; 才设置的密码。 &nbsp; <br />
&nbsp; 这样就完成了服务器端的设置。这时你就可以将jar文件和keystore文件以及cer文件(我这儿是monitor.jar,monitor.keystore,monitor.cer)拷贝到服务器的目录下了，我用的是Tomcat，所以就拷贝到C:\JBuilder8\thirdparty\jakarta-tomcat-4.1.12-LE-jdk14\webapps\ROOT下的自己建的一个目录下了。 &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; 二、客户端： &nbsp; <br />
&nbsp; 1． &nbsp; &nbsp; &nbsp; &nbsp; 首先应该安装2re-1_4_1_03-windows-i586-i，然后将服务器端生成的monitor.cer &nbsp; <br />
&nbsp; 文件拷贝到jre的特定目录下，我这儿是： &nbsp; <br />
&nbsp; C:\Program &nbsp; Files\Java\j2re1.4.1_03\lib\security目录下。 &nbsp; <br />
&nbsp; 2． &nbsp; &nbsp; &nbsp; &nbsp; 将公共钥匙倒入到jre的cacerts（这是jre的默认keystore） &nbsp; <br />
&nbsp; 命令如下： &nbsp; <br />
&nbsp; &nbsp; &nbsp; keytool &nbsp; &nbsp; -import &nbsp; &nbsp; -alias &nbsp; monitor &nbsp; -file &nbsp; &nbsp; monitor.cer &nbsp; &nbsp; &nbsp; <br />
&nbsp; -keystore &nbsp; &nbsp; cacerts &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; 注意这儿要你输入的是cacerts的密码，应该是changeit，而不 &nbsp; <br />
&nbsp; 是你自己设定的keystore的密码。 &nbsp; <br />
&nbsp; 3． &nbsp; &nbsp; &nbsp; &nbsp; 修改policy策略文件，在dos状态下使用命令 &nbsp; &nbsp; policytool &nbsp; <br />
&nbsp; 系统会自动弹出一个policytool的对话框，如图4所示，在这里面首先选择file菜单的open项， &nbsp; <br />
&nbsp; 打开C:\Program &nbsp; Files\Java\j2re1.4.1_03\lib\security目录下的java.poliy文件，然后在edit菜单中选择Change &nbsp; keystore &nbsp; ，在对话框中new &nbsp; keystore &nbsp; url:中输入 &nbsp; <br />
&nbsp; file:/ &nbsp; C:/Program &nbsp; Files/Java/j2re1.4.1_03/lib/security/cacerts, &nbsp; <br />
&nbsp; 这儿要注意反斜杠，在new &nbsp; keystore &nbsp; type &nbsp; 中输入JKS，这是cacerts的固定格式，然后单击Add &nbsp; Policy &nbsp; Entry，在出现的对话框中CodeBase中输入： &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; http://168.168.1.202：8080/* &nbsp; <br />
&nbsp; 其中的168.168.1.202是我服务器的IP地址，8080是我的Tomcat的端口，如果你是在别的应用服务器上比如说是apache，那端口号就可以省略掉。 &nbsp; <br />
&nbsp; 在SignedBy中输入(别名alias):这儿是Monitor &nbsp; <br />
&nbsp; 然后单击add &nbsp; peimission按钮，在出现的对话框中permission中选择你想给这个applet的权限，这儿具体有许多权限，读者可以自己找资料看看。我这儿就选用allpeimission，右边的signedBy中输入别名：monitor &nbsp; <br />
&nbsp; 最后保存，在file菜单的save项。 &nbsp; <br />
&nbsp; &nbsp; 当然你可以看见我已经对多个包实现了签名认证。 &nbsp; <br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <br />
&nbsp; 看需要可以选择设不设置客户端.</p>
<img src ="http://www.blogjava.net/yglwxl/aggbug/271559.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yglwxl/" target="_blank">九宝</a> 2009-05-19 16:40 <a href="http://www.blogjava.net/yglwxl/archive/2009/05/19/271559.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java数字签名（签名生成，用证书验证签名） (转)</title><link>http://www.blogjava.net/yglwxl/archive/2009/05/19/271556.html</link><dc:creator>九宝</dc:creator><author>九宝</author><pubDate>Tue, 19 May 2009 08:30:00 GMT</pubDate><guid>http://www.blogjava.net/yglwxl/archive/2009/05/19/271556.html</guid><wfw:comment>http://www.blogjava.net/yglwxl/comments/271556.html</wfw:comment><comments>http://www.blogjava.net/yglwxl/archive/2009/05/19/271556.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yglwxl/comments/commentRss/271556.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yglwxl/services/trackbacks/271556.html</trackback:ping><description><![CDATA[转载序：网上找的好文章，一篇就把我找了几天的所有东西都概括进来了，真是非常感谢作者：李素科&nbsp; 其实在找资料的过程当中，主要没解决的问题在于如何获得KeyStore文件中的PrivateKey，本来查jsdk 1.4 api文档就可以知道了，但是居然从上到下看了2遍，没有发现这个方法:load()&nbsp; .......)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
证书(Certificate，也称public-key certificate)是用某种签名算法对某些内容(比如公钥)进行数字签名后得到的、可以用来当成信任关系中介的数字凭证。证书发行机构通过发行证书告知证书使用者或实体其公钥(public-key)以及其它一些辅助信息。证书在电子商务安全交易中有着广泛的应用，证书发行机构也称CA(Certificate Authority)。 <br />
<br />
<center><font color="#000099"><strong>应用证书</strong></font></center>
<p><br />
<br />
证书在公钥加密应用中的作用是保证公钥在某些可信的机构发布，其在协议SSL、电子交易协议SET等方面有重要的应用。图1显示了一个最简单的证书应用方法： <br />
<br />
</p>
<center><img src="http://www.it918.com/Files/NewsUpfiles/20040414C1527281.gif"  alt="" /></center><br />
<br />
<center>图1 证书应用方法</center>
<p><br />
<br />
证书的应用步骤是： <br />
<br />
（1） A把自己的公钥PKA送到CA(Certificate Authority)； <br />
<br />
（2） CA用自己的私钥和A的公钥生成A的证书，证书内包括CA的数字签名。签名对象包括需要在证书中说明的内容，比如A的公钥、时间戳、序列号等，为了简化这里不妨假设证书中只有三项内容：A的公钥PKA、时间戳TIME1、序列号IDA。那么CA发送给A的简单证书凭证可表达为：CertA=Eca[TIME1,IDA,PKA]； <br />
<br />
（3） B同样把自己的公钥PKB送到CA； <br />
<br />
（4） B得到CA发布的证书CertB; <br />
<br />
（5） A告知B证书CertA； <br />
<br />
（6） B告知A证书CertB。 <br />
<br />
A、B各自得到对方证书后，利用从CA得到的公钥(在CA的自签证书中)验证彼此对方的证书是否有效，如果有效，那么就得到了彼此的公钥。利用对方的公钥，可以加密数据，也可以用来验证对方的数字签名。 <br />
<br />
本文为了方便说明，并没有使用从CA获得的证书，而是通信双方各自产生自签证书，也就是说图1的A和B并没有经过CA，不过前提是A和B之间是互相拥有对方的证书。 <br />
<br />
证书的内容和意义如表1所示（这里以通用X .509证书格式为例）。 <br />
<br />
</p>
<center>表1 证书内容和意义</center><br />
<br />
<center><ccid_nobr>
<table class="content" width="502" border="1">
    <tbody>
        <tr>
            <td>证书内容</td>
            <td>意义</td>
        </tr>
        <tr>
            <td>Version</td>
            <td>告诉这个X.509证书是哪个版本的，目前有v1、V2、v3</td>
        </tr>
        <tr>
            <td>Serial Number</td>
            <td>由证书分发机构设置证书的序列号</td>
        </tr>
        <tr>
            <td>Signature Algorithm Identifier</td>
            <td>证书采用什么样的签名算法</td>
        </tr>
        <tr>
            <td>Issuer Name</td>
            <td>证书发行者名，也就是给这个证书签名的机构名</td>
        </tr>
        <tr>
            <td>Validity Period</td>
            <td>证书有效时间范围</td>
        </tr>
        <tr>
            <td>Subject Name</td>
            <td>被证书发行机构签名后的公钥拥有者或实体的名字，采用X.500协议，在Internet上的标志是惟一的。例如：CN=Java,OU=Infosec,O=Infosec Lab,C=CN表示一个subject name。</td>
        </tr>
    </tbody>
</table>
</ccid_nobr></center>
<p><br />
<br />
对证书的详细定义及其应用相关的各种协议，这里不加详细说明，详细细节请查看RFC2450、RFC2510、RFC2511、RFC2527、RFC2528、RFC2559、RFC2560、RFC2585、RFC2587等文档。 <br />
<br />
</p>
<center><font color="#000099"><strong>生成自签证书</strong></font></center>
<p><br />
<br />
个人或机构可以从信任的证书分发机构申请得到证书，比如说，可以从http://ca.pku.edu.cn 得到一个属于个人的证书。这里可以利用J2SDK的安全工具keytool手工产生自签证书，所谓自签证书是指证书中的&#8220;Subject Name&#8221;和&#8220;Issuer Name&#8221;相同的证书。 </p>
<p>下面产生一个自签证书。安装完J2SDK（这里用的是J2SDK1.4）后，在J2SDK安装目录的bin目录下，有一个keytool的可执行程序。利用keytool产生自签证书的步骤如下： <br />
<br />
第一步，用-genkey命令选项，产生公私密钥对。在控制台界面输入：keytool -genkey -alias testkeypair -keyalg RSA -keysize 1024 -sigalg MD5withRSA。这里的-alias表示使用这对公私密钥产生新的keystore入口的别名(keystore是用来存放管理密钥对和证书链的，缺省位置是在使用者主目录下，以.keystore为名的隐藏文件，当然也可指定某个路径存放.keystore文件)；-keyalg是产生公私钥对所用的算法，这里是RSA；-keysize定义密钥的长度；-sigalg是签名算法，选择MD5withRSA，即用RSA签名，然后用MD5哈希算法摘要。接下来，系统会提示进行一些输入： <br />
<br />
<ccid_nobr>
<table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="550" align="center" bordercolorlight="black" border="1">
    <tbody>
        <tr>
            <td class="code" bgcolor="#e6e6e6">
            <pre><ccid_code>输入keystore密码：  abc123
            您的名字与姓氏是什么？
            [Unknown]：  Li
            您的组织单位名称是什么？
            [Unknown]：  InfosecLab
            您的组织名称是什么？
            [Unknown]：  InfosecLab Group
            您所在的城市或区域名称是什么？
            [Unknown]：  Beijing
            您所在的州或省份名称是什么？
            [Unknown]：  Beijing
            该单位的两字母国家代码是什么
            [Unknown]：  CN
            CN=Li, OU=InfosecLab, O=InfosecLab Group, L=Beijing, ST=Beijing, C=CN 正确吗？
            [否]：  y
            输入&lt;testkeypair&gt;的主密码 (如果和 keystore 密码相同，按回车）：</ccid_code></pre>
            </td>
        </tr>
    </tbody>
</table>
</ccid_nobr><br />
<br />
第二步，产生自签证书，输入以下命令： <br />
<br />
<ccid_nobr>
<table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="550" align="center" bordercolorlight="black" border="1">
    <tbody>
        <tr>
            <td class="code" bgcolor="#e6e6e6">
            <pre><ccid_code>keytool -selfcert -alias testkeypair -dname "CN=Li, OU=InfosecLab, O=InfosecLab
            Group, L=Beijing, ST=Beijing, C=CN"
            输入keystore密码：  abc123</ccid_code></pre>
            </td>
        </tr>
    </tbody>
</table>
</ccid_nobr><br />
<br />
第三步，导出自签证书，由上面两步产生的证书，已经存放在以&#8220;testkeypair&#8221;为别名的keystore入口了，如果使用其文件，必须导出证书。输入: <br />
<br />
<ccid_nobr>
<table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="550" align="center" bordercolorlight="black" border="1">
    <tbody>
        <tr>
            <td class="code" bgcolor="#e6e6e6">
            <pre><ccid_code>keytool -export -rfc -alias testkeypair -file mycert.crt
            输入keystore密码：  abc123
            保存在文件中的认证 &lt;mycert.crt&gt;</ccid_code></pre>
            </td>
        </tr>
    </tbody>
</table>
</ccid_nobr><br />
<br />
这样，就得到了一个自签的证书mycert.crt。注意，选项rfc是把证书输出为RFC1421定义的、用Base64最终编码的格式。 <br />
<br />
</p>
<center><font color="#000099"><strong>读取证书</strong></font></center>
<p><br />
<br />
Java为安全应用提供了丰富的API，J2SDK1.4 的JSSE (JavaTM Secure Socket Extension) 包括javax.security.certificate包，并且提供对证书的操作方法。而对证书的读操作，只用java.security.cert. CertificateFactory和java.security.cert.X509Certificate就可以了。下面是读取证书内容的部分代码： <br />
<br />
<ccid_nobr>
<table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="550" align="center" bordercolorlight="black" border="1">
    <tbody>
        <tr>
            <td class="code" bgcolor="#e6e6e6">
            <pre><ccid_code>import javax.swing.*;
            import java.awt.*;
            import java.awt.event.*;
            import javax.swing.table.*;
            import java.security.cert.CertificateFactory;
            import java.security.cert.X509Certificate;
            import java.io.*;
            public class CARead extends JPanel {
            private String CA_Name;
            private String CA_ItemData[][] = new String[9][2];
            private String[] columnNames = {"证书字段标记","内容" };
            public CARead(String CertName) {
            CA_Name=CertName;
            /* 三个Panel用来显示证书内容*/
            JTabbedPane tabbedPane = new JTabbedPane();
            JPanel panelNormal = new JPanel();
            tabbedPane.addTab("普通信息", panelNormal);
            JPanel panelAll=new JPanel();
            panelAll.setLayout(new BorderLayout());
            tabbedPane.addTab("所有信息",panelAll);
            JPanel panelBase64=new JPanel();
            panelBase64.setLayout(new BorderLayout());
            tabbedPane.addTab("Base64编码信息",panelBase64);
            /* 读取证书常规信息 */
            Read_Normal(panelNormal);
            /* 读取证书文件字符串表示内容 */
            Read_Bin(panelAll);
            /* 读取证原始Base64编码形式的证书文件 */
            Read_Raw(panelBase64);
            tabbedPane.setSelectedIndex(0);
            setLayout(new GridLayout(1, 1));
            add(tabbedPane);
            }
            /*以下是定义的Read_Normal()，Read_Bin(),Read_Raw()以及main()
            这里省略...   */
            }</ccid_code></pre>
            </td>
        </tr>
    </tbody>
</table>
</ccid_nobr><br />
<br />
定义证书信息的读取函数如下： <br />
<br />
<ccid_nobr>
<table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="550" align="center" bordercolorlight="black" border="1">
    <tbody>
        <tr>
            <td class="code" bgcolor="#e6e6e6">
            <pre><ccid_code>private int Read_Normal(JPanel panel){
            String Field;
            try{
            CertificateFactory certificate_factory=CertificateFactory.getInstance("X.509");
            FileInputStream file_inputstream=new FileInputStream(CA_Name);
            X509Certificate
            x509certificate=(X509Certificate)certificate_factory.generateCertificate
            (file_inputstream);
            Field=x509certificate.getType();
            CA_ItemData[0][0]="类型";
            CA_ItemData[0][1]=Field;
            Field=Integer.toString(x509certificate.getVersion());
            CA_ItemData[1][0]="版本";
            CA_ItemData[1][1]=Field;
            Field=x509certificate.getSubjectDN().getName();
            CA_ItemData[2][0]="标题";
            CA_ItemData[2][1]=Field;
            /* 以下类似，这里省略
            Field=x509certificate.getNotBefore().toString();得到开始有效日期
            Field=x509certificate. getNotAfter().toString();得到截止日期
            Field=x509certificate.getSerialNumber().toString(16);得到序列号
            Field=x509certificate.getIssuerDN().getName();得到发行者名
            Field=x509certificate.getSigAlgName();得到签名算法
            Field=x509certificate.getPublicKey().getAlgorithm();得到公钥算法 */
            file_inputstream.close();
            final JTable table = new JTable(CA_ItemData, columnNames);
            TableColumn tc=null;
            tc = table.getColumnModel().getColumn(1);
            tc.setPreferredWidth(600);
            panel.add(table);
            }catch(Exception exception){
            exception.printStackTrace();
            return -1;
            }
            return 0;
            }</ccid_code></pre>
            </td>
        </tr>
    </tbody>
</table>
</ccid_nobr><br />
<br />
如果以字符串形式读取证书，加入下面Read_Bin这个函数。其中CertificateFactory.generateCertificate() 这个函数可以从证书标准编码(RFC1421定义)中解出可读信息。Read_Bin函数代码如下： <br />
<br />
<ccid_nobr>
<table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="550" align="center" bordercolorlight="black" border="1">
    <tbody>
        <tr>
            <td class="code" bgcolor="#e6e6e6">
            <pre><ccid_code>private int Read_Bin(JPanel panel){
            try{
            FileInputStream file_inputstream=new FileInputStream(CA_Name);
            DataInputStream data_inputstream=new DataInputStream(file_inputstream);
            CertificateFactory certificatefactory=CertificateFactory.getInstance("X.509");
            byte[] bytes=new byte[data_inputstream.available()];
            data_inputstream.readFully(bytes);
            ByteArrayInputStream bais=new ByteArrayInputStream(bytes);
            JEditorPane Cert_EditorPane;
            Cert_EditorPane=new JEditorPane();
            while(bais.available()&gt;0){
            X509Certificate
            Cert=(X509Certificate)certificatefactory.generateCertificate(bais);
            Cert_EditorPane.setText(Cert_EditorPane.getText()+Cert.toString());
            }
            Cert_EditorPane.disable();
            JScrollPane edit_scroll=new JScrollPane(Cert_EditorPane);
            panel.add(edit_scroll);
            file_inputstream.close();
            data_inputstream.close();
            }catch( Exception exception){
            exception.printStackTrace();
            return -1;
            }
            return 0;
            }</ccid_code></pre>
            </td>
        </tr>
    </tbody>
</table>
</ccid_nobr><br />
<br />
如果要得到原始证书编码后的信息，则可用如下代码： <br />
<br />
<ccid_nobr>
<table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="550" align="center" bordercolorlight="black" border="1">
    <tbody>
        <tr>
            <td class="code" bgcolor="#e6e6e6">
            <pre><ccid_code>private int Read_Raw(JPanel panel){
            try{
            JEditorPane Cert_EditorPane=new JEditorPane();
            String CertText=null;
            File inputFile = new File(CA_Name);
            FileReader in = new FileReader(inputFile);
            char[] buf=new char[2000];
            int len=in.read(buf,0,2000);
            for(int i=1;i&lt;len;i++)
            {
            CertText=CertText+buf[i];
            }
            in.close();
            Cert_EditorPane.setText(CertText);
            Cert_EditorPane.disable();
            JScrollPane edit_scroll=new JScrollPane(Cert_EditorPane);
            panel.add(edit_scroll);
            }catch( Exception exception){
            exception.printStackTrace();
            return -1;
            }
            return 0;
            }</ccid_code></pre>
            </td>
        </tr>
    </tbody>
</table>
</ccid_nobr><br />
<br />
最后用这个小程序看一看刚才生成的证书mycert.crt内容，把文件名写入main()中： <br />
<br />
<ccid_nobr>
<table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="550" align="center" bordercolorlight="black" border="1">
    <tbody>
        <tr>
            <td class="code" bgcolor="#e6e6e6">
            <pre><ccid_code>public static void main(String[] args) {
            JFrame frame = new JFrame("证书阅读器");
            frame.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {System.exit(0);}
            });
            frame.getContentPane().add(new CARead("mycert.crt"),BorderLayout.CENTER);
            frame.setSize(700, 425);
            frame.setVisible(true);
            }</ccid_code></pre>
            </td>
        </tr>
    </tbody>
</table>
</ccid_nobr><br />
<br />
证书mycert.crt的内容显示如图2所示，所有信息和Base64的显示内容，这里不再列举。 <br />
<br />
</p>
<center><img src="http://www.it918.com/Files/NewsUpfiles/20040414C1527282.gif"  alt="" /></center>
<p><br />
<br />
&nbsp;</p>
<center>图2 证书mycert.crt的内容显示</center>
<div align="left"><font size="3"></font>&nbsp;</div>
<div align="left">现在已经读取了证书的一些内容，那么怎样使用证书呢？我们可以假设A和B要共享一个绝密的文件F，B信任并拥有A的证书，也就是说B拥有A的公钥。那么A通过A和B共知的加密算法(对称密钥算法，比如DES算法)先加密文件F，然后对加密后的F进行签名和散列摘要(比如MD5算法，目的是保证文件的完整性)，然后把F发送到B。B收到文件后，先用A的证书中的公钥验证签名，然后再用通过共知的加密算法解密，就可以得到原文件了。这里使用的数字签名，可以保证B得到的文件，就是A的，A不能否认其不拥有文件F，因为只有A拥有可以让A的公钥验证其签名的私钥，同时这里使用DES算法加密，使得文件有保密性。 <br />
<br />
使用DES算法的加密解密函数类似，这里不对加密算法做进一步讨论，详细请看J2SDK的JSE部分内容，加密签名、解密验证文件结构见图3。 <br />
<br />
<center><img src="http://www.it918.com/Files/NewsUpfiles/20040414C1527283.gif"  alt="" /></center><br />
<br />
<center>图3 加密签名、解密验证文件结构图</center><br />
<br />
加密函数中的desKeyData存放DES加密密钥，如果要在程序中指定，可以设置为： <br />
<br />
<ccid_nobr>
<table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="550" align="center" bordercolorlight="black" border="1">
    <tbody>
        <tr>
            <td class="code" bgcolor="#e6e6e6">
            <pre><ccid_code>static byte[] desKeyData = { (byte)0x01, (byte)0x02, (byte)0x03, (byte)0x04,
            (byte)0x05, (byte)0x06, (byte)0x07, (byte)0x08 };</ccid_code></pre>
            </td>
        </tr>
    </tbody>
</table>
</ccid_nobr><br />
<br />
加密函数写成： <br />
<br />
<ccid_nobr>
<table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="550" align="center" bordercolorlight="black" border="1">
    <tbody>
        <tr>
            <td class="code" bgcolor="#e6e6e6">
            <pre><ccid_code>public static void crypt(byte[] cipherText,String outFileName){
            try{
            DESKeySpec desKeySpec = new DESKeySpec(desKeyData);
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
            SecretKey secretKey = keyFactory.generateSecret(desKeySpec);
            Cipher cdes = Cipher.getInstance("DES");
            cdes.init(Cipher.ENCRYPT_MODE, secretKey);
            byte[] ct = cdes.doFinal(cipherText);
            try{
            FileOutputStream out=new FileOutputStream(outFileName);
            out.write(ct);
            out.close();
            }catch(IOException e){
            e.printStackTrace();
            }
            }catch (Exception e){
            e.printStackTrace();
            }
            }</ccid_code></pre>
            </td>
        </tr>
    </tbody>
</table>
</ccid_nobr><br />
<br />
其中ct就是加密后的内容,outFileName保存加密后文件的文件名。把cdes.init(Cipher.ENCRYPT_MODE, secretKey)换成cdes.init(Cipher.DECRYPT_MODE, secretKey)就是解密文件了。 <br />
<br />
文件加密后就要对文件签名，保证A发送到B的文件不可伪造。下面是用存放在.keystore中的私钥进行签名的函数，签名使用的摘要算法是MD5。其中sigText是被签名内容的输入数组，outFileName是保存签名后输出文件的名称，KeyPassword是读取Keystore使用的密码，KeyStorePath是存放.keystore文件的路径，函数代码如下： <br />
<br />
<ccid_nobr>
<table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="550" align="center" bordercolorlight="black" border="1">
    <tbody>
        <tr>
            <td class="code" bgcolor="#e6e6e6">
            <pre><ccid_code>public static void sig(byte[] sigText, String outFileName,String
            KeyPassword,String KeyStorePath){
            char[] kpass;
            int i;
            try{
            KeyStore ks = KeyStore.getInstance("JKS");
            FileInputStream ksfis = new FileInputStream(KeyStorePath);
            BufferedInputStream ksbufin = new BufferedInputStream(ksfis);
            kpass=new char[KeyPassword.length()];
            for(i=0;i&lt;KeyPassword.length();i++)
            kpass[i]=KeyPassword.charAt(i);
            ks.load(ksbufin, kpass);
            PrivateKey priv = (PrivateKey) ks.getKey(KeystoreAlias,kpass );
            Signature rsa=Signature.getInstance("MD5withRSA");
            rsa.initSign(priv);
            rsa.update(sigText);
            byte[] sig=rsa.sign();
            System.out.println("sig is done");
            try{
            FileOutputStream out=new FileOutputStream(outFileName);
            out.write(sig);
            out.close();
            }catch(IOException e){
            e.printStackTrace();
            }
            }catch(Exception e){
            e.printStackTrace();
            }
            }</ccid_code></pre>
            </td>
        </tr>
    </tbody>
</table>
</ccid_nobr><br />
<br />
验证签名需要存放签名文件和被签名的文件以及证书，其中，updateData存放被签名文件的内容，sigedText存放得到的签名内容，CertName是证书名。验证签名代码如下： <br />
<br />
<ccid_nobr>
<table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="550" align="center" bordercolorlight="black" border="1">
    <tbody>
        <tr>
            <td class="code" bgcolor="#e6e6e6">
            <pre><ccid_code>public static void veriSig(byte[] updateData, byte[] sigedText){
            try{
            CertificateFactory
            certificatefactory=CertificateFactory.getInstance("X.509");
            FileInputStream fin=new FileInputStream(CertName);
            X509Certificate
            certificate=(X509Certificate)certificatefactory.generateCertificate(fin);
            PublicKey pub = certificate.getPublicKey();
            Signature rsa=Signature.getInstance("MD5withRSA");
            rsa.initVerify(pub);
            rsa.update(updateData);
            boolean verifies=rsa.verify(sigedText);
            System.out.println("verified "+verifies);
            if(verifies){
            System.out.println("Verify is done!");
            }else{
            System.out.println("verify is not successful");
            }
            }catch(Exception e){
            e.printStackTrace();
            }
            }</ccid_code></pre>
            </td>
        </tr>
    </tbody>
</table>
</ccid_nobr><br />
<br />
可以用keytool产生两个自签的签名证书，或者到某个CA去申请两个证书。用Java编写加密和验证程序，上述例子只是一个非常简单的证书应用，实际协议对证书的使用(比如SSL)要比这个复杂多了。 </div>
<img src ="http://www.blogjava.net/yglwxl/aggbug/271556.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yglwxl/" target="_blank">九宝</a> 2009-05-19 16:30 <a href="http://www.blogjava.net/yglwxl/archive/2009/05/19/271556.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java加密和数字签名编程快速入门（转）</title><link>http://www.blogjava.net/yglwxl/archive/2009/05/19/271555.html</link><dc:creator>九宝</dc:creator><author>九宝</author><pubDate>Tue, 19 May 2009 08:21:00 GMT</pubDate><guid>http://www.blogjava.net/yglwxl/archive/2009/05/19/271555.html</guid><wfw:comment>http://www.blogjava.net/yglwxl/comments/271555.html</wfw:comment><comments>http://www.blogjava.net/yglwxl/archive/2009/05/19/271555.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yglwxl/comments/commentRss/271555.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yglwxl/services/trackbacks/271555.html</trackback:ping><description><![CDATA[<h1 id="artibodyTitle">Java加密和数字签名编程快速入门</h1>
<br />
本文主要谈一下密码学中的加密和数字签名，以及其在java中如何进行使用。对密码学有兴趣的伙伴，推荐看Bruce Schneier的著作：Applied Crypotography。在jdk1.5的发行版本中安全性方面有了很大的改进，也提供了对RSA算法的直接支持，现在我们从实例入手解决问题（本文仅是作为简单介绍）： <br />
<br />
　本文主要谈一下密码学中的加密和数字签名，以及其在java中如何进行使用。对密码学有兴趣的伙伴，推荐看Bruce Schneier的著作：Applied Crypotography。在jdk1.5的发行版本中安全性方面有了很大的改进，也提供了对RSA算法的直接支持，现在我们从实例入手解决问题（本文仅是作为简单介绍）： <br />
<br />
　　<strong>一、密码学上常用的概念</strong>　<br />
<br />
　　1）消息摘要：<br />
<br />
　　这是一种与消息认证码结合使用以确保消息完整性的技术。主要使用单向散列函数算法，可用于检验消息的完整性，和通过散列密码直接以文本形式保存等，目前广泛使用的算法有MD4、MD5、SHA-1，jdk1.5对上面都提供了支持，在java中进行消息摘要很简单， java.security.MessageDigest提供了一个简易的操作方法：<br />
<br />
<div class="highlighter">
<ol class="highlighter-j">
    <li><span class="comment">/**</span>
    <li class="alt"><span class="comment">*MessageDigestExample.java</span>
    <li><span class="comment">*Copyright&nbsp;2005-2-16</span>
    <li class="alt"><span class="comment">*/</span>
    <li><span class="keyword">import</span><span>&nbsp;java.security.MessageDigest;</span>
    <li class="alt"><span class="comment">/**</span>
    <li><span class="comment">*单一的消息摘要算法，不使用密码.可以用来对明文消息（如：密码）隐藏保存</span>
    <li class="alt"><span class="comment">*/</span>
    <li><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">class</span><span>&nbsp;MessageDigestExample{</span>
    <li class="alt"><span>　</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">static</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;main(String[]&nbsp;args)&nbsp;</span><span class="keyword">throws</span><span>&nbsp;Exception{</span>
    <li><span>　　</span><span class="keyword">if</span><span>(args.length!=</span><span class="number">1</span><span>){</span>
    <li class="alt"><span>　　　System.err.println(</span><span class="string">"Usage:java&nbsp;MessageDigestExample&nbsp;text"</span><span>);</span>
    <li><span>　　　System.exit(</span><span class="number">1</span><span>);</span>
    <li class="alt"><span>　　}</span>
    <li>
    <li class="alt"><span>　　</span><span class="keyword">byte</span><span>[]&nbsp;plainText=args[</span><span class="number">0</span><span>].getBytes(</span><span class="string">"UTF8"</span><span>);</span>
    <li>
    <li class="alt"><span>　　</span><span class="comment">//使用getInstance("算法")来获得消息摘要,这里使用SHA-1的160位算法</span>
    <li><span>　　MessageDigest&nbsp;messageDigest=MessageDigest.getInstance(</span><span class="string">"SHA-1"</span><span>);</span>
    <li class="alt">
    <li><span>　　System.out.println(</span><span class="string">"\n"</span><span>+messageDigest.getProvider().getInfo());</span>
    <li class="alt"><span>　　</span><span class="comment">//开始使用算法</span>
    <li><span>　　messageDigest.update(plainText);</span>
    <li class="alt"><span>　　System.out.println(</span><span class="string">"\nDigest:"</span><span>);</span>
    <li><span>　　</span><span class="comment">//输出算法运算结果</span>
    <li class="alt"><span>　　System.out.println(</span><span class="keyword">new</span><span>&nbsp;String(messageDigest.digest(),</span><span class="string">"UTF8"</span><span>));</span>
    <li><span>　}</span>
    <li class="alt"><span>}</span></li>
</ol>
</div>
还可以通过消息认证码来进行加密实现，javax.crypto.Mac提供了一个解决方案，有兴趣者可以参考相关API文档，本文只是简单介绍什么是摘要算法。<br />
<br />
　　2）私钥加密：<br />
<br />
　　消息摘要只能检查消息的完整性，但是单向的，对明文消息并不能加密，要加密明文的消息的话，就要使用其他的算法，要确保机密性，我们需要使用私钥密码术来交换私有消息。<br />
<br />
　　这种最好理解，使用对称算法。比如：A用一个密钥对一个文件加密，而B读取这个文件的话，则需要和A一样的密钥，双方共享一个私钥（而在web环境下，私钥在传递时容易被侦听）：<br />
<br />
　　使用私钥加密的话，首先需要一个密钥，可用javax.crypto.KeyGenerator产生一个密钥(java.security.Key),然后传递给一个加密工具(javax.crypto.Cipher),该工具再使用相应的算法来进行加密，主要对称算法有：DES（实际密钥只用到56位），AES（支持三种密钥长度：128、192、256位），通常首先128位，其他的还有DESede等，jdk1.5种也提供了对对称算法的支持，以下例子使用AES算法来加密：<br />
<br />
<div class="highlighter">
<ol class="highlighter-j">
    <li><span class="comment">/**</span>
    <li class="alt"><span class="comment">*PrivateExmaple.java</span>
    <li><span class="comment">*Copyright&nbsp;2005-2-16</span>
    <li class="alt"><span class="comment">*/</span>
    <li><span class="keyword">import</span><span>&nbsp;javax.crypto.Cipher;</span>
    <li class="alt"><span class="keyword">import</span><span>&nbsp;javax.crypto.KeyGenerator;</span>
    <li><span class="keyword">import</span><span>&nbsp;java.security.Key;</span>
    <li class="alt">
    <li><span class="comment">/**</span>
    <li class="alt">*私鈅加密，保证消息机密性
    <li>*/
    <li class="alt"><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">class</span><span>&nbsp;PrivateExample{</span>
    <li><span>　</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">static</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;main(String[]&nbsp;args)&nbsp;</span><span class="keyword">throws</span><span>&nbsp;Exception{</span>
    <li class="alt"><span>　　</span><span class="keyword">if</span><span>(args.length!=</span><span class="number">1</span><span>){</span>
    <li><span>　　　System.err.println(</span><span class="string">"Usage:java&nbsp;PrivateExample&nbsp;&lt;text&gt;"</span><span>);</span>
    <li class="alt"><span>　　　System.exit(</span><span class="number">1</span><span>);</span>
    <li><span>　　}</span>
    <li class="alt"><span>　　</span><span class="keyword">byte</span><span>[]&nbsp;plainText=args[</span><span class="number">0</span><span>].getBytes(</span><span class="string">"UTF8"</span><span>);</span>
    <li>
    <li class="alt"><span>　　</span><span class="comment">//通过KeyGenerator形成一个key</span>
    <li><span>　　System.out.println(</span><span class="string">"\nStart&nbsp;generate&nbsp;AES&nbsp;key"</span><span>);</span>
    <li class="alt"><span>　　KeyGenerator&nbsp;keyGen=KeyGenerator.getInstance(</span><span class="string">"AES"</span><span>);</span>
    <li><span>　　keyGen.init(</span><span class="number">128</span><span>);</span>
    <li class="alt"><span>　　Key&nbsp;key=keyGen.generateKey();</span>
    <li><span>　　System.out.println(</span><span class="string">"Finish&nbsp;generating&nbsp;DES&nbsp;key"</span><span>);</span>
    <li class="alt">
    <li><span>　　</span><span class="comment">//获得一个私鈅加密类Cipher，ECB是加密方式，PKCS5Padding是填充方法</span>
    <li class="alt"><span>　　Cipher&nbsp;cipher=Cipher.getInstance(</span><span class="string">"AES/ECB/PKCS5Padding"</span><span>);</span>
    <li><span>　　System.out.println(</span><span class="string">"\n"</span><span>+cipher.getProvider().getInfo());</span>
    <li class="alt">
    <li><span>　　</span><span class="comment">//使用私鈅加密</span>
    <li class="alt"><span>　　System.out.println(</span><span class="string">"\nStart&nbsp;encryption:"</span><span>);</span>
    <li><span>　　cipher.init(Cipher.ENCRYPT_MODE,key);</span>
    <li class="alt"><span>　　</span><span class="keyword">byte</span><span>[]&nbsp;cipherText=cipher.doFinal(plainText);</span>
    <li><span>　　System.out.println(</span><span class="string">"Finish&nbsp;encryption:"</span><span>);</span>
    <li class="alt"><span>　　System.out.println(</span><span class="keyword">new</span><span>&nbsp;String(cipherText,</span><span class="string">"UTF8"</span><span>));</span>
    <li>
    <li class="alt"><span>　　System.out.println(</span><span class="string">"\nStart&nbsp;decryption:"</span><span>);</span>
    <li><span>　　cipher.init(Cipher.DECRYPT_MODE,key);</span>
    <li class="alt"><span>　　</span><span class="keyword">byte</span><span>[]&nbsp;newPlainText=cipher.doFinal(cipherText);</span>
    <li><span>　　System.out.println(</span><span class="string">"Finish&nbsp;decryption:"</span><span>);</span>
    <li class="alt">
    <li><span>　　System.out.println(</span><span class="keyword">new</span><span>&nbsp;String(newPlainText,</span><span class="string">"UTF8"</span><span>));</span>
    <li class="alt">
    <li><span>　}</span>
    <li class="alt"><span>}</span></li>
</ol>
</div>
<br />
3）公钥加密：<br />
<br />
　　上面提到，私钥加密需要一个共享的密钥，那么如何传递密钥呢？web环境下，直接传递的话很容易被侦听到，幸好有了公钥加密的出现。公钥加密也叫不对称加密，不对称算法使用一对密钥对，一个公钥，一个私钥，使用公钥加密的数据，只有私钥能解开（可用于加密）；同时，使用私钥加密的数据，只有公钥能解开（签名）。但是速度很慢（比私钥加密慢100到1000倍），公钥的主要算法有RSA，还包括Blowfish,Diffie-Helman等，jdk1.5种提供了对RSA的支持，是一个改进的地方：<br />
<div class="highlighter">
<ol class="highlighter-j">
    <li><span class="comment">/**</span>
    <li class="alt"><span class="comment">*PublicExample.java</span>
    <li><span class="comment">*Copyright&nbsp;2005-2-16</span>
    <li class="alt"><span class="comment">*/</span>
    <li><span class="keyword">import</span><span>&nbsp;java.security.Key;</span>
    <li class="alt"><span class="keyword">import</span><span>&nbsp;javax.crypto.Cipher;</span>
    <li><span class="keyword">import</span><span>&nbsp;java.security.KeyPairGenerator;</span>
    <li class="alt"><span class="keyword">import</span><span>&nbsp;java.security.KeyPair;</span>
    <li><span class="comment">/**</span>
    <li class="alt"><span class="comment">*一个简单的公鈅加密例子,Cipher类使用KeyPairGenerator生成的公鈅和私鈅</span>
    <li><span class="comment">*/</span>
    <li class="alt"><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">class</span><span>&nbsp;PublicExample{</span>
    <li><span>　</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">static</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;main(String[]&nbsp;args)&nbsp;</span><span class="keyword">throws</span><span>&nbsp;Exception{</span>
    <li class="alt"><span>　　</span><span class="keyword">if</span><span>(args.length!=</span><span class="number">1</span><span>){</span>
    <li><span>　　　System.err.println(</span><span class="string">"Usage:java&nbsp;PublicExample&nbsp;&lt;text&gt;"</span><span>);</span>
    <li class="alt"><span>　　　System.exit(</span><span class="number">1</span><span>);</span>
    <li><span>　　}</span>
    <li class="alt">
    <li><span>　　</span><span class="keyword">byte</span><span>[]&nbsp;plainText=args[</span><span class="number">0</span><span>].getBytes(</span><span class="string">"UTF8"</span><span>);</span>
    <li class="alt"><span>　　</span><span class="comment">//构成一个RSA密钥</span>
    <li><span>　　System.out.println(</span><span class="string">"\nStart&nbsp;generating&nbsp;RSA&nbsp;key"</span><span>);</span>
    <li class="alt"><span>　　KeyPairGenerator&nbsp;keyGen=KeyPairGenerator.getInstance(</span><span class="string">"RSA"</span><span>);</span>
    <li><span>　　keyGen.initialize(</span><span class="number">1024</span><span>);</span>
    <li class="alt"><span>　　KeyPair&nbsp;key=keyGen.generateKeyPair();</span>
    <li><span>　　System.out.println(</span><span class="string">"Finish&nbsp;generating&nbsp;RSA&nbsp;key"</span><span>);</span>
    <li class="alt">
    <li><span>　　</span><span class="comment">//获得一个RSA的Cipher类，使用公鈅加密</span>
    <li class="alt"><span>　　Cipher&nbsp;cipher=Cipher.getInstance(</span><span class="string">"RSA/ECB/PKCS1Padding"</span><span>);</span>
    <li><span>　　System.out.println(</span><span class="string">"\n"</span><span>+cipher.getProvider().getInfo());</span>
    <li class="alt">
    <li><span>　　System.out.println(</span><span class="string">"\nStart&nbsp;encryption"</span><span>);</span>
    <li class="alt"><span>　　cipher.init(Cipher.ENCRYPT_MODE,key.getPublic());</span>
    <li><span>　　</span><span class="keyword">byte</span><span>[]&nbsp;cipherText=cipher.doFinal(plainText);</span>
    <li class="alt"><span>　　System.out.println(</span><span class="string">"Finish&nbsp;encryption:"</span><span>);</span>
    <li><span>　　System.out.println(</span><span class="keyword">new</span><span>&nbsp;String(cipherText,</span><span class="string">"UTF8"</span><span>));</span>
    <li class="alt">
    <li><span>　　</span><span class="comment">//使用私鈅解密</span>
    <li class="alt"><span>　　System.out.println(</span><span class="string">"\nStart&nbsp;decryption"</span><span>);</span>
    <li><span>　　cipher.init(Cipher.DECRYPT_MODE,key.getPrivate());</span>
    <li class="alt"><span>　　</span><span class="keyword">byte</span><span>[]&nbsp;newPlainText=cipher.doFinal(cipherText);</span>
    <li><span>　　System.out.println(</span><span class="string">"Finish&nbsp;decryption:"</span><span>);</span>
    <li class="alt"><span>　　System.out.println(</span><span class="keyword">new</span><span>&nbsp;String(newPlainText,</span><span class="string">"UTF8"</span><span>));</span>
    <li><span>　}</span>
    <li class="alt"><span>}</span></li>
</ol>
</div>
<br />
<br />
4）数字签名：<br />
<br />
　　数字签名，它是确定交换消息的通信方身份的第一个级别。上面A通过使用公钥加密数据后发给B，B利用私钥解密就得到了需要的数据，问题来了，由于都是使用公钥加密，那么如何检验是A发过来的消息呢？上面也提到了一点，私钥是唯一的，那么A就可以利用A自己的私钥进行加密，然后B再利用A的公钥来解密，就可以了；数字签名的原理就基于此，而通常为了证明发送数据的真实性，通过利用消息摘要获得简短的消息内容，然后再利用私钥进行加密散列数据和消息一起发送。java中为数字签名提供了良好的支持，java.security.Signature类提供了消息签名：<br />
<br />
<div class="highlighter">
<ol class="highlighter-j">
    <li><span class="comment">/**</span>
    <li class="alt"><span class="comment">*DigitalSignature2Example.java</span>
    <li><span class="comment">*Copyright&nbsp;2005-2-16</span>
    <li class="alt"><span class="comment">*/</span>
    <li><span class="keyword">import</span><span>&nbsp;java.security.Signature;</span>
    <li class="alt"><span class="keyword">import</span><span>&nbsp;java.security.KeyPairGenerator;</span>
    <li><span class="keyword">import</span><span>&nbsp;java.security.KeyPair;</span>
    <li class="alt"><span class="keyword">import</span><span>&nbsp;java.security.SignatureException;</span>
    <li>
    <li class="alt"><span class="comment">/**</span>
    <li><span class="comment">*数字签名，使用RSA私钥对对消息摘要签名，然后使用公鈅验证&nbsp;测试</span>
    <li class="alt"><span class="comment">*/</span>
    <li><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">class</span><span>&nbsp;DigitalSignature2Example{</span>
    <li class="alt"><span>　</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">static</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;main(String[]&nbsp;args)&nbsp;</span><span class="keyword">throws</span><span>&nbsp;Exception{</span>
    <li><span>　　</span><span class="keyword">if</span><span>(args.length!=</span><span class="number">1</span><span>){</span>
    <li class="alt"><span>　　　System.err.println(</span><span class="string">"Usage:java&nbsp;DigitalSignature2Example&nbsp;&lt;text&gt;"</span><span>);</span>
    <li><span>　　　System.exit(</span><span class="number">1</span><span>);</span>
    <li class="alt"><span>　　}</span>
    <li>
    <li class="alt"><span>　　</span><span class="keyword">byte</span><span>[]&nbsp;plainText=args[</span><span class="number">0</span><span>].getBytes(</span><span class="string">"UTF8"</span><span>);</span>
    <li><span>　　</span><span class="comment">//形成RSA公钥对</span>
    <li class="alt"><span>　　System.out.println(</span><span class="string">"\nStart&nbsp;generating&nbsp;RSA&nbsp;key"</span><span>);</span>
    <li><span>　　KeyPairGenerator&nbsp;keyGen=KeyPairGenerator.getInstance(</span><span class="string">"RSA"</span><span>);</span>
    <li class="alt"><span>　　keyGen.initialize(</span><span class="number">1024</span><span>);</span>
    <li>
    <li class="alt"><span>　　KeyPair&nbsp;key=keyGen.generateKeyPair();</span>
    <li><span>　　System.out.println(</span><span class="string">"Finish&nbsp;generating&nbsp;RSA&nbsp;key"</span><span>);</span>
    <li class="alt"><span>　　</span><span class="comment">//使用私鈅签名</span>
    <li><span>　　Signature&nbsp;sig=Signature.getInstance(</span><span class="string">"SHA1WithRSA"</span><span>);</span>
    <li class="alt"><span>　　sig.initSign(key.getPrivate());</span>
    <li><span>　　sig.update(plainText);</span>
    <li class="alt"><span>　　</span><span class="keyword">byte</span><span>[]&nbsp;signature=sig.sign();</span>
    <li><span>　　System.out.println(sig.getProvider().getInfo());</span>
    <li class="alt"><span>　　System.out.println(</span><span class="string">"\nSignature:"</span><span>);</span>
    <li><span>　　System.out.println(</span><span class="keyword">new</span><span>&nbsp;String(signature,</span><span class="string">"UTF8"</span><span>));</span>
    <li class="alt">
    <li><span>　　</span><span class="comment">//使用公鈅验证</span>
    <li class="alt"><span>　　System.out.println(</span><span class="string">"\nStart&nbsp;signature&nbsp;verification"</span><span>);</span>
    <li><span>　　sig.initVerify(key.getPublic());</span>
    <li class="alt"><span>　　sig.update(plainText);</span>
    <li><span>　　</span><span class="keyword">try</span><span>{</span>
    <li class="alt"><span>　　　</span><span class="keyword">if</span><span>(sig.verify(signature)){</span>
    <li><span>　　　　System.out.println(</span><span class="string">"Signature&nbsp;verified"</span><span>);</span>
    <li class="alt"><span>　　　}</span><span class="keyword">else</span><span>&nbsp;System.out.println(</span><span class="string">"Signature&nbsp;failed"</span><span>);</span>
    <li><span>　　　}</span><span class="keyword">catch</span><span>(SignatureException&nbsp;e){</span>
    <li class="alt"><span>　　　　System.out.println(</span><span class="string">"Signature&nbsp;failed"</span><span>);</span>
    <li><span>　　　}</span>
    <li class="alt"><span>　　}</span>
    <li><span>}</span></li>
</ol>
</div>
　5)数字证书。<br />
<br />
　　还有个问题，就是公钥问题，A用私钥加密了，那么B接受到消息后，用A提供的公钥解密；那么现在有个讨厌的C，他把消息拦截了，然后用自己的私钥加密，同时把自己的公钥发给B，并告诉B，那是A的公钥，结果....，这时候就需要一个中间机构出来说话了（相信权威，我是正确的），就出现了Certificate Authority(也即CA），有名的CA机构有Verisign等，目前数字认证的工业标准是：CCITT的X.509：<br />
数字证书：它将一个身份标识连同公钥一起进行封装，并由称为认证中心或 CA 的第三方进行数字签名。<br />
<br />
　　密钥库：java平台为你提供了密钥库，用作密钥和证书的资源库。从物理上讲，密钥库是缺省名称为 .keystore 的文件（有一个选项使它成为加密文件）。密钥和证书可以拥有名称（称为别名），每个别名都由唯一的密码保护。密钥库本身也受密码保护；您可以选择让每个别名密码与主密钥库密码匹配。 <br />
<br />
　　使用工具keytool，我们来做一件自我认证的事情吧（相信我的认证）：<br />
<br />
　　1、创建密钥库keytool -genkey -v -alias feiUserKey -keyalg RSA 默认在自己的home目录下（windows系统是c:\documents and settings\&lt;你的用户名&gt; 目录下的.keystore文件），创建我们用 RSA 算法生成别名为 feiUserKey 的自签名的证书,如果使用了-keystore mm 就在当前目录下创建一个密钥库mm文件来保存密钥和证书。<br />
<br />
　　2、查看证书：keytool -list 列举了密钥库的所有的证书 <br />
<br />
　　也可以在dos下输入keytool -help查看帮助。<br />
<strong><br />
<br />
二、JAR的签名</strong><br />
<br />
　　我们已经学会了怎样创建自己的证书了，现在可以开始了解怎样对JAR文件签名，JAR文件在Java中相当于 ZIP 文件，允许将多个 Java 类文件打包到一个具有 .jar 扩展名的文件中，然后可以对这个jar文件进行数字签名，以证实其来源和真实性。该 JAR 文件的接收方可以根据发送方的签名决定是否信任该代码，并可以确信该内容在接收之前没有被篡改过。同时在部署中，可以通过在策略文件中放置访问控制语句根据签名者的身份分配对机器资源的访问权。这样，有些Applet的安全检验访问就得以进行。<br />
<br />
　　使用jarsigner工具可以对jar文件进行签名：<br />
<br />
　　现在假设我们有个Test.jar文件（可以使用jar命令行工具生成）：<br />
<br />
　　jarsigner Test.jar feiUserKey (这里我们上面创建了该别名的证书) ，详细信息可以输入jarsigner查看帮助<br />
<br />
　　验证其真实性：jarsigner -verify　Test.jar(注意，验证的是jar是否被修改了，但不检验减少的，如果增加了新的内容，也提示，但减少的不会提示。）<br />
<br />
　　使用Applet中：&lt;applet code="Test.class" archive="Test.jar" width="150" height="100"&gt;&lt;/applet&gt;然后浏览器就会提示你：准许这个会话-拒绝-始终准许-查看证书等。<br />
<br />
　　<strong>三、安全套接字层（SSL Secure Sockets Layer）和传输层安全性（TLS Transport Layer Security）</strong><br />
<br />
　　安全套接字层和传输层安全性是用于在客户机和服务器之间构建安全的通信通道的协议。它也用来为客户机认证服务器，以及（不太常用的）为服务器认证客户机。该协议在浏览器应用程序中比较常见，浏览器窗口底部的锁表明 SSL/TLS 有效：<br />
<br />
　　1）当使用 SSL/TLS（通常使用 https:// URL）向站点进行请求时，从服务器向客户机发送一个证书。客户机使用已安装的公共 CA 证书通过这个证书验证服务器的身份，然后检查 IP 名称（机器名）与客户机连接的机器是否匹配。<br />
<br />
　　2）客户机生成一些可以用来生成对话的私钥（称为会话密钥）的随机信息，然后用服务器的公钥对它加密并将它发送到服务器。服务器用自己的私钥解密消息，然后用该随机信息派生出和客户机一样的私有会话密钥。通常在这个阶段使用 RSA 公钥算法。<br />
<br />
　　3）客户机和服务器使用私有会话密钥和私钥算法（通常是 RC4）进行通信。使用另一个密钥的消息认证码来确保消息的完整性。<br />
<br />
　　java中javax.net.ssl.SSLServerSocketFactory类提供了一个很好的SSLServerSocker的工厂类，熟悉Socket编程的读者可以去练习。当编写完服务器端之后，在浏览器上输入https://主机名:端口 就会通过SSL/TLS进行通话了。注意：运行服务端的时候要带系统环境变量运行：javax.net.ssl.keyStore=密钥库(创建证书时，名字应该为主机名，比如localhost)和javax.net.ssl.keyStorePassword=你的密码
<div id="textpage1"><!-- Error --><br />
原文： http://www.yesky.com/253/1911753.shtml</div>
<img src ="http://www.blogjava.net/yglwxl/aggbug/271555.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yglwxl/" target="_blank">九宝</a> 2009-05-19 16:21 <a href="http://www.blogjava.net/yglwxl/archive/2009/05/19/271555.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Creating a JAR File(转)</title><link>http://www.blogjava.net/yglwxl/archive/2009/03/30/262843.html</link><dc:creator>九宝</dc:creator><author>九宝</author><pubDate>Mon, 30 Mar 2009 03:27:00 GMT</pubDate><guid>http://www.blogjava.net/yglwxl/archive/2009/03/30/262843.html</guid><wfw:comment>http://www.blogjava.net/yglwxl/comments/262843.html</wfw:comment><comments>http://www.blogjava.net/yglwxl/archive/2009/03/30/262843.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yglwxl/comments/commentRss/262843.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yglwxl/services/trackbacks/262843.html</trackback:ping><description><![CDATA[<p>&nbsp;Creating a JAR File</p>
<p>The basic format of the command for creating a JAR file is: </p>
<pre>jar cf <em>jar-file input-file(s)</em>
</pre>
<p>Let's look at the options and arguments used in this command: </p>
<ul>
    <li>The <code>c</code> option indicates that you want to <em>create</em> a JAR file.
    <li>The <code>f</code> option indicates that you want the output to go to a <em>file</em> rather than to stdout.
    <li><code>jar-file</code> is the name that you want the resulting JAR file to have. You can use any filename for a JAR file. By convention, JAR filenames are given a <code>.jar</code> extension, though this is not required.
    <li>The <code>input-file(s)</code> argument is a space-delimited list of one or more files that you want to be placed in your JAR file. The <code>input-file(s)</code> argument can contain the wildcard <code>*</code> symbol. If any of the "input-files" are directories, the contents of those directories are added to the JAR archive recursively. </li>
</ul>
<p>The <code>c</code> and <code>f</code> options can appear in either order, but there must not be any space between them.</p>
<p>This command will generate a compressed JAR file and place it in the current directory. The command will also generate a default <a href="http://java.sun.com/developer/Books/javaprogramming/JAR/basics/manifest.html">manifest file</a> for the JAR archive.</p>
<p>You can add any of these additional options to the <code>cf</code> options of the basic command: </p>
<table cellpadding="3" border="1">
    <tbody>
        <tr>
            <th>Option</th>
            <th>Description</th>
        </tr>
        <tr>
            <td align="center"><code>v</code></td>
            <td>Produces <em>verbose</em> output on stderr (in version 1.1) or stdout (in version 1.2) while the JAR file is being built. The verbose output tells you the name of each file as it's added to the JAR file.</font></td>
        </tr>
        <tr>
            <td align="center"><code>0</code> (zero)</font></td>
            <td>Indicates that you don't want the JAR file to be compressed.</td>
        </tr>
        <tr>
            <td align="center"><code>M</code></td>
            <td>Indicates that the default manifest file should not be produced.</td>
        </tr>
        <tr>
            <td align="center"><code>m</code></td>
            <td>Used to include manifest information from an existing manifest file. The format for using this option is:
            <pre>jar cmf existing-manifest jar-file input-file(s)
            </pre>
            See <a href="http://java.sun.com/developer/Books/javaprogramming/JAR/basics/mod.html">Modifying a Manifest</a> for more information about his option.</td>
        </tr>
        <tr>
            <td align="center"><code>-C</code></td>
            <td>To change directories during execution of the command. Version 1.2 only. See below for an example.</td>
        </tr>
    </tbody>
</table>
<p>In version 1.1, the JAR-file format supports only ASCII filenames. Version 1.2 adds support for UTF8-encoded names. </p>
<a name="example">
<h3>An Example</h3>
<p></a>Let's look at an example. The JDK demos include a simple <code>TicTacToe</code> applet. This demo contains a bytecode class file, audio files, and images all housed in a directory called <code>TicTacToe</code> having this structure: </p>
<img height="94" alt="" src="http://java.sun.com/developer/Books/javaprogramming/JAR/basics/jar1.gif" width="386" align="bottom" naturalsizeflag="3" />
<p>The <code>audio</code> and <code>images</code> subdirectories contain sound files and GIF images used by the applet.</p>
<p>To package this demo into a single JAR file named <code>TicTacToe.jar</code>, you would run this command from inside the <code>TicTacToe</code> directory: </p>
<pre>jar cvf TicTacToe.jar TicTacToe.class audio images
</pre>
<p>The <code>audio</code> and <code>images</code> arguments represent directories, so the Jar tool will recursively place them and their contents in the JAR file. The generated JAR file <code>TicTacToe.jar</code> will be placed in the current directory. Because the command used the <code>v</code> option for verbose output, you'd see something similar to this output when you run the command:</p>
<!-- BEGIN VCD7 CODE SAMPLE COMPONENT  -->
<table class="grey4" cellspacing="0" cellpadding="10" width="100%" border="0">
    <tbody>
        <tr>
            <td>
            <pre>adding: TicTacToe.class
            (in=3825) (out=2222) (deflated 41%)
            adding: audio/ (in=0) (out=0) (stored 0%)
            adding: audio/beep.au
            (in=4032) (out=3572) (deflated 11%)
            adding: audio/ding.au
            (in=2566) (out=2055) (deflated 19%)
            adding: audio/return.au
            (in=6558) (out=4401) (deflated 32%)
            adding: audio/yahoo1.au
            (in=7834) (out=6985) (deflated 10%)
            adding: audio/yahoo2.au
            (in=7463) (out=4607) (deflated 38%)
            adding: images/ (in=0) (out=0) (stored 0%)
            adding: images/cross.gif
            (in=157) (out=160) (deflated -1%)
            adding: images/not.gif
            (in=158) (out=161) (deflated -1%)
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<!-- END VCD7 CODE SAMPLE COMPONENT  -->
<p>You can see from this output that the JAR file <code>TicTacToe.jar</code> is compressed. The Jar tool compresses files by default. You can turn off the compression feature by using the <code>0</code> (zero) option, so that the command would look like:</p>
<pre>jar cvf0 TicTacToe.jar TicTacToe.class audio images
</pre>
<p>You might want to avoid compression, for example, to increase the speed with which a JAR file could be loaded by a browser. Uncompressed JAR files can generally be loaded more quickly than compressed files because the need to decompress the files during loading is eliminated. However, there's a tradeoff in that download time over a network may be longer for larger, uncompressed files.</p>
<p>The Jar tool will accept arguments that use the wildcard <code>*</code> symbol. As long as there weren't any unwanted files in the <code>TicTacToe</code> directory, you could have used this alternative command to construct the JAR file: </p>
<pre>jar cvf TicTacToe.jar *
</pre>
<p>Though the verbose output doesn't indicate it, the Jar tool automatically adds a manifest file to the JAR archive with pathname <code>META-INF/MANIFEST.MF</code>. See the <a href="http://java.sun.com/developer/Books/javaprogramming/JAR/basics/manifest.html">Understanding the Manifest</a> section for information about manifest files.</p>
<p>In the above example, the files in the archive retained their relative pathnames and directory structure. The Jar tool in version 1.2 of the Java Development Kit provides the <code>-C</code> option that you can use to create a JAR file in which the relative paths of the archived files are not preserved. It's modeled after GZIP's <code>-C</code> option.</p>
<p>As an example, suppose you wanted put audio files and gif images used by the TicTacToe demo into a JAR file, and that you wanted all the files to be on the top level, with no directory hierarchy. You could accomplish that by issuing this command from the parent directory of the <code>images</code> and <code>audio</code> directories: </p>
<pre>jar cf ImageAudio.jar -C images * -C audio *
</pre>
<p>The <code>-C&nbsp;images</code> part of this command directs the Jar tool to go to the <code>images</code> directory, and the <code>*</code> following <code>-C&nbsp;images</code> directs the Jar tool to archive all the contents of that directory. The <code>-C&nbsp;audio&nbsp;*</code> part of the command then does the same with the <code>audio</code> directory. The resulting JAR file would have this table of contents: </p>
<!-- BEGIN VCD7 CODE SAMPLE COMPONENT  -->
<table class="grey4" cellspacing="0" cellpadding="10" width="100%" border="0">
    <tbody>
        <tr>
            <td>
            <pre>META-INF/MANIFEST.MF
            cross.gif
            not.gif
            beep.au
            ding.au
            return.au
            yahoo1.au
            yahoo2.au
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<!-- END VCD7 CODE SAMPLE COMPONENT  -->
<p>By contrast, suppose that you used a command that didn't employ the <code>-C</code> option: </p>
<pre>jar cf ImageAudio.jar images audio
</pre>
<p>The resulting JAR file would have this table of contents: </p>
<!-- BEGIN VCD7 CODE SAMPLE COMPONENT  -->
<table class="grey4" cellspacing="0" cellpadding="10" width="100%" border="0">
    <tbody>
        <tr>
            <td>
            <pre>META-INF/MANIFEST.MF
            images/cross.gif
            images/not.gif
            audio/beep.au
            audio/ding.au
            audio/return.au
            audio/yahoo1.au
            audio/yahoo2.au
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<!-- END VCD7 CODE SAMPLE COMPONENT  --><!-- ================ --><!-- End Main Content --><!-- ================ --><!-- =================== --><!-- END OF MAIN CONTENT --><!-- =================== --><!--stopindex--><!-- END CENTRAL COLUMN COMPONENTS -->
<img src ="http://www.blogjava.net/yglwxl/aggbug/262843.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yglwxl/" target="_blank">九宝</a> 2009-03-30 11:27 <a href="http://www.blogjava.net/yglwxl/archive/2009/03/30/262843.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于java的JIT知识（转）</title><link>http://www.blogjava.net/yglwxl/archive/2009/01/13/251120.html</link><dc:creator>九宝</dc:creator><author>九宝</author><pubDate>Tue, 13 Jan 2009 06:18:00 GMT</pubDate><guid>http://www.blogjava.net/yglwxl/archive/2009/01/13/251120.html</guid><wfw:comment>http://www.blogjava.net/yglwxl/comments/251120.html</wfw:comment><comments>http://www.blogjava.net/yglwxl/archive/2009/01/13/251120.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yglwxl/comments/commentRss/251120.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yglwxl/services/trackbacks/251120.html</trackback:ping><description><![CDATA[<p>什么是<strong style="color: black; background-color: #a0ffff">JIT</strong>？</p>
<p><strong style="color: black; background-color: #a0ffff">JIT</strong>是just in time,即时编译技术。使用该技术，能够加速<strong style="color: black; background-color: #ffff66">java</strong>程序的执行速度。下面，就对该技术做个简单的讲解。</p>
<p>首先，我们大家都知道，通常javac将程序源代码编译，转换成<strong style="color: black; background-color: #ffff66">java</strong>字节码，JVM通过解释字节码将其翻译成对应的机器指令，逐条读入，逐条解释翻译。很显然，经过解释执行，其执行速度必然会比可执行的二进制字节码程序慢。为了提高执行速度，引入了<strong style="color: black; background-color: #a0ffff">JIT</strong>技术。</p>
<p>在运行时<strong style="color: black; background-color: #a0ffff">JIT</strong>会把翻译过的机器码保存起来，已备下次使用，因此从理论上来说，采用该<strong style="color: black; background-color: #a0ffff">JIT</strong>技术可以，可以接近以前纯编译技术。下面我看看，<strong style="color: black; background-color: #a0ffff">JIT</strong>的工作过程。</p>
<h3 class="sol"><strong style="color: black; background-color: #a0ffff">JIT</strong> 编译过程</h3>
<p>当<strong style="color: black; background-color: #a0ffff">JIT</strong>编译启用时（默认是启用的），JVM读入.class文件解释后，将其发给<strong style="color: black; background-color: #a0ffff">JIT</strong>编译器。<strong style="color: black; background-color: #a0ffff">JIT</strong>编译器将字节码编译成本机机器代码，下图展示了该过程。</p>
<p>什么是<strong style="color: black; background-color: #a0ffff">JIT</strong>？</p>
<p><strong style="color: black; background-color: #a0ffff">JIT</strong>是just in time,即时编译技术。使用该技术，能够加速<strong style="color: black; background-color: #ffff66">java</strong>程序的执行速度。下面，就对该技术做个简单的讲解。</p>
<p>首先，我们大家都知道，通常javac将程序源代码编译，转换成<strong style="color: black; background-color: #ffff66">java</strong>字节码，JVM通过解释字节码将其翻译成对应的机器指令，逐条读入，逐条解释翻译。很显然，经过解释执行，其执行速度必然会比可执行的二进制字节码程序慢。为了提高执行速度，引入了<strong style="color: black; background-color: #a0ffff">JIT</strong>技术。</p>
<p>在运行时<strong style="color: black; background-color: #a0ffff">JIT</strong>会把翻译过的机器码保存起来，已备下次使用，因此从理论上来说，采用该<strong style="color: black; background-color: #a0ffff">JIT</strong>技术可以，可以接近以前纯编译技术。下面我看看，<strong style="color: black; background-color: #a0ffff">JIT</strong>的工作过程。</p>
<h3 class="sol"><strong style="color: black; background-color: #a0ffff">JIT</strong> 编译过程</h3>
<p>当<strong style="color: black; background-color: #a0ffff">JIT</strong>编译启用时（默认是启用的），JVM读入.class文件解释后，将其发给<strong style="color: black; background-color: #a0ffff">JIT</strong>编译器。<strong style="color: black; background-color: #a0ffff">JIT</strong>编译器将字节码编译成本机机器代码，下图展示了该过程。</p>
<p><a name="ch1intro-fig-29"></a></p>
<p><br />
<img title="Graphic" height="537" alt="Graphic" src="http://docs.sun.com/source/806-3461/images/nancb4.eps.gif" width="330" _counted="undefined" /> </p>
<p>&nbsp;</p>
<p>通过上面的解释，我们了解了<strong style="color: black; background-color: #a0ffff">JIT</strong>的工作原理及过程，同样也发现了个问题，由于<strong style="color: black; background-color: #a0ffff">JIT</strong>对每条字节码都进行编译，造成了编译过程负担过重。为了避免这种情况，当前的<strong style="color: black; background-color: #a0ffff">JIT</strong>只对经常执行的字节码进行编译，如循环等。</p>
<p>需要说明的是，<strong style="color: black; background-color: #a0ffff">JIT</strong>并不总是奏效，不能期望<strong style="color: black; background-color: #a0ffff">JIT</strong>一定能够加速你代码执行的速度，更糟糕的是她有可能降低代码的执行速度。这取决于你的代码结构，当然很多情况下我们还是能够如愿以偿的。</p>
<img src ="http://www.blogjava.net/yglwxl/aggbug/251120.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yglwxl/" target="_blank">九宝</a> 2009-01-13 14:18 <a href="http://www.blogjava.net/yglwxl/archive/2009/01/13/251120.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java入门 解析配置文件的文件问题(转)</title><link>http://www.blogjava.net/yglwxl/archive/2008/04/28/196736.html</link><dc:creator>九宝</dc:creator><author>九宝</author><pubDate>Mon, 28 Apr 2008 05:21:00 GMT</pubDate><guid>http://www.blogjava.net/yglwxl/archive/2008/04/28/196736.html</guid><wfw:comment>http://www.blogjava.net/yglwxl/comments/196736.html</wfw:comment><comments>http://www.blogjava.net/yglwxl/archive/2008/04/28/196736.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yglwxl/comments/commentRss/196736.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yglwxl/services/trackbacks/196736.html</trackback:ping><description><![CDATA[我们在解析配置文件的时候,常常会为路径发愁,我就遇到过这样的情况<br />
　　
<center>　<img src="http://edu.yesky.com/imagelist/05/11/04i53wd4131d.jpg"  alt="" /></center><br />
　　如上图所示：<br />
　　<br />
　　ParseProperties.<a class="bluekey" href="http://dev.yesky.com/devjava/" target="_blank">java</a>是配置文件database.properties的解析类，那么我们怎样去取得它的路径并解析起配置呢？看解析类ParseProperties的源代码如下：<br />
　　<br />
　　package zy.pro.sc.db;<br />
　　<br />
　　import java.util.*;<br />
　　import java.io.*;<br />
　　<br />
　　public class ParseProperties {<br />
　　<br />
　　Properties properties = new Properties();<br />
　　<br />
　　public ParseProperties() {<br />
　　try{<br />
　　this.parseProp();<br />
　　}catch(Exception e){<br />
　　e.printStackTrace();<br />
　　}<br />
　　}<br />
　　<br />
　　public Properties parseProp()throws　IOException　{<br />
　　InputStream is=this.getClass().getResourceAsStream("database.properties");<br />
/*&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();<br />
InputStream in = classLoader.getSystemResourceAsStream(fileName);<br />
&nbsp;*/<br />
　　properties.load(is);<br />
　　is.close();<br />
　　return null;<br />
　　}<br />
　　public　String　getProperties(String　propStr){<br />
　　return properties.getProperty(propStr);<br />
　　}<br />
　　public static void main(String[] args) {<br />
　　ParseProperties　pp=new ParseProperties();<br />
　　String　driver=pp.getProperties("jdbc.driver");<br />
　　System.out.println(driver);<br />
　　}<br />
　　}<br />
　　看粗体部分，this.getClass()方法可以得到了当前类的Class对象，也可以用ParseProperties.class.getClass()方法来实现同样的效果。之后调用其getResourceAsStream("database.properties")方法来解析配置文件。getResourceAsStream（）方法解析文件时候的相对路径是当前类的包路径。<br />
　　<br />
　　就当前的包来说，zy.pro.sc.db对应的路径是src/zy/pro/sc/db。由于我们要解析的文件和解析类在同一目录下，所以我们的路径是"database.properties"。<br />
　　<br />
　　如果我们的解析文件和解析类不在同一目录下呢，如以下目录结构：<br />
　　
<center><img src="http://edu.yesky.com/imagelist/05/11/q9az3036u527.jpg"  alt="" /></center><br />
　　那么先看一下我们解析类的代码：<br />
　　<br />
　　InputStream is=this.getClass().getResourceAsStream("/database.properties");<br />
　　<br />
　　解析路径变成了"/database.properties",　&#8220;/&#8220;表示取当前类所在的包的根路径下的database.properties文件，也就是相对于ParsePropertie.class的包的根路径下的 database.properties文件。<br />
　　<br />
　　用这种方法更有灵活性。此地要认真体会。不用这种方法，你的解析类只能在目录结构不发生改变的情况下使用。否则将发生异常。例如：你的解析类在servlet中调用的时候就会抛出找不到文件的异常。<br />
　　<br />
　　此路径的定位方法也可以使用于解析XML的文件。详细情况同上。<br />
<img src ="http://www.blogjava.net/yglwxl/aggbug/196736.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yglwxl/" target="_blank">九宝</a> 2008-04-28 13:21 <a href="http://www.blogjava.net/yglwxl/archive/2008/04/28/196736.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JProfiler试用手记（转）</title><link>http://www.blogjava.net/yglwxl/archive/2008/04/22/194780.html</link><dc:creator>九宝</dc:creator><author>九宝</author><pubDate>Tue, 22 Apr 2008 07:19:00 GMT</pubDate><guid>http://www.blogjava.net/yglwxl/archive/2008/04/22/194780.html</guid><wfw:comment>http://www.blogjava.net/yglwxl/comments/194780.html</wfw:comment><comments>http://www.blogjava.net/yglwxl/archive/2008/04/22/194780.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/yglwxl/comments/commentRss/194780.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yglwxl/services/trackbacks/194780.html</trackback:ping><description><![CDATA[&nbsp;JProfiler是一款Java的性能监控工具。可以查看当前应用的<strong>对象、对象引用、内存、CPU使用情况、线程、线程运行情况（阻塞、等待等）</strong>，同时可以查找应用内存使用得热点，即：哪个对象占用的内存比较多；或者CPU热点，即：哪儿方法占用的较大得CPU资源。我使用的是4.3.2版本，以前试用过3**版本，不过那个bug比较多，容易死，4**版本稳定多了。
<p>&nbsp;&nbsp;&nbsp;&nbsp; 有了上面那些信息对于系统的调优会有很大帮助。这里提供有几篇文章供参考：<a href="http://www.blogjava.net/fine/archive/2007/05/07/115671.html">获取、介绍</a>，<a href="http://www.blogjava.net/ddpie/archive/2007/05/14/117450.html">简单入门</a>，<a href="http://www.javaeye.com/topic/70721">使用JProfiler解决实际问题</a>。这几篇文章基本介绍了常见东西了，下面说点心得。
<ol>
    <li>JProfiler监控是要消耗系统资源的，所以一般情况下不要用于性能测试时候的监控。 <br />
    <li>如果要用于相对大压力情况下，可以有选择的打开监控项，不用所有都打开。主要有两个，一个是内存监控，打开的情况下可以查找内存分配热点。一个是CPU监控，打开的情况下可以查看CPU使用热点。 <img src="http://lh5.google.com/image/pengjiaheng/RlQ6uwGdATI/AAAAAAAAAHM/HmnGe-vpZaQ/jp-1.JPG?imgmax=720"  alt="" /> <br />
    如图所示，<font color="#ff0000">红笔标注部分</font>。如果两个都关闭的话，还是可以跑一定压力的，同时还可以监控对象数量。<br />
    <li>个人认为最好用的（也是用的最多的）是查询当前的对象的数量。数量监控很重要，如果你使用了单例，那么你只会看到有一个对象存在，如果多了就说明程序有问题了。同样，如果应用进行一系列操作，检查一下该销毁的对象是否还继续存在，如果没有释放，就得考虑是否存在内存溢出了。 <br />
    <li>JProfiler还提供了一个比较好的检查内存溢出得工具。他可以查找某个对象的引用情况，即：当你发现某个该释放掉的对象没有释放，就可以看一下哪个实例在引用它，找到了根即找到了溢出点。<br />
    <strong>具体操作如下：</strong>在 &#8220;Memory Views&#8221;界面中右键选择你要监控的对象，选择第一项&#8220;Take Heap Snapshot for Selection&#8221;，选择完成后会进入&#8220;Heap Walker&#8221;界面，界面下面提供几个功能，选择&#8220;References&#8221;即可 。如图：<img src="http://lh6.google.com/image/pengjiaheng/RlQ8_AGdAUI/AAAAAAAAAHU/RVx00xLfzZM/jp-2.JPG?imgmax=720"  alt="" /><br />
    <br />
    <li>JProfiler提供不同的观察粒度，提供对类的监控、对包的监控、对J2EE组件的监控，同时过滤器也比较好用，直接定位你关注的包或类即可。<br />
    <li>JProfiler的监控可能与应用之间存在一定时间差，所以有些时候需要等待刷新，才能显示正确系统情况。</li>
</ol>
<img src ="http://www.blogjava.net/yglwxl/aggbug/194780.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yglwxl/" target="_blank">九宝</a> 2008-04-22 15:19 <a href="http://www.blogjava.net/yglwxl/archive/2008/04/22/194780.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>利用JProfiler对应用服务器内存泄漏问题诊断一例（转）</title><link>http://www.blogjava.net/yglwxl/archive/2008/04/22/194755.html</link><dc:creator>九宝</dc:creator><author>九宝</author><pubDate>Tue, 22 Apr 2008 05:24:00 GMT</pubDate><guid>http://www.blogjava.net/yglwxl/archive/2008/04/22/194755.html</guid><wfw:comment>http://www.blogjava.net/yglwxl/comments/194755.html</wfw:comment><comments>http://www.blogjava.net/yglwxl/archive/2008/04/22/194755.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yglwxl/comments/commentRss/194755.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yglwxl/services/trackbacks/194755.html</trackback:ping><description><![CDATA[<div class="blog_content">
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在中间件应用服务器的整体调优中，有关于等待队列、执行线程，EJB池以及数据库连接池和Statement Cache方面的调优，这些都属于系统参数方面的调优，本文主要从另外一个角度，也就是从应用的角度来解决中间件应用服务器的内存泄露问题，从这个角度来提高系统的稳定性和性能。 </p>
<p><span><span style="font-size: medium; color: #000000; font-family: Arial">项目背景</span></span> </p>
<p><span><strong><span style="font-size: small; color: #000000; font-family: Arial">问题描述</span></strong></span> </p>
<p>某个大型项目（Use Case用例超过300个），在项目上线后，其Web应用服务器经常宕机。表现为： </p>
<p>1. 应用服务器内存长期不合理占用，内存经常处于高位占用，很难回收到低位； </p>
<p>2. 应用服务器极为不稳定，几乎每两天重新启动一次，有时甚至每天重新启动一次； </p>
<p>3. 应用服务器经常做Full GC(Garbage Collection)，而且时间很长，大约需要30-40秒，应用服务器在做Full GC的时候是不响应客户的交易请求的，非常影响系统性能。 </p>
<p><span><strong><span style="font-size: small; color: #000000; font-family: Arial">Web应用服务器的物理部署</span></strong></span> </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一台Unix服务器（4CPU，8G Memory）来部署本Web应用程序；Web应用程序部署在中间件应用服务器上；部署了一个节点（Node），只配置一个应用服务器实例（Instance），没有做Cluster部署。 </p>
<p><span><strong><span style="font-size: small; color: #000000; font-family: Arial">Web应用服务器启动脚本中的内存参数</span></strong></span>
<table cellpadding="0" width="100%" border="1">
    <tbody>
        <tr>
            <td bgcolor="#f4f4f4">MEM_ARGS="-XX:MaxPermSize=128m -XX:MaxNewSize=512m -Xms3096m <br />
            -Xmx3096m -XX:+Printetails -Xloggc:./inwebapp1/gc.$$" </td>
        </tr>
    </tbody>
</table>
</p>
<p>可以看出目前生产系统中Web应用服务器的内存分配为3G Memory。 </p>
<p><span><strong><span style="font-size: small; color: #000000; font-family: Arial">Web应用服务器的重要部署参数</span></strong></span>
<table cellpadding="4" border="1">
    <tbody>
        <tr>
            <td>参数名称 </td>
            <td>参数值 </td>
            <td>参数解释 </td>
        </tr>
        <tr>
            <td>kernel.default(Thread Count) </td>
            <td>120 </td>
            <td>执行线程数目，是并发处理能力的重要参数 </td>
        </tr>
        <tr>
            <td>Session Timeout </td>
            <td>240分钟（4小时） </td>
            <td>HttpSession会话超时</td>
        </tr>
    </tbody>
</table>
</p>
<p>&nbsp;</p>
<p><span><span style="font-size: medium; color: #000000; font-family: Arial"><strong>分析</strong></span></span> </p>
<p><span><strong><span style="font-size: small; color: #000000; font-family: Arial">分析方法</span></strong></span> </p>
<p>内存长期占用并导致系统不稳定一般有两种可能： </p>
<p>1. 对象被大量创建而且被缓存，在旧的对象释放前又有大量新的对象被创建使得内存长期高位占用。 </p>
<ul>
    <li>表现为：内存不断被消耗、在高位时也很难回归到低位，有大量的对象在不断的创建，经过很长时间后又被回收。例如：在HttpSession中保存了大量的分页查询数据，而HttpSession的会话超时时间设置过长（例如：1天），那么在旧的对象释放前又有大量新的对象在第二天产生。
    <li>解决办法：对共享的对象可以采用池机制进行缓存，避免各自创建；缓存的临时对象应该及时释放；另一种办法是扩大系统的内存容量。</li>
</ul>
<p>2. 另一种情况就是内存泄漏问题 </p>
<ul>
    <li>表现为：内存回收低位点不断升高（以每次内存回收的最低点连成一条直线，那么它是一条上升线）；内存回收的频率也越来越高，内存占用也越来越高，最终出现"Out of Memory Exception"的系统异常。
    <li>解决办法：定位那些有内存泄漏的类或对象并修改完善这些类以避免内存泄漏。方法是：经过一段时间的测试、监控，如果某个类的对象数目屡创新高，即使在JVM Full GC后仍然数目降不下来，这些对象基本上是属于内存泄漏的对象了。</li>
</ul>
<p><span><strong><span style="font-size: small; color: #000000; font-family: Arial">问题定位</span></strong></span> </p>
<p>这里请看5月份 Web应用服务器的内存回收图形： </p>
<p>《注意：5月18日早上10点重新启动了Web服务器，5月20日早上又重新启动了Web服务器。》 </p>
<ul>
    <li>在Web应用重要部署参数中，我们知道：Session的超时时间为4个小时，我们在监控平台也观测到：在18日晚上10点左右所有的会话都过期了，从图形一中也能看出18日晚上确实系统的内存有回收到40%（就象股票的高位跳水）；
    <li>从图形一（5月18日）中我们也能看到Full GC回收后的内存占用率走势（红色曲线），上午基本平滑上升到20%（内存占用率），中午开始上升到30%，下午上升到40%
    <li>从图形二（5月19日）中我们也能看到Full GC回收后的内存占用率走势（红色曲线），上午又上升到了60%，到下午上升到了70%。
    <li>从黄色曲线（GC花费的时间，以秒为单位），Full GC的频率也在增快，时间耗费也越来越长，在图形一中基本高位在20秒左右，到19日基本都是30-40秒之间了。</li>
</ul>
<p>&nbsp;<strong><span style="color: #000000">图形一 5月18日</span></strong><br />
<img height="318" alt="图形一 5月18日" src="http://www-128.ibm.com/developerworks/cn/java/j-performance/images/image002.gif" width="554" border="0" _counted="undefined" /><br />
<br />
<strong><span style="color: #000000">图二</span></strong><br />
<img height="320" alt="图二" src="http://www-128.ibm.com/developerworks/cn/java/j-performance/images/image004.gif" width="554" border="0" _counted="undefined" /></p>
<p>通过上述分析，我们基本定位到了Web应用服务器的内存在高位长期占用的原因了：是内存泄露！并且正是由于这个原因导致系统不稳定、响应客户请求越来越慢的。 </p>
<p><span><strong><span style="font-size: small; color: #000000; font-family: Arial">解决方法</span></strong></span> </p>
<p>方法如下： </p>
<ul>
    <li>我们从图形二中发现，在8.95(将近9点钟)到9.66（将近9点40）期间有几次Full GC，但是有内存泄漏，从占用率40%上升到50%左右，泄漏了大约10%的内存，约300M；
    <li>我们在自己搭建的Web应用服务器平台（应用软件版本和生产版本一致）做这一阶段相同的查询交易；表明对同一个黑盒（Web应用）施加同样的刺激（相同的操作过程和查询交易）以期重现现象；
    <li>我们<span class="hilite2">使用</span><span class="hilite1">Jprofiler</span>工具对Web应用服务器的内存进行实时监控；
    <li>做完这些交易后，用户退出系统，并等待Web应用服务器的HttpSession超时（我们这里设置为15分钟）；
    <li>我们对Web应用服务器做了两次强制性的内存回收操作。</li>
</ul>
<p>发现如下： </p>
<p><br />
<strong><span style="color: #000000">图三</span></strong><br />
<img height="392" alt="图三" src="http://www-128.ibm.com/developerworks/cn/java/j-performance/images/image007.gif" width="554" border="0" _counted="undefined" /></p>
<p>如图三所示，内存经过HttpSession超时后，并强制gc后，仍然有大量的对象没有释放。例如：gov.gdlt.taxcore.comm.security.MenuNode，仍然有807个实例没有释放。 </p>
<p>我们继续追溯发现，这些MenuNode首先存放在一个ArrayList对象中，然后发现这个ArrayList对象又是存放在WHsessionAttrVO对象的Map中，WHsessionAttrVO 对象又是存放在ExternalSessionManager的staic Map中（名称为sessionMap），如图四所示。 </p>
<p><br />
<strong><span style="color: #000000">图四</span></strong><br />
<img height="260" alt="图四" src="http://www-128.ibm.com/developerworks/cn/java/j-performance/images/image009.gif" width="554" border="0" _counted="undefined" /></p>
<p>我们发现gov.gdlt.taxcore.taxevent.xtgl.comm.WHsessionAttrVO中保存了EJBSessionId信息(登录用户的唯一标志，由用户id+登录时间戳组成，每天都不同)和一个HashMap，这个HashMap中的内容有： </p>
<ul>
    <li>ArrayList: 内有MenuTreeNodes（菜单树节点）
    <li>HashMap: 内有操作人员代码信息
    <li>CurrentVersion:当前版本号
    <li>CurrentTime:当前系统时间</li>
</ul>
<p>WHsessionAttrVO这个对象的最终存放在ExternalSessionManager的static Map sessionMap中，由于ExternalSessionManager是一个全局的单实例，不会释放，所以它的成员变量sessionMap中的数据也不会释放，而Map中的Key值为EJBSessionId，每天登录的用户EJBSessionId都不同，就造成了每天的登录信息（包括菜单信息）都保存在sessionMap中不会被释放，最终造成了内存的泄漏。 </p>
<p><br />
<strong><span style="color: #000000">图五</span></strong><br />
<img height="151" alt="图五" src="http://www-128.ibm.com/developerworks/cn/java/j-performance/images/image011.jpg" width="502" border="0" _counted="undefined" /></p>
<p>如上图所示：WHsessionAttrsVO对象中除了有一个String对象（内容是EJBSessionId），还有一个HashMap对象。 </p>
<p><br />
<strong><span style="color: #000000">图六</span></strong><br />
<img height="264" alt="图六" src="http://www-128.ibm.com/developerworks/cn/java/j-performance/images/image013.gif" width="516" border="0" _counted="undefined" /></p>
<p>如上图所示，这个HashMap中的内容主要有menuTreeNodes为key，value为ArrayList的对象和以czrydminfo为key，value为HashMap对象的数据。 </p>
<p><br />
<strong><span style="color: #000000">图七</span></strong><br />
<img height="299" alt="图七" src="http://www-128.ibm.com/developerworks/cn/java/j-performance/images/image015.jpg" width="596" border="0" _counted="undefined" /></p>
<p>如上图所示：menuTreeNodes为key，value为ArrayList对象中包含的对象有许多的MenuNode对象，封装的都是用户的菜单节点。 </p>
<p><br />
<strong><span style="color: #000000">图八</span></strong><br />
<img height="116" alt="图八" src="http://www-128.ibm.com/developerworks/cn/java/j-performance/images/image017.jpg" width="384" border="0" _counted="undefined" /></p>
<p>如上图所示，最顶层（Root）的初始对象为一个ExternalSessionManager对象，其中的一个成员变量为static (静态的)，名称为：sessionMap，这个对象是singleton方式的，全局只有一个。 </p>
<p><span><strong><span style="font-size: small; color: #000000; font-family: Arial">初步估量</span></strong></span> </p>
<p>我们从图形一和图形二中可以看出，每天应用服务器损失大约40%的内存，大约1G左右。 </p>
<p>从图形四可以看出，当前用户（Id=24400001129）有807个菜单项（每个菜单项为一个MenuNode 对象实例，图形四中的这个实例的size为592 Byte），这些菜单数据和用户基本登录信息（czrydmInfo HashMap）也都存放在WHsessionAttrVO对象中，当前这个WHsessionAttrVO对象的size为457K。 </p>
<p>我们做如下估算： </p>
<p>假设平均每天有4千人（估计值，这个数值仅仅是5月19日峰值的1/2左右）登录系统（有重复登录的现象，例如：上午登录一次，中午退出系统，下午登录一次），以平均每人占用200K（估计值，是用户id=24400001129 的Size的1/2左右）来计算，一天泄漏的内存约800M，比较符合目前内存泄漏的情况。当然，这种估计仍然需要经过实践的检验，方法是：当这次发现的内存泄漏问题解决后看系统是否还有其它内存泄漏问题。 </p>
<p><br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td><img class="magplus" title="点击查看原始大小图片" height="0" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="700" _counted="undefined" /></td>
        </tr>
    </tbody>
</table>
<span><span style="font-size: medium; color: #000000; font-family: Arial">方案</span></span> </p>
<p>ExternalSessionManager类是当初某某软件商设计的用来解决Web服务器负载均衡的模块，这个类主要用来保存客户的基本登录信息（包括会话的EJBSessionId），以维护多个Web服务器之间的会话信息一致。 </p>
<p>改进方案有两种： </p>
<ul>
    <li>
    <p>从架构设计方面改进 </p>
    <p>实现Web层的负载均衡有很多标准的实现方式。例如：采用负载均衡设备(硬件或软件)来实现。 </p>
    <p>如果采用新的Web层的负载均衡方式，那么就可以去掉ExternalSessionManager这个类了。 </p>
    <li>
    <p>从应用实现方面改进 </p>
    <p>保留当前的Web层的负载均衡设计机制，仅仅从应用实现方面解决内存泄漏问题，首先菜单信息不应该保存在ExternalSessionManager中。其次，增加对ExternalSessionManager类中用户会话登录信息的清除，有几种方式可以选择： </p>
    <ul>
        <li>被动方式，当HttpSession会话超时（或过期）被Web应用服务器回收时清除相应的ExternalSessionManager中的过期会话登录信息。
        <li>主动方式，可以采用任务定时清理每天的过期会话登录信息或线程轮询清理。
        <li>采用新的会话登录信息存储方式，ExternalSessionManager的sessionMap中的key值不再以EJBSessionId作为键值，而是以用户id（EJBSessionId的前11位）代替。由于用户id每天都是一样的，所以不会造成内存泄漏。保存得登录信息也不再包含菜单节点信息，而只是登录基本信息。最多也只是保存整个系统所有的用户id及其基本登录信息（大约每个用户的登录信息只有1.5K左右，而目前这个系统的营业网点用户为1万左右，所以大约只占用Web服务器15M内存）。</li>
    </ul>
    </li>
</ul>
<p><br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td><img class="magplus" title="点击查看原始大小图片" height="0" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="700" _counted="undefined" /></td>
        </tr>
    </tbody>
</table>
<span><span style="font-size: medium; color: #000000; font-family: Arial">实施情况</span></span> </p>
<p>采用的方案：某某软件商采用了新的会话登录信息存贮方案，即:ExternalSessionManager的成员变量sessionMap中不再保存用户菜单信息，只保存基本的登录信息；存储方式采用用户id（11位）作为键值（key）来保留用户基本登录信息。 </p>
<p>基本分析：由于基本登录信息只有1K左右，而目前内网登录的用户总数也只有8887个，所以只保存了大约10M-15M的信息在内存，占用量很小，并且不会有内存泄漏。用户菜单信息保存在session中，如果用户退出时点击logout页面，那么应用服务器可以很快地释放这部分内存；如果用户直接关闭窗口，那么保存在session中的菜单信息只有等会话超时后才会由系统清除并回收内存。 </p>
<p>监控状况： </p>
<p><br />
<strong><span style="color: #000000">图九</span></strong><br />
<img height="378" alt="图九" src="http://www-128.ibm.com/developerworks/cn/java/j-performance/images/image019.jpg" width="622" border="0" _counted="undefined" /></p>
<p>如图九所示，ExternalSessionManager中只保留了简单的登录信息（Map中保存了WHsessionAttrVO对象），包括：当前版本(currentversion)，操作人员代码基本信息（czrydmInfo），当前时间（currenttime）。 </p>
<p><br />
<strong><span style="color: #000000">图十</span></strong><br />
<img height="164" alt="图十" src="http://www-128.ibm.com/developerworks/cn/java/j-performance/images/image021.jpg" width="553" border="0" _counted="undefined" /></p>
<p>如图十所示，这个登录用户的基本信息只有1368 bytes，大约1.3K </p>
<p><br />
<strong><span style="color: #000000">图十一</span></strong><br />
<img height="281" alt="图十一" src="http://www-128.ibm.com/developerworks/cn/java/j-performance/images/image023.jpg" width="658" border="0" _counted="undefined" /></p>
<p>如图十一所示，一共有两个用户（相同的用户id）登录系统，当一个用户<span class="hilite2">使用</span>logout页面退出时，保留在session中的菜单信息(MenuNode)立刻释放了，所以Difference一栏减少了806个菜单项。 </p>
<p><br />
<strong><span style="color: #000000">图十二</span></strong><br />
<img height="256" alt="图十二" src="http://www-128.ibm.com/developerworks/cn/java/j-performance/images/image025.jpg" width="604" border="0" _counted="undefined" /></p>
<p>如图十二所示，当另外一个会话超时后，应用服务器回收了整个会话的菜单信息（MenuNode），图上已经没有MenuNode对象了。并且由于是同一个用户登录，所以保留在ExternalSessionManager成员变量sessionMap中的对象WHsessionAttrVO只有一个(id=24400001129)，而没有产生多个，没有因为多次登录而产生多个对象的后果，避免了内存泄漏问题的出现，解决了前期定位的内存泄漏问题。 </p>
<p><br />
<strong><span style="color: #000000">图十三</span></strong><br />
<img height="335" alt="图十三" src="http://www-128.ibm.com/developerworks/cn/java/j-performance/images/image027.jpg" width="451" border="0" _counted="undefined" /></p>
<p>如图十三所示，经过gc内存回收后，发现内存回收比较稳定，基本都回收到了最低点，也证明了内存没有泄露。 </p>
<p>结论与建议：从测试情况看，解决了前期定位的内存泄漏问题。 </p>
<p><strong>生产系统实施后的监控与分析</strong> </p>
<p>经过调优后，我们发现：在2005年6月2日晚9点40左右重新部署、启动了Web应用服务器（采用了新的调优方案）。经过几天的监控运行，发现Web应用服务器目前运行基本稳定，目前没有出现新的内存泄漏问题，下列图示说明了这一点 </p>
<p><br />
<strong><span style="color: #000000">图十四 2005年6月2日</span></strong><br />
<img height="224" alt="图十四 2005年6月2日" src="http://www-128.ibm.com/developerworks/cn/java/j-performance/images/image029.gif" width="554" border="0" _counted="undefined" /></p>
<p>如图十四所示，6月2日晚21.7（21点42分）重新启动应用服务器，内存占用很少，大约为15%（请看红色曲线），每次GC消耗的时间也很短，大约在5秒以内（请看黄色曲线）。 </p>
<p><br />
<strong><span style="color: #000000">图十五 2005年6月3日周五</span></strong><br />
<img height="248" alt="图十五 2005年6月3日周五" src="http://www-128.ibm.com/developerworks/cn/java/j-performance/images/image031.gif" width="553" border="0" _counted="undefined" /></p>
<p>如图十五所示，在6月3日周五的整个工作日内，内存的回收基本到位，回收位置控制在20%-30%之间，也就是在600M-900M之间（请看红色曲线的最低点），始终可以回收2G的内存供应用程序<span class="hilite2">使用</span>，每次GC的时间最高不超过20秒，Full GC平均在10秒左右，时间消耗比较短（请看黄色曲线）。 </p>
<p><br />
<strong><span style="color: #000000">图十六2005年6月5日周日</span></strong><br />
<img height="198" alt="图十六2005年6月5日周日" src="http://www-128.ibm.com/developerworks/cn/java/j-performance/images/image033.gif" width="554" border="0" _counted="undefined" /></p>
<p>如图十六所示，在周日休息日期间，Web应用服务器全天只做了大约4次Full GC（黄色曲线中的小山峰），时间都在10秒以内；大的Full GC后，内存只占用10%，内存回收很彻底。 </p>
<p><br />
<strong><span style="color: #000000">图十七 2005年6月6日周一</span></strong><br />
<img height="249" alt="图十七 2005年6月6日周一" src="http://www-128.ibm.com/developerworks/cn/java/j-performance/images/image035.gif" width="554" border="0" _counted="undefined" /></p>
<p>如图十七所示，在周一工作日期间，内存回收还是不错的，基本可以回收到30%（见红色曲线的最低点），即：占用900M内存空间，剩余2G的内存空间；Full GC的时间大部分控制在20秒以内，平均15秒（见黄色曲线）。 </p>
<p><br />
<strong><span style="color: #000000">图十八 2005年6月7日周二</span></strong><br />
<img height="208" alt="图十八 2005年6月7日周二" src="http://www-128.ibm.com/developerworks/cn/java/j-performance/images/image037.gif" width="554" border="0" _counted="undefined" /></p>
<p>如图十八所示，在6月7日周二早上，大约8:30左右，Web应用服务器作了一次Full GC，用了10秒的时间，把内存回收到了10%的位置，为后续的<span class="hilite2">使用</span>腾出了90%的内存空间。内存回收仍然比较彻底，说明基本没有内存泄漏问题。 </p>
<p>经过这几天的监控分析，我们可以看出： </p>
<ul>
    <li>Web应用服务器的内存<span class="hilite2">使用</span>已经比较合理，内存在工作日的占用在20%至30%之间，约1G的内存占用，有2G的内存空间富裕；而在空闲时间（周日，每天的凌晨等）内存可以回收到10%，有90%的内存空间富裕；
    <li>Web应用服务器的Full GC的次数明显减少了并且每次Full GC占用的时间也很少，基本控制在10-20秒之间，有的甚至在10秒以内，明显改善了内网应用服务器内存的<span class="hilite2">使用</span>；
    <li>从6月2日重新部署之后，Web应用服务器没有出现宕机重启的现象。</li>
</ul>
<p>&nbsp;</p>
<p>
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td><img class="magplus" title="点击查看原始大小图片" height="0" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="700" _counted="undefined" /></td>
        </tr>
    </tbody>
</table>
</p>
<p><span><span style="font-size: medium; color: #000000; font-family: Arial">总结</span></span></p>
<p>&nbsp;通过本文，我们可以看到，内存的泄露将会导致服务器的宕机，系统性能就更别说了。对于系统内存泄露问题应该从服务器GC日志方面进行早诊断，<span class="hilite2">使用</span>工具早确认并提出解决方案，排除内存泄露问题，提高系统性能，以规避项目风险。 </p>
</div>
<img src ="http://www.blogjava.net/yglwxl/aggbug/194755.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yglwxl/" target="_blank">九宝</a> 2008-04-22 13:24 <a href="http://www.blogjava.net/yglwxl/archive/2008/04/22/194755.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>从jar中读取文件</title><link>http://www.blogjava.net/yglwxl/archive/2008/03/06/184234.html</link><dc:creator>九宝</dc:creator><author>九宝</author><pubDate>Thu, 06 Mar 2008 04:51:00 GMT</pubDate><guid>http://www.blogjava.net/yglwxl/archive/2008/03/06/184234.html</guid><wfw:comment>http://www.blogjava.net/yglwxl/comments/184234.html</wfw:comment><comments>http://www.blogjava.net/yglwxl/archive/2008/03/06/184234.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yglwxl/comments/commentRss/184234.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yglwxl/services/trackbacks/184234.html</trackback:ping><description><![CDATA[Sample1,利用Menifest文件读取jar中的文件<br />
/*<br />
1.文件目录<br />
test--<br />
&nbsp;&nbsp;&nbsp;&nbsp; --a.text<br />
&nbsp;&nbsp;&nbsp;&nbsp; --b.gif<br />
<br />
2. Menifest文件内容:<br />
Manifest-Version: 1.0<br />
abc: test/a.txt<br />
iconname: test/Anya.jpg<br />
注意:manifest.mf文件最后一行要打一回车<br />
Another Notification:<br />
如果manifest文件内容是:<br />
Manifest-Version: 1.0<br />
Main-Class: com.DesignToolApp<br />
Class-path: lib/client.jar lib/j2ee.jar<br />
在MANIFEST.MF文件的最后，要留两个空行（也就是回车），才可以识别到Class-Path这一行，如果只有一个空行，那么只识别到Main-Class这一行。Class-Path中的库名用空格格开，使用和jar包相对的路径，发布时把jar包和其他用到的类库一起交给用户就可以了。<br />
<br />
<br />
3.打jar包<br />
test.jar <br />
*/&nbsp;<br />
String iconpath = jar.getManifest().getMainAttributes().getValue("abc");<br />
&nbsp;&nbsp;&nbsp;&nbsp;InputStream in = jar.getInputStream(jar.getJarEntry(iconpath));<br />
&nbsp;&nbsp;&nbsp;&nbsp; //Image img = ImageIO.read(in);<br />
&nbsp;&nbsp;&nbsp;&nbsp;InputStreamReader isr =&nbsp; new InputStreamReader(in);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BufferedReader reader = new BufferedReader(isr);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String line;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while ((line = reader.readLine()) != null) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(line);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; reader.close();<br />
<br />
Sample2,读取JAR 文件列表及各项的名称、大小和压缩后的大小<br />
<p>public class JarFileInfoRead {<br />
&nbsp;public static void main (String args[])<br />
&nbsp; throws IOException {<br />
&nbsp; String jarpath="d://temp//test.jar";<br />
&nbsp; JarFile jarFile = new JarFile(jarpath);<br />
&nbsp; Enumeration enu = jarFile.entries();<br />
&nbsp; while (enu.hasMoreElements()) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; process(enu.nextElement());<br />
&nbsp; }<br />
}</p>
<p>private static void process(Object obj) {<br />
&nbsp; JarEntry entry = (JarEntry)obj;<br />
&nbsp; String name = entry.getName();<br />
&nbsp; long size = entry.getSize();<br />
&nbsp; long compressedSize = entry.getCompressedSize();<br />
&nbsp; System.out.println(name + "\t" + size + "\t" + compressedSize);<br />
}<br />
}</p>
Sample3,读取JAR中 文件的内容<br />
public class JarFileRead {<br />
&nbsp;&nbsp;&nbsp; public static void main (String args[])<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throws IOException {<br />
&nbsp;&nbsp;&nbsp; &nbsp; String jarpath="d://temp//test.jar";<br />
&nbsp;&nbsp;&nbsp; &nbsp; JarFile jarFile = new JarFile(jarpath);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Enumeration enu = jarFile.entries();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (enu.hasMoreElements()) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;JarEntry entry = (JarEntry)enu.nextElement();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String name = entry.getName();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //System.out.println(name);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(name.equals("test/a.txt")){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; InputStream input = jarFile.getInputStream(entry);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; process(input);<br />
&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; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; jarFile.close();<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; private static void process(InputStream input)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throws IOException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; InputStreamReader isr =<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new InputStreamReader(input);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BufferedReader reader = new BufferedReader(isr);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String line;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while ((line = reader.readLine()) != null) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(line);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; reader.close();<br />
&nbsp;&nbsp;&nbsp; }<br />
}<br />
<img src ="http://www.blogjava.net/yglwxl/aggbug/184234.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yglwxl/" target="_blank">九宝</a> 2008-03-06 12:51 <a href="http://www.blogjava.net/yglwxl/archive/2008/03/06/184234.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Swing的Jtable类(转载) </title><link>http://www.blogjava.net/yglwxl/archive/2008/01/15/175462.html</link><dc:creator>九宝</dc:creator><author>九宝</author><pubDate>Tue, 15 Jan 2008 06:29:00 GMT</pubDate><guid>http://www.blogjava.net/yglwxl/archive/2008/01/15/175462.html</guid><wfw:comment>http://www.blogjava.net/yglwxl/comments/175462.html</wfw:comment><comments>http://www.blogjava.net/yglwxl/archive/2008/01/15/175462.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yglwxl/comments/commentRss/175462.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yglwxl/services/trackbacks/175462.html</trackback:ping><description><![CDATA[<div class="postText">
<p><font size="2"></font></p>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><font size="2"><span style="color: #008080">1</span>&nbsp;<span style="color: #000000">table.setSelectionBackground(Color.black);&nbsp;table.setSelectionForeground(Color.white);</span></font> </div>
<p><font size="2"></font></p>
<font size="2">
<hr />
<br />
Swing颇受欢迎的JTable类为显示大块数据提供了一种简单的机制。JTable有很多东西是用于数据的生成和编辑，其中的很多东西还可以自定义，从而更进一步增强其功能。本文会引导你一步步地进入JTable的世界。</font>
<p><font size="2">Listing A包含了一个简单示例的代码，这个示例会说明常用JTable的行为。用户能够更改JTable的布局、拖放它的栏，或者通过拖动标题的分隔线来改变其大小。</font> </p>
<p><font size="2">这些列被保存在一个String数组里：</font> </p>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><font size="2"><span style="color: #008080">1</span>&nbsp;<span style="color: #000000">String[]&nbsp;columnNames&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;{</span><span style="color: #000000">"</span><span style="color: #000000">Product</span><span style="color: #000000">"</span><span style="color: #000000">,</span><span style="color: #000000">"</span><span style="color: #000000">Number&nbsp;of&nbsp;Boxes</span><span style="color: #000000">"</span><span style="color: #000000">,</span><span style="color: #000000">"</span><span style="color: #000000">Price</span><span style="color: #000000">"</span><span style="color: #000000">};</span></font> </div>
<font size="2">数据被初始化并保存在一个二维的对象数组里： </font>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><font size="2"><span style="color: #008080">1</span> <img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top"  alt="" /> <span style="color: #000000">Object[][]&nbsp;data&nbsp;</span> <span style="color: #000000">=</span> </font><span style="color: #000000"><br />
</span><font size="2"><span style="color: #008080">2</span> <span style="color: #000000"><img id="Codehighlighter1_18_187_Open_Image" onclick="this.style.display='none'; Codehighlighter1_18_187_Open_Text.style.display='none'; Codehighlighter1_18_187_Closed_Image.style.display='inline'; Codehighlighter1_18_187_Closed_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockStart.gif" align="top"  alt="" /> <img id="Codehighlighter1_18_187_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_18_187_Closed_Text.style.display='none'; Codehighlighter1_18_187_Open_Image.style.display='inline'; Codehighlighter1_18_187_Open_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ContractedBlock.gif" align="top"  alt="" /> </span><span id="Codehighlighter1_18_187_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /> </span></font><span id="Codehighlighter1_18_187_Open_Text"><font size="2"><span style="color: #000000">{<br />
</span><span style="color: #008080">3</span> <span style="color: #000000"><img id="Codehighlighter1_20_52_Open_Image" onclick="this.style.display='none'; Codehighlighter1_20_52_Open_Text.style.display='none'; Codehighlighter1_20_52_Closed_Image.style.display='inline'; Codehighlighter1_20_52_Closed_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top"  alt="" /> <img id="Codehighlighter1_20_52_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_20_52_Closed_Text.style.display='none'; Codehighlighter1_20_52_Open_Image.style.display='inline'; Codehighlighter1_20_52_Open_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ContractedSubBlock.gif" align="top"  alt="" /> </span><span id="Codehighlighter1_20_52_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /> </span><span id="Codehighlighter1_20_52_Open_Text"><span style="color: #000000">{</span> <span style="color: #000000">"</span> <span style="color: #000000">Apples</span> <span style="color: #000000">"</span> <span style="color: #000000">,&nbsp;</span> <span style="color: #0000ff">new</span> <span style="color: #000000">&nbsp;Integer(</span> <span style="color: #000000">5</span> <span style="color: #000000">),</span> <span style="color: #000000">"</span> <span style="color: #000000">5.00</span> <span style="color: #000000">"</span> <span style="color: #000000">}</span> </span></font><font size="2"><span style="color: #000000">,<br />
</span><span style="color: #008080">4</span> <span style="color: #000000"><img id="Codehighlighter1_64_97_Open_Image" onclick="this.style.display='none'; Codehighlighter1_64_97_Open_Text.style.display='none'; Codehighlighter1_64_97_Closed_Image.style.display='inline'; Codehighlighter1_64_97_Closed_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top"  alt="" /> <img id="Codehighlighter1_64_97_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_64_97_Closed_Text.style.display='none'; Codehighlighter1_64_97_Open_Image.style.display='inline'; Codehighlighter1_64_97_Open_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ContractedSubBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <span id="Codehighlighter1_64_97_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /> </span><span id="Codehighlighter1_64_97_Open_Text"><span style="color: #000000">{</span> <span style="color: #000000">"</span> <span style="color: #000000">Oranges</span> <span style="color: #000000">"</span> <span style="color: #000000">,&nbsp;</span> <span style="color: #0000ff">new</span> <span style="color: #000000">&nbsp;Integer(</span> <span style="color: #000000">3</span> <span style="color: #000000">),</span> <span style="color: #000000">"</span> <span style="color: #000000">6.00</span> <span style="color: #000000">"</span> <span style="color: #000000">}</span> </span></font><font size="2"><span style="color: #000000">,<br />
</span><span style="color: #008080">5</span> <span style="color: #000000"><img id="Codehighlighter1_109_140_Open_Image" onclick="this.style.display='none'; Codehighlighter1_109_140_Open_Text.style.display='none'; Codehighlighter1_109_140_Closed_Image.style.display='inline'; Codehighlighter1_109_140_Closed_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top"  alt="" /> <img id="Codehighlighter1_109_140_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_109_140_Closed_Text.style.display='none'; Codehighlighter1_109_140_Open_Image.style.display='inline'; Codehighlighter1_109_140_Open_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ContractedSubBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <span id="Codehighlighter1_109_140_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /> </span><span id="Codehighlighter1_109_140_Open_Text"><span style="color: #000000">{</span> <span style="color: #000000">"</span> <span style="color: #000000">Pears</span> <span style="color: #000000">"</span> <span style="color: #000000">,&nbsp;</span> <span style="color: #0000ff">new</span> <span style="color: #000000">&nbsp;Integer(</span> <span style="color: #000000">2</span> <span style="color: #000000">),</span> <span style="color: #000000">"</span> <span style="color: #000000">4.00</span> <span style="color: #000000">"</span> <span style="color: #000000">}</span> </span></font><font size="2"><span style="color: #000000">,<br />
</span><span style="color: #008080">6</span> <span style="color: #000000"><img id="Codehighlighter1_152_184_Open_Image" onclick="this.style.display='none'; Codehighlighter1_152_184_Open_Text.style.display='none'; Codehighlighter1_152_184_Closed_Image.style.display='inline'; Codehighlighter1_152_184_Closed_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top"  alt="" /> <img id="Codehighlighter1_152_184_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_152_184_Closed_Text.style.display='none'; Codehighlighter1_152_184_Open_Image.style.display='inline'; Codehighlighter1_152_184_Open_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ContractedSubBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <span id="Codehighlighter1_152_184_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /> </span><span id="Codehighlighter1_152_184_Open_Text"><span style="color: #000000">{</span> <span style="color: #000000">"</span> <span style="color: #000000">Grapes</span> <span style="color: #000000">"</span> <span style="color: #000000">,&nbsp;</span> <span style="color: #0000ff">new</span> <span style="color: #000000">&nbsp;Integer(</span> <span style="color: #000000">3</span> <span style="color: #000000">),</span> <span style="color: #000000">"</span> <span style="color: #000000">2.00</span> <span style="color: #000000">"</span> <span style="color: #000000">}</span> </span></font><font size="2"><span style="color: #000000">,<br />
</span><span style="color: #008080">7</span> <span style="color: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockEnd.gif" align="top"  alt="" />}</span> </font></span><span style="color: #000000"><font size="2">;</font> </span></div>
<p><font size="2">JTable是使用data和columnNames构成的：<br />
JTable table = new JTable(data, columnNames);</font> </p>
<p><strong><font size="2">查看JTable</font> </strong></p>
<p><font size="2">JTable的高度和宽度按照下面的方法来设定：<br />
table.setPreferredScrollableViewportSize(new Dimension(300, 80));</font> </p>
<p><font size="2">如果JTable的一个列或者JTable窗口自身的大小被重新确定，那么其他列会被相应的缩小或者放大，以适应新的窗口。使用setAutoResizeMode()方法就能够控制这种行为：</font> </p>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><font size="2"><span style="color: #008080">1</span>&nbsp;<span style="color: #000000">table.setAutoResizeMode(</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;mode);</span></font> </div>
<font size="2">mode整数字段可能的值有： </font>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><font size="2"><span style="color: #008080">1</span>&nbsp;</font> <font size="2"><span style="color: #000000">AUTO_RESIZE_OFF<br />
</span><span style="color: #008080">2</span>&nbsp;</font> <font size="2"><span style="color: #000000">AUTO_RESIZE_NEXT_COLUMN<br />
</span><span style="color: #008080">3</span>&nbsp;</font> <font size="2"><span style="color: #000000">AUTO_RESIZE_SUBSEQUENT_COLUMNS<br />
</span><span style="color: #008080">4</span>&nbsp;</font> <font size="2"><span style="color: #000000">AUTO_RESIZE_LAST_COLUMN<br />
</span><span style="color: #008080">5</span>&nbsp;<span style="color: #000000">AUTO_RESIZE_ALL_COLUMNS</span></font> </div>
<p><strong><font size="2">表格的缺省值</font> </strong></p>
<p><font size="2">单元格内方格坐标线的缺省颜色是Color.gray。要更改这些方格坐标线的颜色，就要用到：</font> </p>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><font size="2"><span style="color: #008080">1</span>&nbsp;<span style="color: #000000">table.setGridColor(Color.black);</span></font> </div>
<font size="2">你可以用下面的方法来改变行的高度： </font>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><font size="2"><span style="color: #008080">1</span>&nbsp;<span style="color: #000000">table.setRowHeight(intpixelHeight);</span></font> </div>
<p><font size="2">各个单元格的高度将等于行的高度减去行间的距离。</font> </p>
<p><font size="2">在缺省情况下，内容的前景颜色和背景颜色的选择都是由Swing的所见即所得的实现来确定的。你可以使用下面的方法来更改选择的颜色：</font> </p>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><font size="2"><span style="color: #008080">1</span>&nbsp;<span style="color: #000000">table.setSelectionBackground(Color.black);&nbsp;table.setSelectionForeground(Color.white);</span></font> </div>
<font size="2">你也可以隐藏单元格的方格坐标线，就像下面这样： </font>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><font size="2"><span style="color: #008080">1</span>&nbsp;<span style="color: #000000">table.setShowHorizontalLines(</span><span style="color: #0000ff">false</span></font> <font size="2"><span style="color: #000000">);<br />
</span><span style="color: #008080">2</span>&nbsp;<span style="color: #000000">table.setShowVerticalLines(</span><span style="color: #0000ff">false</span><span style="color: #000000">);</span></font> </div>
<p><strong><font size="2">列的宽度</font> </strong></p>
<p><font size="2">JTable组件有几个控制表格特性的类和接口。TableColumn会不断追踪列的宽度，并负责列大小的调整，包括最大和最小宽度。</font> </p>
<p><font size="2">TableColumnModel管理着TableColumns的集合以及列的选择。要设置某个列的宽度，就要为表格列的模型设置一个参照。然后，取得想要的TableColumn并调用其setPreferredWidth()方法：</font> </p>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><font size="2"><span style="color: #008080">1</span>&nbsp;<span style="color: #000000">TableColumncolumn&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;table.getColumnModel().getColumn(</span><span style="color: #000000">0</span></font> <font size="2"><span style="color: #000000">);<br />
</span><span style="color: #008080">2</span>&nbsp;<span style="color: #000000">column.setPreferredWidth(</span><span style="color: #000000">100</span><span style="color: #000000">);</span></font> </div>
<font size="2">当用户拖放列的时候，列的索引并不会发生改变。getColumn(0)方法会一直返回正确的列，无论它出现在屏幕的哪个地方。 </font>
<p><strong><font size="2">标题</font> </strong></p>
<p><font size="2">JtableHeader会处理JTable标题的显示。你可以细分JtableHeader以获得自定义的布局。例如，如果你的应用程序需要一个跨越多个列的标题，那么只用简单地细分JtableHeader并将它集成到你的JTable里就行了。</font> </p>
<p><font size="2">你可以通过为当前JTable的JtableHeader设置一个参照或者调用其setReorderingAllowed()方法，来指定标题的重新排序是否被允许：</font> </p>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><font size="2"><span style="color: #008080">1</span>&nbsp;<span style="color: #000000">table.getTableHeader().setReorderingAllowed(</span><span style="color: #0000ff">false</span><span style="color: #000000">);</span></font> </div>
<font size="2">类似地，你可以确信列不会因为在列标题之间拖动而改变大小。要达到这个目的，你就要使用setResizingAllowed()方法： </font>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><font size="2"><span style="color: #008080">1</span>&nbsp;<span style="color: #000000">table.getTableHeader().setResizingAllowed(</span><span style="color: #0000ff">false</span><span style="color: #000000">);</span></font> </div>
<p><strong><font size="2">选择模式</font> </strong></p>
<p><font size="2">在缺省状况下，当用户在JTable里选择一个单元格的时候，整个行都被选中了。有多种方法能够让用户自定义选择的方式。利用ListSelectionModel接口，你可以允许用户选择单个或者多个行：</font> </p>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><font size="2"><span style="color: #008080">1</span>&nbsp;<span style="color: #000000">table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);</span></font> </div>
<p><font size="2">ListSelectionModel有下面这些字段：</font> </p>
<p><font size="2">&nbsp;&nbsp;&nbsp; * SINGLE_SELECTION允许一次选择一行。<br />
&nbsp;&nbsp;&nbsp; * SINGLE_INTERVAL_SELECTION允许选择相邻的一系列行。<br />
&nbsp;&nbsp;&nbsp; * MULTIPLE_INTERVAL_SELECTION也允许选择相邻的列，但是带有扩展功能。它允许用户使用[Ctrl]键进行多个互不相邻的选择（即选择不相邻的行）。</font> </p>
<p><font size="2">setCellSelectionEnabled()方法让用户能够同时选择单个单元格或者整个行：</font> </p>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><font size="2"><span style="color: #008080">1</span>&nbsp;<span style="color: #000000">table.setCellSelectionEnabled(</span><span style="color: #0000ff">true</span><span style="color: #000000">);</span></font> </div>
<p><strong><font size="2">编辑单元格</font> </strong></p>
<p><font size="2">我们这个简单的表格允许用户编辑表格里的任何单元格。Listing B列出了一个表格，它允许由程序员来决定哪些单元格能够被编辑。第一步是创建一个自定义的TableModel：</font> </p>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><font size="2"><span style="color: #008080">1</span>&nbsp;<span style="color: #0000ff">class</span><span style="color: #000000">&nbsp;SimpleTableModel&nbsp;</span><span style="color: #0000ff">extends</span><span style="color: #000000">&nbsp;AbstractTableModel&nbsp;{}</span></font> </div>
<font size="2">数据被封装在TableModel里，当JTable初始化的时候，自定义的TableModel就被作为一个参数传递给JTable的构造函数而不是那个二维的对象数组：</font>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><font size="2"><span style="color: #008080">1</span>&nbsp;<span style="color: #000000">SimpleTableModelmyModel&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">new</span></font> <font size="2"><span style="color: #000000">&nbsp;SimpleTableModel();<br />
</span><span style="color: #008080">2</span>&nbsp;<span style="color: #000000">JTable&nbsp;table&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;JTable(myModel);</span></font> </div>
<font size="2">如果想让第二列和第三列也变得可以编辑，并把第一列变成恒定的，那么你就要强制替代TableModel的isCellEditable()方法：</font>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><font size="2"><span style="color: #008080">1</span>&nbsp;<span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;booleanisCellEditable(</span><span style="color: #0000ff">int</span></font> <font size="2"><span style="color: #000000">&nbsp;row,&nbsp;intcol){<br />
</span><span style="color: #008080">2</span>&nbsp;<span style="color: #0000ff">if</span><span style="color: #000000">&nbsp;(col&nbsp;</span><span style="color: #000000">==</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">0</span><span style="color: #000000">)&nbsp;{</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">false</span></font> <font size="2"><span style="color: #000000">;}<br />
</span><span style="color: #008080">3</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">else</span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">true</span></font> <font size="2"><span style="color: #000000">;&nbsp;}<br />
</span><span style="color: #008080">4</span>&nbsp;<span style="color: #000000">}</span></font> </div>
<p><strong><font size="2">简单的表格验证</font> </strong></p>
<p><font size="2">你需要确保用户只输入整数值，假如说，向第二列（&#8220;盒子的数量&#8221;这一列）输入值来强制替代setValueAt()方法，并将验证逻辑包括进这个新方法里。首先，你要检查列是否是整数，以及这个列是否只应该包含整数值：</font> </p>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><font size="2"><span style="color: #008080">1</span>&nbsp;<span style="color: #0000ff">if</span><span style="color: #000000">&nbsp;(data[</span><span style="color: #000000">0</span><span style="color: #000000">][col]&nbsp;</span><span style="color: #0000ff">instanceof</span><span style="color: #000000">&nbsp;Integer&nbsp;</span><span style="color: #000000">&amp;&amp;</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">!</span><span style="color: #000000">(value&nbsp;</span><span style="color: #0000ff">instanceof</span></font> <font size="2"><span style="color: #000000">&nbsp;Integer))<br />
</span><span style="color: #008080">2</span>&nbsp;<span style="color: #000000">{&#8230;&nbsp;}&nbsp;</span><span style="color: #0000ff">else</span><span style="color: #000000">&nbsp;{&nbsp;data[row][col]&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;value;}</span></font> </div>
<font size="2">然后，检查被插入的值是否是个整数。如果它不是的，那么这个字段就不应该被更新，而且应该要显示一条错误信息：</font>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><font size="2"><span style="color: #008080">1</span>&nbsp;<span style="color: #0000ff">try</span></font> <font size="2"><span style="color: #000000">&nbsp;{<br />
</span><span style="color: #008080">2</span>&nbsp;<span style="color: #000000">data[row][col]&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">new</span></font> <font size="2"><span style="color: #000000">&nbsp;Integer(value.toString());<br />
</span><span style="color: #008080">3</span>&nbsp;<span style="color: #000000">}&nbsp;</span><span style="color: #0000ff">catch</span></font> <font size="2"><span style="color: #000000">&nbsp;(NumberFormatException&nbsp;e)&nbsp;{<br />
</span><span style="color: #008080">4</span>&nbsp;<span style="color: #000000">JOptionPane.showMessageDialog(SimpleTable.</span><span style="color: #0000ff">this</span></font> <font size="2"><span style="color: #000000">,<br />
</span><span style="color: #008080">5</span>&nbsp;<span style="color: #000000">"</span><span style="color: #000000">Please&nbsp;enter&nbsp;only&nbsp;integer&nbsp;values.</span><span style="color: #000000">"</span></font> <font size="2"><span style="color: #000000">);<br />
</span><span style="color: #008080">6</span>&nbsp;<span style="color: #000000">}</span></font> </div>
<p><strong><font size="2">背景颜色</font> </strong></p>
<p><font size="2">Listing C包含了用于ColorTable.java的代码，它说明了如何向JTable加入颜色。你可以通过强制替代其prepareRenderer()方法来向JTable加入背景颜色：</font> </p>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><font size="2"><span style="color: #008080">1</span>&nbsp;<span style="color: #000000">JTable&nbsp;table&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">new</span></font> <font size="2"><span style="color: #000000">&nbsp;JTable(data,&nbsp;columnNames){<br />
</span><span style="color: #008080">2</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;Component&nbsp;prepareRenderer(TableCellRenderer&nbsp;r,&nbsp;</span><span style="color: #0000ff">int</span></font> <font size="2"><span style="color: #000000">&nbsp;row,&nbsp;intcol){}<br />
</span><span style="color: #008080">3</span>&nbsp;<span style="color: #000000">};</span></font> </div>
<font size="2">然后，插入决定哪些列应该有颜色以及应该是什么颜色的逻辑：</font>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><font size="2"><span style="color: #008080">1</span>&nbsp;<span style="color: #0000ff">if</span><span style="color: #000000">&nbsp;(col&nbsp;</span><span style="color: #000000">==</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">2</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">&amp;&amp;</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">!</span></font> <font size="2"><span style="color: #000000">isCellSelected(row,&nbsp;col)){<br />
</span><span style="color: #008080">2</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Color&nbsp;bg&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;Color(</span><span style="color: #000000">200</span><span style="color: #000000">,&nbsp;</span><span style="color: #000000">100</span><span style="color: #000000">,&nbsp;</span><span style="color: #000000">30</span></font> <font size="2"><span style="color: #000000">);<br />
</span><span style="color: #008080">3</span>&nbsp;</font> <font size="2"><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;c.setBackground(bg);<br />
</span><span style="color: #008080">4</span>&nbsp;</font> <font size="2"><span style="color: #000000">c.setForeground(Color.white);<br />
</span><span style="color: #008080">5</span>&nbsp;<span style="color: #000000">}</span></font> </div>
<font size="2">要注意，当你更改单元格背景颜色的时候，你还应该更该单元格里所显示的文本的颜色，让其变得更加易读。图C显示了一个第一列和第二列加上了颜色的JTable。</font>
<p><strong><font size="2">一切皆在掌握中</font> </strong></p>
<p><font size="2">我们的例子只是JTable其他部分的基础。通过使用这些工具，你能够快速和轻易地掌控对Java应用程序所生成的表格的格式化，这样就能够让你的用户在进行正常使用的时候不碰到障碍。</font> <br />
<br />
摘自：<a href="http://www.7dspace.com/doc/21/0601/20061905111047137.htm">http://www.7dspace.com/doc/21/0601/20061905111047137.htm</a><a href="http://www.7dspace.com/"></a></p>
</div>
<img src ="http://www.blogjava.net/yglwxl/aggbug/175462.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yglwxl/" target="_blank">九宝</a> 2008-01-15 14:29 <a href="http://www.blogjava.net/yglwxl/archive/2008/01/15/175462.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>在JAVA中使用拖拽功能(2转)</title><link>http://www.blogjava.net/yglwxl/archive/2008/01/10/174278.html</link><dc:creator>九宝</dc:creator><author>九宝</author><pubDate>Thu, 10 Jan 2008 06:16:00 GMT</pubDate><guid>http://www.blogjava.net/yglwxl/archive/2008/01/10/174278.html</guid><wfw:comment>http://www.blogjava.net/yglwxl/comments/174278.html</wfw:comment><comments>http://www.blogjava.net/yglwxl/archive/2008/01/10/174278.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/yglwxl/comments/commentRss/174278.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yglwxl/services/trackbacks/174278.html</trackback:ping><description><![CDATA[在JAVA中使用拖拽功能<br />
sun在java2中引入了一些新的方法来帮助实现拖拽功能，这些新的类在java.awt.dnd包中<br />
实现一个D&amp;D操作一般包括三个步骤:<br />
&nbsp;首先实现一个拖拽源，这个拖拽源和相应的组件是关联起来的<br />
&nbsp;第二步实现一个拖拽目标，这个目标用来实现拖拽物的接收<br />
&nbsp;第三步实现一个数据传输对象，该对象封装拖动的数据<br />
&nbsp; _____________________&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&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;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp; &nbsp;<br />
&nbsp;| DragSource Component|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |DropTarget Component|<br />
&nbsp;|_____________________|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&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;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&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;&nbsp; |____________Transferable Data_________________|<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />
&nbsp;Transferable 接口实现出的对象能够保证&nbsp; DropTarget Component读懂拖拽过来的对象中包含的信息<br />
&nbsp;如果是在同一个虚拟机中实现拖拽的话，DragSource Component会传递一个引用给DropTarget Component<br />
&nbsp;但是如果在不同的JVM中或者是在JVM和本地系统之间传递数据的话我们就必须实现一个Transferable对象来传递数据<br />
&nbsp;Transferable中封装的内容存放到DataFlavors，用户可以通过访问DataFlavors来获取数据<br />
&nbsp;1。创建可拖拽对象<br />
&nbsp;&nbsp; 一个对象那个如果想作为拖拽源的话，必须和五个对象建立练习，这五个对象分别是：<br />
&nbsp;&nbsp;&nbsp; * java.awt.dnd.DragSource<br />
&nbsp;&nbsp;&nbsp; 获取DragSource的方法很简单，直接调用DragSource.getDefaultDragSource()；就可以得到DragSource对象<br />
&nbsp;&nbsp;&nbsp; * java.awt.dnd.DragGestureRecognizer<br />
&nbsp;&nbsp;&nbsp; DragGestureRecognizer类中实现了一些与平台无关的方法，我们如果想在自己的组件上实现拖拽的话只要调用createDefaultDragGestureRecognizer()方法就可以了<br />
&nbsp;&nbsp;&nbsp; 该方法接收三个参数，建立组件和拖拽动作之间的关系<br />
&nbsp;&nbsp;&nbsp; * java.awt.dnd.DragGestureListener<br />
&nbsp;&nbsp;&nbsp; 当建立了组件和拖拽动作之间的联系后，如果用户执行了拖拽操作，组件将发送一个消息给DragGestureListener监听器<br />
&nbsp;&nbsp;&nbsp; DragGestureListener监听器接下来会发送一个startDrag()消息给拖拽源对象，告诉组件应该执行拖拽的初始化操作了<br />
&nbsp;&nbsp;&nbsp; 拖拽源会产生一个DragSourceContext对象来监听动作的状态，这个监听过程是通过监听本地方法DragSourceContextPeer来实现的<br />
&nbsp;&nbsp;&nbsp; * java.awt.datatransfer.Transferable<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; * java.awt.dnd.DragSourceListener <br />
&nbsp;&nbsp;&nbsp; DragSourceListener接口负责当鼠标拖拽对象经过组件时的可视化处理， DragSourceListener接口的显示结果只是暂时改变组件的外观<br />
&nbsp;&nbsp;&nbsp; 同时他提供一个feedback，当用户的拖拽操作完成之后会收到一个dragDropEnd的消息，我们可以在这个函数中执行相应的操作<br />
&nbsp;&nbsp;&nbsp; 再来回顾一下拖拽源的建立过程<br />
&nbsp;&nbsp;&nbsp; 首先、 DragGestureRecognizer 确认一个拖拽操作，同时告知 DragGestureListener.<br />
<br />
&nbsp;&nbsp;&nbsp; 其次、 Assuming the actions and/or flavors are OK, DragGestureListener asks DragSource to startDrag().<br />
<br />
&nbsp;&nbsp;&nbsp; 第三、 DragSource creates a DragSourceContext and a DragSourceContextPeer. The DragSourceContext adds itself as a DragSourceListener to the DragSourceContextPeer.<br />
<br />
&nbsp;&nbsp;&nbsp; 第四、 DragSourceContextPeer receives state notifications (component entered/exited/is over) from the native system and delegates them to the DragSourceContext.<br />
<br />
&nbsp;&nbsp;&nbsp; 第五、 The DragSourceContext notifies the DragSourceListener, which provides drag over feedback (if the DropTargetListener accepts the action). Typical feedback includes asking the DragSourceContext to change the cursor.<br />
<br />
&nbsp;&nbsp;&nbsp; 最后、 When the drop is complete, the DragSourceListener receives a dragDropEnd notification message<br />
<br />
2。创建droppable Component<br />
&nbsp;&nbsp; 创建一个 droppable Component必须和下面两个对象发生关联&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; * java.awt.dnd.DropTarget<br />
&nbsp;&nbsp;&nbsp; DropTarget构造函数使DropTarget 和 DropTargetListener objects发生关联<br />
&nbsp;&nbsp;&nbsp; Droptarget对象提供 setComponent 和addDropTargetListener 两个方法<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; * java.awt.dnd.DropTargetListener <br />
&nbsp;&nbsp;&nbsp; The DropTargetListener needs an association with the Component so that the Component can notify the DropTargetListener to display "drag under" effects during the operation. This listener, which can be conveniently created as an inner class, transfers the data when the drop occurs. Warning: The Component itself shouldn't be the listener, since this implies its availability for use as some other Component's listener.<br />
&nbsp;<br />
<br />
<br />
<br />
<br />
下面的例子演示了一个从树中拖拽一个节点到文本域中<br />
<br />
package appletandservlet;<br />
<br />
import java.awt.*;<br />
<br />
import javax.swing.*;<br />
import com.borland.jbcl.layout.XYLayout;<br />
import com.borland.jbcl.layout.*;<br />
import java.awt.dnd.*;<br />
import java.awt.datatransfer.*;<br />
import java.io.*;<br />
import javax.swing.tree.*;<br />
<br />
public class DragAndDrop extends JFrame {<br />
<br />
&nbsp;&nbsp;&nbsp; XYLayout xYLayout1 = new XYLayout();<br />
&nbsp;&nbsp;&nbsp; JScrollPane jScrollPane1 = new JScrollPane();<br />
&nbsp;&nbsp;&nbsp; JTextArea jTextArea1 = new JTextArea();<br />
<br />
&nbsp;&nbsp;&nbsp; public DragAndDrop() {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; jbInit();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (Exception exception) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; exception.printStackTrace();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; getContentPane().setLayout(xYLayout1);<br />
<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; jScrollPane1.getViewport().setBackground(new Color(105, 38, 125));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; jTextArea1.setBackground(Color.orange);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; jTextArea1.setToolTipText("");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; JTree jtr = new JTree();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; jtr.setBackground(Color.BLUE);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; jScrollPane1.getViewport().add(jtr);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.getContentPane().add(jTextArea1,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new XYConstraints(238, 42, 140, 248));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.getContentPane().add(jScrollPane1,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new XYConstraints(16, 42, 217, 249));<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DragSource dragSource = DragSource.getDefaultDragSource(); //创建拖拽源<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dragSource.createDefaultDragGestureRecognizer(jtr,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DnDConstants.ACTION_COPY_OR_MOVE,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new DragAndDropDragGestureListener()); //建立拖拽源和事件的联系<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DropTarget dropTarget = new DropTarget(jTextArea1,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new DragAndDropDropTargetListener());<br />
<br />
&nbsp;&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp;&nbsp; private void jbInit() throws Exception {<br />
<br />
&nbsp;&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp;&nbsp; public static void main(String[] args) {<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DragAndDrop dad = new DragAndDrop();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dad.setTitle("拖拽演示");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dad.setSize(400, 300);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dad.setVisible(true);<br />
<br />
&nbsp;&nbsp;&nbsp; }<br />
}<br />
<br />
<br />
class DragAndDropDragGestureListener implements DragGestureListener {<br />
&nbsp;&nbsp;&nbsp; public void dragGestureRecognized(DragGestureEvent dge) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //将数据存储到Transferable中，然后通知组件开始调用startDrag()初始化<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; JTree tree = (JTree) dge.getComponent();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TreePath path = tree.getSelectionPath();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(path!=null){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DefaultMutableTreeNode selection = (DefaultMutableTreeNode) path<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .getLastPathComponent();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DragAndDropTransferable dragAndDropTransferable = new<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DragAndDropTransferable(selection);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dge.startDrag(DragSource.DefaultCopyDrop, dragAndDropTransferable, new DragAndDropDragSourceListener());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; }<br />
<br />
<br />
}<br />
<br />
<br />
class DragAndDropTransferable implements Transferable {<br />
&nbsp;&nbsp;&nbsp; private DefaultMutableTreeNode treeNode;<br />
&nbsp;&nbsp;&nbsp; DragAndDropTransferable(DefaultMutableTreeNode treeNode) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.treeNode = treeNode;<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; static DataFlavor flavors[] = {DataFlavor.stringFlavor};<br />
&nbsp;&nbsp;&nbsp; public DataFlavor[] getTransferDataFlavors() {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return flavors;<br />
&nbsp;&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp;&nbsp; public boolean isDataFlavorSupported(DataFlavor flavor) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(treeNode.getChildCount()==0){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return true;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return false;<br />
&nbsp;&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp;&nbsp; public Object getTransferData(DataFlavor flavor) throws<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UnsupportedFlavorException, IOException {<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return treeNode;<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; }<br />
<br />
<br />
}<br />
<br />
<br />
&nbsp;class DragAndDropDragSourceListener implements DragSourceListener {<br />
&nbsp; public void dragDropEnd(DragSourceDropEvent dragSourceDropEvent) {<br />
&nbsp;&nbsp;&nbsp; if (dragSourceDropEvent.getDropSuccess()) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //拖拽动作结束的时候打印出移动节点的字符串<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int dropAction = dragSourceDropEvent.getDropAction();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (dropAction == DnDConstants.ACTION_MOVE) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("MOVE: remove node");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp; }<br />
<br />
&nbsp; public void dragEnter(DragSourceDragEvent dragSourceDragEvent) {<br />
&nbsp;&nbsp;&nbsp; DragSourceContext context = dragSourceDragEvent<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .getDragSourceContext();<br />
&nbsp;&nbsp;&nbsp; int dropAction = dragSourceDragEvent.getDropAction();<br />
&nbsp;&nbsp;&nbsp; if ((dropAction &amp; DnDConstants.ACTION_COPY) != 0) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; context.setCursor(DragSource.DefaultCopyDrop);<br />
&nbsp;&nbsp;&nbsp; } else if ((dropAction &amp; DnDConstants.ACTION_MOVE) != 0) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; context.setCursor(DragSource.DefaultMoveDrop);<br />
&nbsp;&nbsp;&nbsp; } else {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; context.setCursor(DragSource.DefaultCopyNoDrop);<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp; }<br />
<br />
&nbsp; public void dragExit(DragSourceEvent dragSourceEvent) {<br />
&nbsp; }<br />
<br />
&nbsp; public void dragOver(DragSourceDragEvent dragSourceDragEvent) {<br />
&nbsp; }<br />
<br />
&nbsp; public void dropActionChanged(DragSourceDragEvent dragSourceDragEvent) {<br />
&nbsp; }<br />
}<br />
class DragAndDropDropTargetListener implements DropTargetListener{<br />
&nbsp;&nbsp;&nbsp; public void dragEnter(DropTargetDragEvent dtde){<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; public void dragOver(DropTargetDragEvent dtde){<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; public void dropActionChanged(DropTargetDragEvent dtde){<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; public void dragExit(DropTargetEvent dte){<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; public void drop(DropTargetDropEvent dtde){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Transferable tr=dtde.getTransferable();//使用该函数从Transferable对象中获取有用的数据<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String s="";<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(tr.isDataFlavorSupported(DataFlavor.stringFlavor)){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; s = tr.getTransferData(DataFlavor.stringFlavor).toString();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (IOException ex) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (UnsupportedFlavorException ex) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(s);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DropTarget c=(DropTarget)dtde.getSource();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; JTextArea d=(JTextArea)c.getComponent();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(s!=null&amp;&amp;s!=""){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; d.append(s + "\n");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; }<br />
<br />
<br />
}<br />
<img src ="http://www.blogjava.net/yglwxl/aggbug/174278.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yglwxl/" target="_blank">九宝</a> 2008-01-10 14:16 <a href="http://www.blogjava.net/yglwxl/archive/2008/01/10/174278.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java中的Drag and Drop详解与代码示例 (转)</title><link>http://www.blogjava.net/yglwxl/archive/2008/01/10/174276.html</link><dc:creator>九宝</dc:creator><author>九宝</author><pubDate>Thu, 10 Jan 2008 06:12:00 GMT</pubDate><guid>http://www.blogjava.net/yglwxl/archive/2008/01/10/174276.html</guid><wfw:comment>http://www.blogjava.net/yglwxl/comments/174276.html</wfw:comment><comments>http://www.blogjava.net/yglwxl/archive/2008/01/10/174276.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yglwxl/comments/commentRss/174276.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yglwxl/services/trackbacks/174276.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 通过两种方法实现Drag and Drop:&nbsp;1.比较初级的D&amp;D:只利用java.awt.datatransfer.*中的类实现.&nbsp;2.高级D&amp;D: 利用javax.awt.dnd.*中的类实现.比较初级D&amp;D:只利用java.awt.datatransfer.*中的类实现.&nbsp;这种方法只支持对JComponent的拖拽.&...&nbsp;&nbsp;<a href='http://www.blogjava.net/yglwxl/archive/2008/01/10/174276.html'>阅读全文</a><img src ="http://www.blogjava.net/yglwxl/aggbug/174276.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yglwxl/" target="_blank">九宝</a> 2008-01-10 14:12 <a href="http://www.blogjava.net/yglwxl/archive/2008/01/10/174276.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>单元测试(Unit Test)(转)</title><link>http://www.blogjava.net/yglwxl/archive/2008/01/08/173543.html</link><dc:creator>九宝</dc:creator><author>九宝</author><pubDate>Tue, 08 Jan 2008 02:03:00 GMT</pubDate><guid>http://www.blogjava.net/yglwxl/archive/2008/01/08/173543.html</guid><wfw:comment>http://www.blogjava.net/yglwxl/comments/173543.html</wfw:comment><comments>http://www.blogjava.net/yglwxl/archive/2008/01/08/173543.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yglwxl/comments/commentRss/173543.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yglwxl/services/trackbacks/173543.html</trackback:ping><description><![CDATA[<p style="margin-top: 0cm"><span style="font-size: 21pt">B.</span>1<span style="font-family: 宋体">　单元测试</span>(Unit Test)</p>
<p style="text-indent: 22.6pt"><span style="font-family: 宋体">一个单元</span>(Unit)<span style="font-family: 宋体">是指一个可独立进行的工作，独立进行指的是这个工作不受前一次或接下来的工作的结果影响。简单地说，就是不与程序运行时的上下文</span>(Context)<span style="font-family: 宋体">发生关系。</span></p>
<p style="text-indent: 22.6pt"><span style="font-family: 宋体">如果是在</span>Java<span style="font-family: 宋体">程序中，<span style="kkkk: blue">具体来说一个单元可以是指一个方法</span></span><span style="kkkk: blue">(Method)</span><span style="font-family: 宋体">。这个方法不依赖于前一次运行的结果，也不牵涉到后一次的运行结果。</span></p>
<p style="text-indent: 22.6pt"><span style="font-family: 宋体">举例来说，下面这个程序的</span>gcd()<span style="font-family: 宋体">方法可视为一个单元：</span></p>
<div style="padding-right: 0cm; padding-left: 0cm; padding-bottom: 1pt; border-top-style: none; padding-top: 0cm; border-bottom: blue 1pt solid; border-right-style: none; border-left-style: none">
<p><span style="font-family: Wingdings">&#220;</span> MathTool.java</p>
</div>
<p style="margin-left: 12.1pt">package onlyfun.caterpillar;</p>
<p style="margin-left: 12.1pt">public class MathTool {</p>
<p style="margin-left: 12.1pt">&nbsp;&nbsp;&nbsp; public static int gcd(int num1, int num2) {</p>
<p style="margin-left: 12.1pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int r = 0;</p>
<p style="margin-left: 12.1pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while(num2 != 0) {</p>
<p style="margin-left: 12.1pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; r = num1 % num2;</p>
<p style="margin-left: 12.1pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; num1 = num2;</p>
<p style="margin-left: 12.1pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; num2 = r;</p>
<p style="margin-left: 12.1pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p style="margin-left: 12.1pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return num1;</p>
<p style="margin-left: 12.1pt">&nbsp;&nbsp;&nbsp; }</p>
<div style="padding-right: 0cm; padding-left: 0cm; padding-bottom: 1pt; margin-left: 1.45pt; border-top-style: none; margin-right: 0cm; padding-top: 0cm; border-bottom: blue 1pt solid; border-right-style: none; border-left-style: none">
<p style="margin-left: 0cm; text-indent: 8pt">}</p>
</div>
<p style="text-indent: 22.6pt"><span style="font-family: 宋体">下面的</span>gcd()<span style="font-family: 宋体">方法不可视为一个单元，要完成</span>gcd<span style="font-family: 宋体">的计算，必须调用</span>setNum1()<span style="font-family: 宋体">、</span>setNum2()<span style="font-family: 宋体">与</span>gcd() 3<span style="font-family: 宋体">个方法。</span></p>
<div style="padding-right: 0cm; padding-left: 0cm; padding-bottom: 1pt; border-top-style: none; padding-top: 0cm; border-bottom: blue 1pt solid; border-right-style: none; border-left-style: none">
<p><span style="font-family: Wingdings">&#220;</span> MathFoo.java</p>
</div>
<p style="margin-left: 12.1pt">package onlyfun.caterpillar;</p>
<p style="margin-left: 12.1pt">public class MathFoo {</p>
<p style="margin-left: 12.1pt">&nbsp;&nbsp;&nbsp; private static int num1;</p>
<p style="margin-left: 12.1pt">&nbsp;&nbsp;&nbsp; private static int num2;</p>
<p style="margin-left: 12.1pt">&nbsp;&nbsp;&nbsp; public static void setNum1(int n) {</p>
<p style="margin-left: 12.1pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; num1 = n;</p>
<p style="margin-left: 12.1pt">&nbsp;&nbsp;&nbsp; }</p>
<p style="margin-left: 12.1pt">&nbsp;&nbsp;&nbsp; public static void setNum2(int n) {</p>
<p style="margin-left: 12.1pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; num2 = n;</p>
<p style="margin-left: 12.1pt">&nbsp;&nbsp;&nbsp; }</p>
<p style="margin-left: 12.1pt">&nbsp;&nbsp;&nbsp; public static int gcd() {</p>
<p style="margin-left: 12.1pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int r = 0;</p>
<p style="margin-left: 12.1pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while(num2 != 0) {</p>
<p style="margin-left: 12.1pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; r = num1 % num2;</p>
<p style="margin-left: 12.1pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; num1 = num2;</p>
<p style="margin-left: 12.1pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; num2 = r;</p>
<p style="margin-left: 12.1pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p style="margin-left: 12.1pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return num1;</p>
<p style="margin-left: 12.1pt">&nbsp;&nbsp;&nbsp; }</p>
<div style="padding-right: 0cm; padding-left: 0cm; padding-bottom: 1pt; margin-left: 1.45pt; border-top-style: none; margin-right: 0cm; padding-top: 0cm; border-bottom: blue 1pt solid; border-right-style: none; border-left-style: none">
<p style="margin-left: 0cm; text-indent: 8pt">}</p>
</div>
<p style="text-indent: 22.6pt"><span style="font-family: 宋体">然而要完全使用一个方法来完成一个单元操作在实现上是有困难的，所以单元也可广义解释为数个方法的集合。这数个方法组合为一个单元操作，目的是完成一个任务。</span></p>
<p style="text-indent: 22.6pt"><span style="font-family: 宋体">不过设计时仍优先考虑将一个公开的方法设计为单元，辅助的方法则使用设定为私用，尽量不用数个公开的方法来完成一件工作，以保持接口简洁与单元边界清晰。将工作以一个单元进行设计，这使得单元可以重用，并且也使得单元可以进行测试，进而增加类的可重用性。</span></p>
<p style="text-indent: 23pt"><span style="font-family: 宋体; letter-spacing: 0.5pt">单元测试指的是对每一个工作单元进行测试，了解其运行结果是否符合我们的要求。例如当编写完</span><span style="letter-spacing: 0.5pt">MathTool</span><span style="font-family: 宋体; letter-spacing: 0.5pt">类之后，也许会这么写一个小小的测试程</span><span style="font-family: 宋体">序：</span></p>
<div style="padding-right: 0cm; padding-left: 0cm; padding-bottom: 1pt; border-top-style: none; padding-top: 0cm; border-bottom: blue 1pt solid; border-right-style: none; border-left-style: none">
<p><span style="font-family: Wingdings">&#220;</span> MathToolTest.java</p>
</div>
<p style="margin-left: 12.1pt">package test.onlyfun.caterpillar;</p>
<p style="margin-left: 12.1pt">import onlyfun.caterpillar.MathTool;</p>
<p style="margin-left: 12.1pt">public class MathToolTest {</p>
<p style="margin-left: 12.1pt">&nbsp;&nbsp;&nbsp; public static void main(String[] args) {</p>
<p style="margin-left: 12.1pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(MathTool.gcd(10, 5) == 5) {</p>
<p style="margin-left: 12.1pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("GCD Test OK!");</p>
<p style="margin-left: 12.1pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p style="margin-left: 12.1pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else {</p>
<p style="margin-left: 12.1pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("GCD Test Fail!");</p>
<p style="margin-left: 12.1pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p style="margin-left: 12.1pt">&nbsp;&nbsp;&nbsp; }</p>
<div style="padding-right: 0cm; padding-left: 0cm; padding-bottom: 1pt; margin-left: 1.45pt; border-top-style: none; margin-right: 0cm; padding-top: 0cm; border-bottom: blue 1pt solid; border-right-style: none; border-left-style: none">
<p style="margin-left: 0cm; text-indent: 8pt">}</p>
</div>
<p style="text-indent: 22.6pt"><span style="font-family: 宋体">在文字模式下使用文字信息显示测试结果，这个动作是开发人员经常作的事情，然而您必须一行一行看着测试程序的输出结果，以了解测试是否成功。另一方面，测试程序本身也是一个程序，在更复杂的测试中，也许会遇到测试程序本身出错，而导致无法验证结果的情况。</span></p>
<p style="text-indent: 22.6pt">JUnit<span style="font-family: 宋体">是一个测试框架，通过它所提供的工具，可以减少编写错误的测试程序的机会。另一方面，可以有更好的方法来检验测试结果，而不是看着一长串输出的文字来检验测试是否成功。</span>JUnit<span style="font-family: 宋体">测试框架让测试的进行更有效率且更具可靠性。</span></p>
<p class="1-1"><span lang="EN-US" style="font-size: 21pt">B.</span><span lang="EN-US">2</span><span style="font-family: 宋体">　</span><span lang="EN-US">JUnit</span><span style="font-family: 宋体">设置</span></p>
<p class="MsoNormal" style="text-indent: 22.6pt"><span lang="EN-US">JUnit</span><span style="font-family: 宋体">最初是由</span><span lang="EN-US">Erich Gamma</span><span style="font-family: 宋体">与</span><span lang="EN-US">Kent Beck</span><span style="font-family: 宋体">编写，为单元测试的支持框架，用来编写与执行重复性的测试。它包括以下特性：</span></p>
<p class="0d" style="margin-left: 45.25pt; text-indent: -21pt"><span lang="EN-US" style="font-family: Wingdings">&#220;</span><span lang="EN-US">&nbsp;&nbsp; </span><span style="font-size: 11pt; font-family: 宋体">对预期结果作判断</span></p>
<p class="0d" style="margin-left: 45.25pt; text-indent: -21pt"><span lang="EN-US" style="font-family: Wingdings">&#220;</span><span lang="EN-US">&nbsp;&nbsp; </span><span style="font-size: 11pt; font-family: 宋体">提供测试装备的生成与销毁</span></p>
<p class="0d" style="margin-left: 45.25pt; text-indent: -21pt"><span lang="EN-US" style="font-family: Wingdings">&#220;</span><span lang="EN-US">&nbsp;&nbsp; </span><span style="font-size: 11pt; font-family: 宋体">易于组织与执行测试</span></p>
<p class="0d" style="margin-left: 45.25pt; text-indent: -21pt"><span lang="EN-US" style="font-family: Wingdings">&#220;</span><span lang="EN-US">&nbsp;&nbsp; </span><span style="font-size: 11pt; font-family: 宋体">图形与文字接口的测试器</span></p>
<p class="MsoNormal" style="text-indent: 22.6pt; line-height: 16pt"><span style="font-family: 宋体">要设定</span><span lang="EN-US">JUnit</span><span style="font-family: 宋体">，可先到</span> <span lang="EN-US" style="kkkk: blue">JUnit</span><span style="font-family: 宋体; kkkk: blue">官方网站</span><span lang="EN-US" style="kkkk: blue">(http://junit.org/)</span><span style="font-family: 宋体">下载</span><span lang="EN-US">JUnit</span><span style="font-family: 宋体">的</span><span lang="EN-US">zip</span><span style="font-family: 宋体">文件，下载后解开压缩文件，其中会含有</span><span lang="EN-US">junit.jar</span><span style="font-family: 宋体">文件，将这个文件复制到所要的数据夹中，然后设定</span><span lang="EN-US">Classpath</span><span style="font-family: 宋体">指向</span><span lang="EN-US">junit.jar</span><span style="font-family: 宋体">。例如：</span></p>
<pre style="margin: 6pt 0cm 0pt 24.25pt; line-height: 16pt"><span lang="EN-US">set classpath=%classpath%;YOUR_JUNIT_DIR\junit.jar</span></pre>
<p class="MsoNormal" style="text-indent: 22.6pt; line-height: 16pt"><span style="font-family: 宋体">如果是</span><span lang="EN-US">Windows 2000/XP</span><span style="font-family: 宋体">，可以在环境变量中设定</span><span lang="EN-US">Classpath</span><span style="font-family: 宋体">变量</span><span lang="EN-US">(</span><span style="font-family: 宋体">可参考附录</span><span lang="EN-US">A</span><span style="font-family: 宋体">中的</span><span lang="EN-US">Classpath</span><span style="font-family: 宋体">设置介绍</span><span lang="EN-US">)</span><span style="font-family: 宋体">。</span></p>
<p class="1-1"><span lang="EN-US" style="font-size: 21pt">B.</span><span lang="EN-US">3</span><span style="font-family: 宋体">　第一个</span><span lang="EN-US">JUnit</span><span style="font-family: 宋体">测试</span></p>
<p class="MsoNormal" style="text-indent: 22.6pt; line-height: 16pt"><span style="font-family: 宋体">要对程序进行测试，首先要设计测试案例</span><span lang="EN-US">(Test Case)</span><span style="font-family: 宋体">。一个测试案例是对程序给予假定条件，然后运行程序并看看在给定的条件下，程序的运行结果是否符合要求。</span></p>
<p class="MsoNormal" style="text-indent: 22.6pt; line-height: 16pt"><span style="font-family: 宋体">在</span><span lang="EN-US">JUnit</span><span style="font-family: 宋体">下，可以<span style="kkkk: blue">继承</span></span><span lang="EN-US" style="kkkk: blue">TestCase</span><span style="font-family: 宋体; kkkk: blue">来编写测试案例</span><span style="font-family: 宋体">，并定义测试方法，每一个<span style="kkkk: blue">测试方法是以</span></span><span lang="EN-US" style="kkkk: blue">testXXX()</span><span style="font-family: 宋体; kkkk: blue">来命名</span><span style="font-family: 宋体">。一个例子如下所示：</span></p>
<p class="MsoNormal" style="text-indent: 22.6pt; line-height: 16pt"><span lang="EN-US">&nbsp;</span></p>
<div style="padding-right: 0cm; padding-left: 0cm; padding-bottom: 1pt; border-top-style: none; padding-top: 0cm; border-bottom: blue 1pt solid; border-right-style: none; border-left-style: none">
<p class="03"><span lang="EN-US" style="font-family: Wingdings">&#220;</span><span lang="EN-US"> MathToolUnitTest.java</span><strong><span lang="EN-US"> </span></strong></p>
</div>
<p class="04" style="margin-left: 12.1pt"><span lang="EN-US">package test.onlyfun.caterpillar;</span></p>
<p class="04" style="margin-left: 12.1pt"><span lang="EN-US">&nbsp;</span></p>
<p class="04" style="margin-left: 12.1pt"><span lang="EN-US">import onlyfun.caterpillar.MathTool;</span></p>
<p class="04" style="margin-left: 12.1pt"><span lang="EN-US">import junit.framework.TestCase;</span></p>
<p class="04" style="margin-left: 12.1pt"><span lang="EN-US">&nbsp;</span></p>
<p class="04" style="margin-left: 12.1pt"><span lang="EN-US">public class MathToolUnitTest extends TestCase {</span></p>
<p class="04" style="margin-left: 12.1pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp; public void testGcd() {</span></p>
<p class="04" style="margin-left: 12.1pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; assertEquals(5, MathTool.gcd(10, 5));</span></p>
<p class="04" style="margin-left: 12.1pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp; }</span></p>
<p class="04" style="margin-left: 12.1pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp; </span></p>
<p class="04" style="margin-left: 12.1pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp; public static void main(String[] args) {</span></p>
<p class="04" style="margin-left: 12.1pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; junit.textui.TestRunner.run(MathToolUnitTest.class);</span></p>
<p class="04" style="margin-left: 12.1pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp; }</span></p>
<div style="padding-right: 0cm; padding-left: 0cm; padding-bottom: 1pt; margin-left: 1.45pt; border-top-style: none; margin-right: 0cm; padding-top: 0cm; border-bottom: blue 1pt solid; border-right-style: none; border-left-style: none">
<p class="05" style="margin-left: 0cm; text-indent: 8pt"><span lang="EN-US">}</span></p>
</div>
<p class="MsoNormal" style="text-indent: 22.6pt"><span lang="EN-US">assertEquals()</span><span style="font-family: 宋体">方法用来断定您的预期值与单元方法实际的返回结果是否相同，如果预期值与返回的结果不同则丢出异常，</span><span lang="EN-US">TestRunner</span><span style="font-family: 宋体">会捕捉异常，并提取其中的相关信息以报告测试结果。这里使用的是文字模式的</span><span lang="EN-US">TestRunner</span><span style="font-family: 宋体">。</span></p>
<p class="MsoNormal" style="text-indent: 21.8pt"><span style="font-family: 宋体; letter-spacing: 0.2pt">接下来根据测试案例编写实际的程序，首先试着让测试案例能通过编译：</span></p>
<pre style="margin: 6pt 0cm 0pt 24.25pt"><span lang="EN-US">package onlyfun.caterpillar;</span></pre>
<pre style="margin-left: 24.25pt"><span lang="EN-US">&nbsp;</span></pre>
<pre style="margin-left: 24.25pt"><span lang="EN-US">public class MathTool {</span></pre>
<pre style="margin-left: 24.25pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp; public static int gcd(int num1, int num2) {</span><span lang="EN-US"> </span></pre>
<pre style="margin-left: 24.25pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return 0;</span></pre>
<pre style="margin-left: 24.25pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp; }</span></pre>
<pre style="margin-left: 24.25pt"><span lang="EN-US">}</span></pre>
<p class="MsoNormal" style="text-indent: 22.6pt"><span style="font-family: 宋体">编译完</span><span lang="EN-US">MathTool.java</span><span style="font-family: 宋体">并用</span><span lang="EN-US">javac</span><span style="font-family: 宋体">来编译它。在编译完成之后，接着运行测试案例，会得到以下的结果：</span></p>
<pre style="margin: 6pt 0cm 0pt 24.25pt"><span lang="EN-US">.F</span></pre>
<pre style="margin-left: 24.25pt"><span lang="EN-US">Time: 0</span></pre>
<pre style="margin-left: 24.25pt"><span lang="EN-US">There was 1 failure:</span></pre>
<pre style="margin-left: 24.25pt"><span lang="EN-US">1) testGcd(test.onlyfun.caterpillar.MathToolUnitTest)junit.framework.AssertionFa</span></pre>
<pre style="margin-left: 24.25pt"><span lang="EN-US">iledError: expected:&lt;5&gt; but was:&lt;0&gt;</span></pre>
<pre style="margin-left: 24.25pt"><span lang="EN-US">...</span><span style="font-family: 宋体">略</span></pre>
<pre style="margin-left: 24.25pt"><span lang="EN-US">FAILURES!!!</span></pre>
<pre style="margin-left: 24.25pt"><span lang="EN-US">Tests run: 1,&nbsp; Failures: 1,&nbsp; Errors: 0</span></pre>
<p class="MsoNormal" style="text-indent: 22.6pt"><span style="font-family: 宋体">由于</span><span lang="EN-US">MathTool</span><span style="font-family: 宋体">中并没有编写什么实际的逻辑，所以测试失败。在测试驱动中，测试案例所报告的结果通常是以测试失败作为开始，您的挑战就是要一步步消除这些失败的信息。接下来根据测试案例，完成所设计的程序：</span></p>
<div style="padding-right: 0cm; padding-left: 0cm; padding-bottom: 1pt; border-top-style: none; padding-top: 0cm; border-bottom: blue 1pt solid; border-right-style: none; border-left-style: none">
<p class="03"><span lang="EN-US" style="font-family: Wingdings">&#220;</span><span lang="EN-US"> MathTool.java</span><strong><span lang="EN-US"> </span></strong></p>
</div>
<p class="04" style="margin-left: 12.1pt"><span lang="EN-US">package onlyfun.caterpillar;</span></p>
<p class="04" style="margin-left: 12.1pt"><span lang="EN-US">&nbsp;</span></p>
<p class="04" style="margin-left: 12.1pt"><span lang="EN-US">public class MathTool {</span></p>
<p class="04" style="margin-left: 12.1pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp; public static int gcd(int num1, int num2) {</span><span lang="EN-US"> </span></p>
<p class="04" style="margin-left: 12.1pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int r = 0;</span><span lang="EN-US"> </span></p>
<p class="04" style="margin-left: 12.1pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while(num2 != 0) {</span><span lang="EN-US"> </span></p>
<p class="04" style="margin-left: 12.1pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; r = num1 % num2;</span><span lang="EN-US"> </span></p>
<p class="04" style="margin-left: 12.1pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; num1 = num2;</span><span lang="EN-US"> </span></p>
<p class="04" style="margin-left: 12.1pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; num2 = r;</span><span lang="EN-US"> </span></p>
<p class="04" style="margin-left: 12.1pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span><span lang="EN-US"> </span></p>
<p class="04" style="margin-left: 12.1pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return num1;</span><span lang="EN-US"> </span></p>
<p class="04" style="margin-left: 12.1pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp; }</span></p>
<div style="padding-right: 0cm; padding-left: 0cm; padding-bottom: 1pt; margin-left: 1.45pt; border-top-style: none; margin-right: 0cm; padding-top: 0cm; border-bottom: blue 1pt solid; border-right-style: none; border-left-style: none">
<p class="05" style="margin-left: 0cm; text-indent: 8pt"><span lang="EN-US">}</span></p>
</div>
<p class="MsoNormal" style="text-indent: 22.6pt"><span style="font-family: 宋体">再次运行测试案例，会得到以下的结果，通过最后的</span><span lang="EN-US">OK</span><span style="font-family: 宋体">信息，知道测试已经成功：</span></p>
<pre style="margin: 6pt 0cm 0pt 24.25pt"><span lang="EN-US">.Time: 0</span></pre>
<pre style="margin-left: 24.25pt"><span lang="EN-US">&nbsp;</span></pre>
<pre style="margin-left: 24.25pt"><span lang="EN-US">OK (1 test)</span></pre>
<p class="MsoNormal" style="text-indent: 22.6pt"><span style="font-family: 宋体">不一定要在</span><span lang="EN-US">main()</span><span style="font-family: 宋体">中指定</span><span lang="EN-US">TestRunner</span><span style="font-family: 宋体">，而可以直接启动一个</span><span lang="EN-US">TestRunner</span><span style="font-family: 宋体">，并指定测试案例类</span><span lang="EN-US">(</span><span style="font-family: 宋体">继承</span><span lang="EN-US">TestCase</span><span style="font-family: 宋体">的类</span><span lang="EN-US">)</span><span style="font-family: 宋体">。例如启动一个</span><span lang="EN-US">Swing</span><span style="font-family: 宋体">窗口的测试结果画面：</span></p>
<pre style="margin: 6pt 0cm 0pt 24.25pt"><span lang="EN-US">java junit.swingui.TestRunner test.onlyfun.caterpillar.MathToolUnitTest</span></pre>
<p class="MsoNormal" style="text-indent: 22.6pt"><span style="font-family: 宋体">执行的结果画面如图</span><span lang="EN-US">B-1</span><span style="font-family: 宋体">所示。</span></p>
<p class="MsoNormal" style="text-indent: 22.6pt"><span style="font-family: 宋体">在</span><span lang="EN-US">Swing</span><span style="font-family: 宋体">窗口的测试结果显示中，如果中间的横棒是显示绿色，表示所有的测试都已经成功，如果中间的横棒显示红色，表示测试失败。</span><span lang="EN-US">JUnit</span><span style="font-family: 宋体">的名言</span><span style="font-family: 宋体; letter-spacing: 0.5pt">是</span><span lang="EN-US" style="letter-spacing: 0.5pt; kkkk: blue">Keep the bar green to keep the code clean</span><span style="font-family: 宋体; letter-spacing: 0.5pt">，意思是保持绿色横棒以保证测试成功。</span></p>
<p class="MsoNormal" style="text-indent: 22.6pt"><span style="font-family: 宋体">也可以指定文字模式的测试结果。例如：</span></p>
<pre style="margin: 6pt 0cm 0pt 24.25pt"><span lang="EN-US">java junit.textui.TestRunner test.onlyfun.caterpillar.MathToolUnitTest</span></pre>
<p class="MsoNormal" style="text-indent: 0.65pt; line-height: 125%; text-align: center"><span lang="EN-US"><img height="312" alt="" src="http://book.csdn.net/BookFiles/135/0b/image002.jpg" width="300" /></span></p>
<p align="center"><span style="font-family: 宋体">图</span><span lang="EN-US" style="font-family: 'Times New Roman'">B-1&nbsp; JUnit</span><span style="font-family: 宋体">的</span><span lang="EN-US" style="font-family: 'Times New Roman'">Swing</span><span style="font-family: 宋体">窗口测试</span><span style="font-family: 宋体">结果</span></p>
<p class="1-1"><span lang="EN-US" style="font-size: 21pt">B</span><span lang="EN-US">.4</span><span style="font-family: 宋体">　自动构建与测试</span></p>
<p class="MsoNormal" style="text-indent: 22.6pt"><span lang="EN-US">Ant</span><span style="font-family: 宋体">可以进行自动化构建，而</span><span lang="EN-US">JUnit</span><span style="font-family: 宋体">可以进行自动化测试，</span><span lang="EN-US">Ant</span><span style="font-family: 宋体">可以与</span><span lang="EN-US">JUnit</span><span style="font-family: 宋体">结合，使得自动化的构建与测试变得可行。</span></p>
<p class="MsoNormal" style="text-indent: 22.6pt"><span style="font-family: 宋体">如果要让</span><span lang="EN-US">Ant</span><span style="font-family: 宋体">能支持</span><span lang="EN-US">JUnit</span><span style="font-family: 宋体">，建议直接将</span><span lang="EN-US">JUnit</span><span style="font-family: 宋体">的</span><span lang="EN-US">junit.jar</span><span style="font-family: 宋体">放置在</span><span lang="EN-US">Ant</span><span style="font-family: 宋体">的</span><span lang="EN-US">lib</span><span style="font-family: 宋体">目录，并记得改变</span><span lang="EN-US">Classpath</span><span style="font-family: 宋体">中原先有关</span><span lang="EN-US">junit.jar</span><span style="font-family: 宋体">的设定。例如将</span><span lang="EN-US">Classpath</span><span style="font-family: 宋体">重新指向</span><span lang="EN-US">%ANT_HOME%\lib\junit.jar(</span><span style="font-family: 宋体">假设已经如附录</span><span lang="EN-US">A</span><span style="font-family: 宋体">中设置了</span><span lang="EN-US">ant_home</span><span style="font-family: 宋体">的环境变量</span><span lang="EN-US">)</span><span style="font-family: 宋体">。虽然也有其他的方式可以设定，但这是最快也是最简单的方法。</span></p>
<p class="MsoNormal" style="text-indent: 22.6pt"><span lang="EN-US">Ant</span><span style="font-family: 宋体">使用</span><span lang="EN-US">&lt;junit&gt;</span><span style="font-family: 宋体">标签来设定</span><span lang="EN-US">JUnit</span><span style="font-family: 宋体">测试，下面是一个简单的例子：</span></p>
<div style="padding-right: 0cm; padding-left: 0cm; padding-bottom: 1pt; border-top-style: none; padding-top: 0cm; border-bottom: blue 1pt solid; border-right-style: none; border-left-style: none">
<p class="03" style="margin-top: 0cm; line-height: 6pt"><span lang="EN-US">&nbsp;</span></p>
</div>
<p class="04" style="margin-left: 12.1pt"><span lang="EN-US">&lt;?xml version="1.0"?&gt;</span></p>
<p class="04" style="margin-left: 12.1pt"><span lang="EN-US">&lt;project name="autoBuildTest" default="test"&gt;</span><span lang="EN-US"> </span></p>
<p class="04" style="margin-left: 12.1pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp; &lt;target name="setProperties"&gt;</span><span lang="EN-US"> </span></p>
<p class="04" style="margin-left: 12.1pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="src.dir" value="src"/&gt;</span><span lang="EN-US"> </span></p>
<p class="04" style="margin-left: 12.1pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="classes.dir" value="classes"/&gt;</span><span lang="EN-US"> </span></p>
<p class="04" style="margin-left: 12.1pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp; &lt;/target&gt;</span><span lang="EN-US"> </span></p>
<p class="04" style="margin-left: 12.1pt; line-height: 12pt"><span lang="EN-US">&nbsp;</span></p>
<p class="04" style="margin-left: 12.1pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp; &lt;target name="prepareDir" depends="setProperties"&gt;</span><span lang="EN-US"> </span></p>
<p class="04" style="margin-left: 12.1pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;delete dir="${classes.dir}"/&gt;</span><span lang="EN-US"> </span></p>
<p class="04" style="margin-left: 12.1pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;mkdir dir="${classes.dir}"/&gt;</span><span lang="EN-US"> </span></p>
<p class="04" style="margin-left: 12.1pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp; &lt;/target&gt;</span><span lang="EN-US"> </span></p>
<p class="04" style="margin-left: 12.1pt; line-height: 12pt"><span lang="EN-US">&nbsp;</span></p>
<p class="04" style="margin-left: 12.1pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp; &lt;target name="compile" depends="prepareDir"&gt;</span><span lang="EN-US"> </span></p>
<p class="04" style="margin-left: 12.1pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;javac srcdir="${src.dir}" destdir="${classes.dir}"/&gt;</span><span lang="EN-US"> </span></p>
<p class="04" style="margin-left: 12.1pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp; &lt;/target&gt;</span><span lang="EN-US"> </span></p>
<p class="04" style="margin-left: 12.1pt"><span lang="EN-US">&nbsp;</span></p>
<p class="04" style="margin-left: 12.1pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp; &lt;target name="test" depends="compile"&gt;</span><span lang="EN-US"> </span></p>
<p class="04" style="margin-left: 12.1pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;junit printsummary="yes"&gt;</span><span lang="EN-US"> </span></p>
<p class="04" style="margin-left: 12.1pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;test</span><span lang="EN-US"> </span></p>
<p class="04" style="margin-left: 12.1pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; name="test.onlyfun.caterpillar.MathToolUnitTest"/&gt;</span><span lang="EN-US"> </span></p>
<p class="04" style="margin-left: 12.1pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;classpath&gt;</span><span lang="EN-US"> </span></p>
<p class="04" style="margin-left: 12.1pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;pathelement location="${classes.dir}"/&gt;</span><span lang="EN-US"> </span></p>
<p class="04" style="margin-left: 12.1pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/classpath&gt;</span><span lang="EN-US"> </span></p>
<p class="04" style="margin-left: 12.1pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/junit&gt;</span><span lang="EN-US"> </span></p>
<p class="04" style="margin-left: 12.1pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp; &lt;/target&gt;</span><span lang="EN-US"> </span></p>
<div style="padding-right: 0cm; padding-left: 0cm; padding-bottom: 1pt; margin-left: 1.45pt; border-top-style: none; margin-right: 0cm; padding-top: 0cm; border-bottom: blue 1pt solid; border-right-style: none; border-left-style: none">
<p class="05" style="margin-left: 0cm; text-indent: 8pt"><span lang="EN-US">&lt;/project&gt;</span></p>
</div>
<p class="MsoNormal" style="text-indent: 22.6pt"><span lang="EN-US" style="kkkk: blue">printsummary</span><span style="font-family: 宋体; kkkk: blue">属性</span><span style="font-family: 宋体">会将测试的结果简单地显示出来，</span><span lang="EN-US">&lt;test&gt;</span><span style="font-family: 宋体">的</span><span lang="EN-US">name</span><span style="font-family: 宋体">属性是设定所要进行测试的测试案例类。</span><span lang="EN-US">Ant</span><span style="font-family: 宋体">构建与调用</span><span lang="EN-US">JUnit</span><span style="font-family: 宋体">进行测试的信息如下：</span></p>
<pre style="margin: 6pt 0cm 0pt 24.25pt"><span lang="EN-US">C:\workspace\B&gt;ant</span></pre>
<pre style="margin-left: 24.25pt"><span lang="EN-US">Buildfile: build.xml</span></pre>
<pre style="margin-left: 24.25pt"><span lang="EN-US">&nbsp;</span></pre>
<pre style="margin-left: 24.25pt"><span lang="EN-US">setProperties:</span></pre>
<pre style="margin-left: 27.25pt"><strong><em><span lang="EN-US">&nbsp;</span></em></strong></pre>
<pre style="margin-left: 24.25pt"><span lang="EN-US">prepareDir:</span></pre>
<pre style="margin-left: 24.25pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp; [mkdir] Created dir: C:\workspace\B\classes</span></pre>
<pre style="margin-left: 24.25pt"><span lang="EN-US">&nbsp;</span></pre>
<pre style="margin-left: 24.25pt"><span lang="EN-US">compile:</span></pre>
<pre style="margin-left: 24.25pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp; [javac] Compiling 4 source files to C:\workspace\B\classes</span></pre>
<pre style="margin-left: 24.25pt"><span lang="EN-US">&nbsp;</span></pre>
<pre style="margin-left: 24.25pt"><span lang="EN-US">test:</span></pre>
<pre style="margin-left: 24.25pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp; [junit] Running test.onlyfun.caterpillar.MathToolUnitTest</span></pre>
<pre style="margin-left: 24.25pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp; [junit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0 sec</span></pre>
<pre style="margin-left: 24.25pt"><span lang="EN-US">&nbsp;</span></pre>
<pre style="margin-left: 24.25pt"><span lang="EN-US">BUILD SUCCESSFUL</span></pre>
<pre style="margin-left: 24.25pt"><span lang="EN-US">Total time: 1 second</span></pre>
<!-- page --><br />
<p class="1-1"><span lang="EN-US" style="font-size: 21pt">B.</span><span lang="EN-US">5</span><span style="font-family: 宋体">　自动生成测试报告</span></p>
<p class="MsoNormal" style="text-indent: 22.6pt"><span style="font-family: 宋体">接上一个主题，可以将</span><span lang="EN-US">JUnit</span><span style="font-family: 宋体">的测试过程在</span><span lang="EN-US">Ant</span><span style="font-family: 宋体">构建过程中显示出来，只要加入</span><span lang="EN-US" style="kkkk: blue">&lt; formatter&gt;</span><span style="font-family: 宋体; kkkk: blue">标签</span><span style="font-family: 宋体">设定即可：</span></p>
<pre style="margin: 6pt 0cm 0pt 24.25pt"><span lang="EN-US">&lt;?xml version="1.0"?&gt;</span></pre>
<pre style="margin-left: 24.25pt"><span lang="EN-US">&lt;project name="autoBuildTest" default="test"&gt;</span></pre>
<pre style="margin-left: 24.25pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp; ...</span></pre>
<pre style="margin-left: 24.25pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp; &lt;target name="test" depends="compile"&gt;</span><span lang="EN-US"> </span></pre>
<pre style="margin-left: 24.25pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;junit printsummary="yes"&gt;</span><span lang="EN-US"> </span></pre>
<pre style="margin-left: 24.25pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;formatter type="plain" usefile="false"/&gt;</span></pre>
<pre style="margin-left: 24.25pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;test</span><span lang="EN-US"> </span></pre>
<pre style="margin-left: 24.25pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;name="test.onlyfun.caterpillar.MathToolUnitTest"/&gt;</span><span lang="EN-US"> </span></pre>
<pre style="margin-left: 24.25pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;classpath&gt;</span><span lang="EN-US"> </span></pre>
<pre style="margin-left: 24.25pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;pathelement location="${classes.dir}"/&gt;</span><span lang="EN-US"> </span></pre>
<pre style="margin-left: 24.25pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/classpath&gt;</span><span lang="EN-US"> </span></pre>
<pre style="margin-left: 24.25pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/junit&gt;</span><span lang="EN-US"> </span></pre>
<pre style="margin-left: 24.25pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&lt;/target&gt;</span></pre>
<pre style="margin-left: 24.25pt"><span lang="EN-US">&lt;/project&gt;</span></pre>
<p class="MsoNormal" style="text-indent: 22.6pt"><span lang="EN-US">Ant</span><span style="font-family: 宋体">构建与调用</span><span lang="EN-US">JUnit</span><span style="font-family: 宋体">进行测试的信息如下：</span></p>
<pre style="margin: 6pt 0cm 0pt 24.25pt"><span lang="EN-US">C:\workspace\B&gt;ant</span></pre>
<pre style="margin-left: 24.25pt; line-height: 13pt"><span lang="EN-US">Buildfile: build.xml</span></pre>
<pre style="margin-left: 27.25pt; line-height: 13pt"><strong><em><span lang="EN-US">&nbsp;</span></em></strong></pre>
<pre style="margin-left: 24.25pt; line-height: 13pt"><span lang="EN-US">setProperties:</span></pre>
<pre style="margin-left: 24.25pt; line-height: 13pt"><span lang="EN-US">&nbsp;</span></pre>
<pre style="margin-left: 24.25pt; line-height: 13pt"><span lang="EN-US">prepareDir:</span></pre>
<pre style="margin-left: 24.25pt; line-height: 13pt"><span lang="EN-US">&nbsp;&nbsp; [delete] Deleting directory C:\workspace\B\classes</span></pre>
<pre style="margin-left: 24.25pt; line-height: 13pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp; [mkdir] Created dir: C:\workspace\B\classes</span></pre>
<pre style="margin-left: 24.25pt; line-height: 13pt"><span lang="EN-US">&nbsp;</span></pre>
<pre style="margin-left: 24.25pt; line-height: 13pt"><span lang="EN-US">compile:</span></pre>
<pre style="margin-left: 24.25pt; line-height: 13pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp; [javac] Compiling 4 source files to C:\workspace\B\classes</span></pre>
<pre style="margin-left: 24.25pt; line-height: 13pt"><span lang="EN-US">&nbsp;</span></pre>
<pre style="margin-left: 24.25pt; line-height: 13pt"><span lang="EN-US">test:</span></pre>
<pre style="margin-left: 24.25pt; line-height: 13pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp; [junit] Running test.onlyfun.caterpillar.MathToolUnitTest</span></pre>
<pre style="margin-left: 24.25pt; line-height: 13pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp; [junit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0.016 sec</span></pre>
<pre style="margin-left: 24.25pt; line-height: 13pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp; [junit] Testsuite: test.onlyfun.caterpillar.MathToolUnitTest</span></pre>
<pre style="margin-left: 24.25pt; line-height: 13pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp; [junit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0.016 sec</span></pre>
<pre style="margin-left: 24.25pt; line-height: 13pt"><span lang="EN-US">&nbsp;</span></pre>
<pre style="margin-left: 24.25pt; line-height: 13pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp; [junit] Testcase: testGcd took 0.016 sec</span></pre>
<pre style="margin-left: 24.25pt; line-height: 13pt"><span lang="EN-US">&nbsp;</span></pre>
<pre style="margin-left: 24.25pt; line-height: 13pt"><span lang="EN-US">BUILD SUCCESSFUL</span></pre>
<pre style="margin-left: 24.25pt; line-height: 13pt"><span lang="EN-US">Total time: 2 seconds</span></pre>
<p class="MsoNormal" style="text-indent: 22.6pt"><span style="font-family: 宋体">当</span><span lang="EN-US" style="kkkk: blue">usefile</span><span style="font-family: 宋体; kkkk: blue">属性设定为</span><span lang="EN-US" style="kkkk: blue">true</span><span style="font-family: 宋体">时，会自动将产生的结果保存在文件中，默认是</span><span lang="EN-US" style="letter-spacing: 0.3pt">TEST-*.txt</span><span style="font-family: 宋体; letter-spacing: 0.3pt">。其中</span><span lang="EN-US" style="letter-spacing: 0.3pt">*</span><span style="font-family: 宋体; letter-spacing: 0.3pt">是测试案例类名称。就上例而言，所产生的报告文件内容如下：</span></p>
<pre style="margin: 6pt 0cm 0pt 24.25pt"><span lang="EN-US">Testsuite: test.onlyfun.caterpillar.MathToolUnitTest</span></pre>
<pre style="margin-left: 24.25pt"><span lang="EN-US">Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0 sec</span></pre>
<pre style="margin-left: 24.25pt"><span lang="EN-US">&nbsp;</span></pre>
<pre style="margin-left: 24.25pt"><span lang="EN-US">Testcase: testGcd took 0 sec</span></pre>
<p class="MsoNormal" style="text-indent: 22.6pt"><span lang="EN-US">&lt;formatter&gt;</span><span style="font-family: 宋体">标签还可以设定将测试的结果，以</span><span lang="EN-US">XML</span><span style="font-family: 宋体">文件保存下来。一个编写的例子如下，它将测试的结果保存至</span><span lang="EN-US">report</span><span style="font-family: 宋体">目录中，</span> <span style="font-family: 宋体">文件名称为</span><span lang="EN-US">TEST-*.xml</span><span style="font-family: 宋体">，</span><span lang="EN-US">*</span><span style="font-family: 宋体">是测试案例类名称：</span></p>
<pre style="margin: 6pt 0cm 0pt 24.25pt"><strong><em><span lang="EN-US">&lt;</span></em></strong><span lang="EN-US">?xml version="1.0"?&gt;</span></pre>
<pre style="margin-left: 24.25pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp; ...</span></pre>
<pre style="margin-left: 24.25pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp; &lt;target name="test" depends="compile"&gt;</span><span lang="EN-US"> </span></pre>
<pre style="margin-left: 24.25pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;junit printsummary="yes"&gt;</span><span lang="EN-US"> </span></pre>
<pre style="margin-left: 24.25pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="kkkk: blue">&nbsp;&lt;formatter type="xml"/&gt;</span></span></pre>
<pre style="margin-left: 24.25pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;test</span><span lang="EN-US"> </span></pre>
<pre style="margin-left: 24.25pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;name="test.onlyfun.caterpillar.MathToolUnitTest"/&gt;</span><span lang="EN-US"> </span></pre>
<pre style="margin-left: 24.25pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;classpath&gt;</span><span lang="EN-US"> </span></pre>
<pre style="margin-left: 24.25pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;pathelement location="${classes.dir}"/&gt;</span><span lang="EN-US"> </span></pre>
<pre style="margin-left: 24.25pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/classpath&gt;</span><span lang="EN-US"> </span></pre>
<pre style="margin-left: 24.25pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/junit&gt;</span><span lang="EN-US"> </span></pre>
<pre style="margin-left: 24.25pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&lt;/target&gt;</span></pre>
<pre style="margin-left: 24.25pt"><span lang="EN-US">&lt;/project&gt;</span></pre>
<p class="MsoNormal" style="text-indent: 22.6pt"><span style="font-family: 宋体">也可以将测试结果所产生的</span><span lang="EN-US">XML</span><span style="font-family: 宋体">文件转换为</span><span lang="EN-US">HTML</span><span style="font-family: 宋体">文件，使用</span><span lang="EN-US">Ant</span><span style="font-family: 宋体">可以直接完成这个工作。</span><span lang="EN-US" style="kkkk: blue">&lt;junitreport&gt;</span><span style="font-family: 宋体; kkkk: blue">标签使用</span><span lang="EN-US" style="kkkk: blue"> XSLT</span><span style="font-family: 宋体; kkkk: blue">将</span><span lang="EN-US" style="kkkk: blue">XML</span><span style="font-family: 宋体; kkkk: blue">文件转换为</span><span lang="EN-US" style="kkkk: blue">HTML</span><span style="font-family: 宋体; kkkk: blue">文件</span><span style="font-family: 宋体">。下面的例子将前面的说明作个总结，以完整呈现编写的实例：</span></p>
<div style="padding-right: 0cm; padding-left: 0cm; padding-bottom: 1pt; border-top-style: none; padding-top: 0cm; border-bottom: blue 1pt solid; border-right-style: none; border-left-style: none">
<p class="03"><span lang="EN-US" style="font-family: Wingdings">&#220;</span><span lang="EN-US"> build.xml</span></p>
</div>
<p class="04" style="margin-left: 12.1pt"><span lang="EN-US">&lt;?xml version="1.0"?&gt;</span></p>
<p class="04" style="margin-left: 12.1pt"><span lang="EN-US">&lt;project name="autoBuildTest" default="report"&gt;</span><span lang="EN-US"> </span></p>
<p class="04" style="margin-left: 12.1pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp; &lt;target name="setProperties"&gt;</span><span lang="EN-US"> </span></p>
<p class="04" style="margin-left: 12.1pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="src.dir" value="src"/&gt;</span><span lang="EN-US"> </span></p>
<p class="04" style="margin-left: 12.1pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="classes.dir" value="classes"/&gt;</span><span lang="EN-US"> </span></p>
<p class="04" style="margin-left: 12.1pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="report.dir" value="report"/&gt;</span><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></p>
<p class="04" style="margin-left: 12.1pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp; &lt;/target&gt;</span><span lang="EN-US"> </span></p>
<p class="04" style="margin-left: 12.1pt"><span lang="EN-US">&nbsp;</span></p>
<p class="04" style="margin-left: 12.1pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp; &lt;target name="prepareDir" depends="setProperties"&gt;</span><span lang="EN-US"> </span></p>
<p class="04" style="margin-left: 12.1pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;delete dir="${report.dir}"/&gt;</span><span lang="EN-US"> </span></p>
<p class="04" style="margin-left: 12.1pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;delete dir="${classes.dir}"/&gt;</span><span lang="EN-US"> </span></p>
<p class="04" style="margin-left: 12.1pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;mkdir dir="${report.dir}"/&gt;</span><span lang="EN-US"> </span></p>
<p class="04" style="margin-left: 12.1pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;mkdir dir="${classes.dir}"/&gt;</span><span lang="EN-US"> </span></p>
<p class="04" style="margin-left: 12.1pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp; &lt;/target&gt;</span><span lang="EN-US"> </span></p>
<p class="04" style="margin-left: 12.1pt"><span lang="EN-US">&nbsp;</span></p>
<p class="04" style="margin-left: 12.1pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp; &lt;target name="compile" depends="prepareDir"&gt;</span><span lang="EN-US"> </span></p>
<p class="04" style="margin-left: 12.1pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;javac srcdir="${src.dir}" destdir="${classes.dir}"/&gt;</span><span lang="EN-US"> </span></p>
<p class="04" style="margin-left: 12.1pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp; &lt;/target&gt;</span><span lang="EN-US">&nbsp; </span></p>
<p class="04" style="margin-left: 12.1pt"><span lang="EN-US">&nbsp;</span></p>
<p class="04" style="margin-left: 12.1pt; line-height: 13.2pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp; &lt;target name="test" depends="compile"&gt;</span><span lang="EN-US"> </span></p>
<p class="04" style="margin-left: 12.1pt; line-height: 13.2pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;junit printsummary="yes"&gt;</span><span lang="EN-US"> </span></p>
<p class="04" style="margin-left: 12.1pt; line-height: 13.2pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;formatter type="xml"/&gt;</span></p>
<p class="04" style="margin-left: 12.1pt; line-height: 13.2pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;test</span><span lang="EN-US"> </span></p>
<p class="04" style="margin-left: 12.1pt; line-height: 13.2pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; name="test.onlyfun.caterpillar.MathToolUnitTest"/&gt;</span><span lang="EN-US"> </span></p>
<p class="04" style="margin-left: 12.1pt; line-height: 13.2pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;classpath&gt;</span><span lang="EN-US"> </span></p>
<p class="04" style="margin-left: 12.1pt; line-height: 13.2pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;pathelement location="${classes.dir}"/&gt;</span><span lang="EN-US"> </span></p>
<p class="04" style="margin-left: 12.1pt; line-height: 13.2pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/classpath&gt;</span><span lang="EN-US"> </span></p>
<p class="04" style="margin-left: 12.1pt; line-height: 13.2pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/junit&gt;</span><span lang="EN-US"> </span></p>
<p class="04" style="margin-left: 12.1pt; line-height: 13.2pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp; &lt;/target&gt;</span></p>
<p class="04" style="margin-left: 12.1pt; line-height: 13.2pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp; </span></p>
<p class="04" style="margin-left: 12.1pt; line-height: 13.2pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp; &lt;target name="report" depends="test"&gt;</span><span lang="EN-US"> </span></p>
<p class="04" style="margin-left: 12.1pt; line-height: 13.2pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;junitreport todir="${report.dir}"&gt;</span><span lang="EN-US"> </span></p>
<p class="04" style="margin-left: 12.1pt; line-height: 13.2pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;fileset dir="${report.dir}"&gt;</span><span lang="EN-US"> </span></p>
<p class="04" style="margin-left: 12.1pt; line-height: 13.2pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;include name="TEST-*.xml"/&gt;</span><span lang="EN-US"> </span></p>
<p class="04" style="margin-left: 12.1pt; line-height: 13.2pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/fileset&gt;</span><span lang="EN-US"> </span></p>
<p class="04" style="margin-left: 12.1pt; line-height: 13.2pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;report</span><span lang="EN-US"> </span></p>
<p class="04" style="margin-left: 12.1pt; line-height: 13.2pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;format="frames" todir="${report.dir}/html"/&gt;</span><span lang="EN-US"> </span></p>
<p class="04" style="margin-left: 12.1pt; line-height: 13.2pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/junitreport&gt;</span><span lang="EN-US"> </span></p>
<p class="04" style="margin-left: 12.1pt; line-height: 13.2pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp; &lt;/target&gt;</span><span lang="EN-US">&nbsp;&nbsp;&nbsp; </span></p>
<div style="padding-right: 0cm; padding-left: 0cm; padding-bottom: 1pt; margin-left: 1.45pt; border-top-style: none; margin-right: 0cm; padding-top: 0cm; border-bottom: blue 1pt solid; border-right-style: none; border-left-style: none">
<p class="05" style="margin-left: 0cm; text-indent: 8pt"><span lang="EN-US">&lt;/project&gt;</span></p>
</div>
<p class="MsoNormal" style="text-indent: 22.6pt"><span lang="EN-US">&lt;include&gt;</span><span style="font-family: 宋体">设定搜寻</span><span lang="EN-US">TEST-*.xml</span><span style="font-family: 宋体">文件，将之转换为</span><span lang="EN-US">HTML</span><span style="font-family: 宋体">文件，而最后的结果被设定保存至</span><span lang="EN-US">report/html/</span><span style="font-family: 宋体">目录下，在</span><span lang="EN-US">format</span><span style="font-family: 宋体">属性中设定了</span><span lang="EN-US">HTML</span><span style="font-family: 宋体">文件具有边框</span><span lang="EN-US">(Frame)</span><span style="font-family: 宋体">，如果不设定这个属性，则</span><span lang="EN-US">HTML</span><span style="font-family: 宋体">报告文件就不具有边框。在运行</span><span lang="EN-US">Ant</span><span style="font-family: 宋体">之后所产生的</span><span lang="EN-US"> HTML</span><span style="font-family: 宋体">测试结果报告文件如图</span><span lang="EN-US">B-2</span><span style="font-family: 宋体">所示。</span></p>
<p class="MsoNormal" style="text-indent: 0.65pt; line-height: 125%; text-align: center"><span lang="EN-US"><img height="224" alt="" src="http://book.csdn.net/BookFiles/135/0b/image003.jpg" width="336" /></span></p>
<p align="center"><span style="font-family: 宋体">图</span><span lang="EN-US" style="font-family: 'Times New Roman'">B-2&nbsp; Ant</span><span style="font-family: 宋体">结合</span><span lang="EN-US" style="font-family: 'Times New Roman'">JUnit</span><span style="font-family: 宋体">所自动产生的测试报告</span></p>
<p class="MsoNormal" style="text-indent: 22.6pt"><span style="font-family: 宋体">附录</span><span lang="EN-US">B</span><span style="font-family: 宋体">只是对</span><span lang="EN-US">JUnit</span><span style="font-family: 宋体">的一些简介，如果需要更多有关</span><span lang="EN-US">JUnit</span><span style="font-family: 宋体">的资料，可以参考以下的网址：</span></p>
<p class="0d" style="margin-left: 46.85pt; text-indent: -22.6pt"><span lang="EN-US" style="kkkk: blue">http://caterpillar.onlyfun.net/Gossip/JUnit/JUnitGossip.htm</span></p>
<!-- page --><!-- page -->
<img src ="http://www.blogjava.net/yglwxl/aggbug/173543.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yglwxl/" target="_blank">九宝</a> 2008-01-08 10:03 <a href="http://www.blogjava.net/yglwxl/archive/2008/01/08/173543.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java 中的位运算 (转)</title><link>http://www.blogjava.net/yglwxl/archive/2008/01/08/173540.html</link><dc:creator>九宝</dc:creator><author>九宝</author><pubDate>Tue, 08 Jan 2008 01:56:00 GMT</pubDate><guid>http://www.blogjava.net/yglwxl/archive/2008/01/08/173540.html</guid><wfw:comment>http://www.blogjava.net/yglwxl/comments/173540.html</wfw:comment><comments>http://www.blogjava.net/yglwxl/archive/2008/01/08/173540.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yglwxl/comments/commentRss/173540.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yglwxl/services/trackbacks/173540.html</trackback:ping><description><![CDATA[<p><strong>移位运算符</strong></p>
<p>&nbsp;&nbsp;&nbsp; 包括：<br />
&nbsp;&nbsp;&nbsp; &#8220;&gt;&gt; 右移&#8221;；&#8220;&lt;&lt; 左移&#8221;；&#8220;&gt;&gt;&gt; 无符号右移&#8221;</p>
<p>例子：<br />
-5&gt;&gt;3=-1<br />
1111 1111 1111 1111 1111 1111 1111 1011<br />
1111 1111 1111 1111 1111 1111 1111 1111<br />
其结果与 Math.floor((double)-5/(2*2*2)) 完全相同。</p>
<p>-5&lt;&lt;3=-40<br />
1111 1111 1111 1111 1111 1111 1111 1011<br />
1111 1111 1111 1111 1111 1111 1101 1000 <br />
其结果与 -5*2*2*2 完全相同。</p>
<p>5&gt;&gt;3=0<br />
0000 0000 0000 0000 0000 0000 0000 0101<br />
0000 0000 0000 0000 0000 0000 0000 0000<br />
其结果与 5/(2*2*2) 完全相同。</p>
<p>5&lt;&lt;3=40<br />
0000 0000 0000 0000 0000 0000 0000 0101<br />
0000 0000 0000 0000 0000 0000 0010 1000<br />
其结果与 5*2*2*2 完全相同。</p>
<p>-5&gt;&gt;&gt;3=536870911&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
1111 1111 1111 1111 1111 1111 1111 1011<br />
0001 1111 1111 1111 1111 1111 1111 1111</p>
<p>无论正数、负数，它们的右移、左移、无符号右移 32 位都是其本身，比如 -5&lt;&lt;32=-5、-5&gt;&gt;32=-5、-5&gt;&gt;&gt;32=-5。<br />
一个有趣的现象是，把 1 左移 31 位再右移 31 位，其结果为 -1。<br />
0000 0000 0000 0000 0000 0000 0000 0001<br />
1000 0000 0000 0000 0000 0000 0000 0000<br />
1111 1111 1111 1111 1111 1111 1111 1111</p>
<p><strong><br />
位逻辑运算符</strong></p>
<p>&nbsp;&nbsp;&nbsp; 包括：<br />
&nbsp;&nbsp;&nbsp; &amp; 与；| 或；~ 非（也叫做求反）；^ 异或</p>
<p>&nbsp;&nbsp;&nbsp; &#8220;&amp; 与&#8221;、&#8220;| 或&#8221;、&#8220;~ 非&#8221;是基本逻辑运算，由此可以演变出&#8220;与非&#8221;、&#8220;或非&#8221;、&#8220;与或非&#8221;复合逻辑运算。&#8220;^ 异或&#8221;是一种特殊的逻辑运算，对它求反可以得到&#8220;同或&#8221;，所以&#8220;同或&#8221;逻辑也叫&#8220;异或非&#8221;逻辑。</p>
<p>例子：<br />
5&amp;3=1<br />
0000 0000 0000 0000 0000 0000 0000 0101<br />
0000 0000 0000 0000 0000 0000 0000 0011<br />
0000 0000 0000 0000 0000 0000 0000 0001</p>
<p>-5&amp;3=1<br />
1111 1111 1111 1111 1111 1111 1111 1011<br />
0000 0000 0000 0000 0000 0000 0000 0011<br />
0000 0000 0000 0000 0000 0000 0000 0011</p>
<p>5|3=7<br />
0000 0000 0000 0000 0000 0000 0000 0101<br />
0000 0000 0000 0000 0000 0000 0000 0011<br />
0000 0000 0000 0000 0000 0000 0000 0111</p>
<p>-5|3=-5<br />
1111 1111 1111 1111 1111 1111 1111 1011<br />
0000 0000 0000 0000 0000 0000 0000 0011<br />
1111 1111 1111 1111 1111 1111 1111 1011</p>
<p>~5=-6<br />
0000 0000 0000 0000 0000 0000 0000 0101<br />
1111 1111 1111 1111 1111 1111 1111 1010</p>
<p>~-5=4<br />
1111 1111 1111 1111 1111 1111 1111 1011<br />
0000 0000 0000 0000 0000 0000 0000 0100</p>
<p>5^3=6<br />
0000 0000 0000 0000 0000 0000 0000 0101<br />
0000 0000 0000 0000 0000 0000 0000 0011<br />
0000 0000 0000 0000 0000 0000 0000 0110</p>
<p>-5^3=-8<br />
1111 1111 1111 1111 1111 1111 1111 1011<br />
0000 0000 0000 0000 0000 0000 0000 0011<br />
1111 1111 1111 1111 1111 1111 1111 1000<br />
<br />
<br />
<br />
<strong><font color="#ff0000" size="2">请注意！引用、转贴本文应注明原作者：Rosen Jiang 以及出处：</font></strong><a href="http://www.blogjava.net/rosen"><font face="宋体" color="#ff0000" size="2"><strong>http://www.blogjava.net/rosen</strong></font></a></p>
<img src ="http://www.blogjava.net/yglwxl/aggbug/173540.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yglwxl/" target="_blank">九宝</a> 2008-01-08 09:56 <a href="http://www.blogjava.net/yglwxl/archive/2008/01/08/173540.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>改变Swing的LookAndFeel （转）</title><link>http://www.blogjava.net/yglwxl/archive/2007/11/15/160785.html</link><dc:creator>九宝</dc:creator><author>九宝</author><pubDate>Thu, 15 Nov 2007 08:42:00 GMT</pubDate><guid>http://www.blogjava.net/yglwxl/archive/2007/11/15/160785.html</guid><wfw:comment>http://www.blogjava.net/yglwxl/comments/160785.html</wfw:comment><comments>http://www.blogjava.net/yglwxl/archive/2007/11/15/160785.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yglwxl/comments/commentRss/160785.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yglwxl/services/trackbacks/160785.html</trackback:ping><description><![CDATA[<table width="100%">
    <tbody>
        <tr>
            <td>要改变Swing默认的LookAndFeel，网上都说用UIManager下的一个静态方法setLookAndFeel即可，但是我用了这个方法有半年的时间也没有看到真正的WindowsLookAndFeel。昨天网上无意中才看到正解，要设置LookAndFeel，不仅要调用上面提到的方法，还要调用一个SwingUtilities类中的静态方法updateComponentTreeUI。即<br />
            <p class="code">try{<br />
            &nbsp;&nbsp;&nbsp;&nbsp;javax.swing.UIManager.setLookAndFeel(new&nbsp;com.sun.java.swing.plaf.windows.WindowsLookAndFeel());<br />
            &nbsp;&nbsp;&nbsp;&nbsp;javax.swing.SwingUtilities.updateComponentTreeUI(this);<br />
            }catch(javax.swing.UnsupportedLookAndFeelException&nbsp;e){<br />
            &nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace();<br />
            }<br />
            </p>
            <p><br />
            后者在运行时对整个ComponentTree进行更新，应用当前的UI设置。</p>
            <p><br />
            public static void setLookAndFeel(String className, java.awt.Component c) {<br />
            &nbsp;&nbsp;&nbsp; try {<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UIManager.setLookAndFeel(className);<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SwingUtilities.updateComponentTreeUI(c);//注意这行<br />
            &nbsp;&nbsp;&nbsp; }<br />
            &nbsp;&nbsp;&nbsp; catch (Exception ex) {<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ex.printStackTrace();<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; JOptionPane.showMessageDialog(null,<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "不好意思,setLookAndFeel时出错了:( Errormsg:" + ex,<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "setLookAndFeel",<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; JOptionPane.INFORMATION_MESSAGE);<br />
            &nbsp;&nbsp;&nbsp; }</p>
            </td>
        </tr>
    </tbody>
</table>
<img src ="http://www.blogjava.net/yglwxl/aggbug/160785.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yglwxl/" target="_blank">九宝</a> 2007-11-15 16:42 <a href="http://www.blogjava.net/yglwxl/archive/2007/11/15/160785.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>深入学习GridBagLayout(转)</title><link>http://www.blogjava.net/yglwxl/archive/2007/11/14/160646.html</link><dc:creator>九宝</dc:creator><author>九宝</author><pubDate>Wed, 14 Nov 2007 15:24:00 GMT</pubDate><guid>http://www.blogjava.net/yglwxl/archive/2007/11/14/160646.html</guid><wfw:comment>http://www.blogjava.net/yglwxl/comments/160646.html</wfw:comment><comments>http://www.blogjava.net/yglwxl/archive/2007/11/14/160646.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/yglwxl/comments/commentRss/160646.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yglwxl/services/trackbacks/160646.html</trackback:ping><description><![CDATA[<p align="left">&nbsp;&nbsp;&nbsp;&nbsp;GridBagLayout 不是用于简单的示例程序界面。使用GridBagLayout搭建界面就像是在起居室中搭脚手架清除画钩一样。</p>
<p align="left">对于简单的程序使用Boborderlayout和Gridlayout就绰绰有余了, 但如果要把程序提到实际应用上你就得考虑使用GridBagLayout。当然, 做复杂的应用程序时，一开始就使用GridBagLayout就会更有效率。</p>
<p align="left">一旦你决定使用GridBagLayout，接下来一步便是要找一些纸和铅笔,只有你准确知道你的界面看上去需要成什么样子，你就可以敲键盘。这就是说,你应该在编码之前进行妥善规划。</p>
<p align="left">&nbsp;&nbsp;&nbsp;&nbsp;下面将介绍一个很小的应用程序来帮助我们学习GridBagLayout，这个例子是从一个Flickr RSS fead中显示一系列照片, 最后的界面就像下面这样：</p>
<p align="center"><img title="JAVA:深入学习GridBagLayout" style="border-right: black 0px solid; border-top: black 0px solid; border-left: black 0px solid; border-bottom: black 0px solid" height="347" alt="JAVA:深入学习GridBagLayout" src="http://www.java3z.com/cwbwebhome/article/article2/img4/lildIAsHvtx46.jpg" width="553" align="center" /></p>
<p>下面的是这个界面的一个原始草图：</p>
<p align="center"><img title="JAVA:深入学习GridBagLayout" style="border-right: black 0px solid; border-top: black 0px solid; border-left: black 0px solid; border-bottom: black 0px solid" height="477" alt="JAVA:深入学习GridBagLayout" src="http://www.java3z.com/cwbwebhome/article/article2/img4/lirW3QqfAOm2s.gif" width="500" align="center" /></p>
<p>正如你所看到的，最终的结果看上去和计划的想法完全一样。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;你应该能看到在草图里有一些线，这些线是用来把总界面分成若干行和列的，这样你就很清楚每一个组件放置的格子位置。这就是GridBagLayout里"格"的那一部分，而图上的数字就是格的号码。</p>
<p align="left">在某种意义上说, 我们可以把GridBagLayout想象成为早些年的HTML3和4，它们都是基于表的布局，Grid的概念就类似rowspan和colspan的意思，只不过换了个名字罢了。</p>
<p align="left">随着我们的界面和表格的设置完成，是时候该进行界面布局并开始写代码了。</p>
<p><strong>工作过程</strong><strong></strong></p>
<p>这一节我假定你已经了解了基本的窗口和组件创建知识。</p>
<p>通过这篇文章我们最终能在一个frame中布局组件，我们将在以后的文章对界面进行改进使它更适用。因此,为了了解这整个工作的过程，我们列出了所有的目标代码。<br />
<br />
<pre>import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class GridBagWindow extends JFrame {
private JButton searchBtn;
private JComboBox modeCombo;
private JLabel tagLbl;
private JLabel tagModeLbl;
private JLabel previewLbl;
private JTable resTable;
private JTextField tagTxt;
public GridBagWindow() {
Container contentPane = getContentPane();
GridBagLayout gridbag = new GridBagLayout();
contentPane.setLayout(gridbag);
GridBagConstraints c = new GridBagConstraints();
//setting a default constraint value
c.fill =GridBagConstraints.HORIZONTAL;
tagLbl = new JLabel("Tags");
c.gridx = 0; //x grid position
c.gridy = 0; //y grid position
gridbag.setConstraints(tagLbl, c); //associate the label with a constraint object
contentPane.add(tagLbl); //add it to content pane
tagModeLbl = new JLabel("Tag Mode");
c.gridx = 0;
c.gridy = 1;
gridbag.setConstraints(tagModeLbl, c);
contentPane.add(tagModeLbl);
tagTxt = new JTextField("plinth");
c.gridx = 1;
c.gridy = 0;
c.gridwidth = 2;
gridbag.setConstraints(tagTxt, c);
contentPane.add(tagTxt);
String[] options = {"all", "any"};
modeCombo = new JComboBox(options);
c.gridx = 1;
c.gridy = 1;
c.gridwidth = 1;
gridbag.setConstraints(modeCombo, c);
contentPane.add(modeCombo);
searchBtn = new JButton("Search");
c.gridx = 1;
c.gridy = 2;
gridbag.setConstraints(searchBtn, c);
contentPane.add(searchBtn);
resTable = new JTable(5,3);
c.gridx = 0;
c.gridy = 3;
c.gridwidth = 3;
gridbag.setConstraints(resTable, c);
contentPane.add(resTable);
previewLbl = new JLabel("Preview goes here");
c.gridx = 0;
c.gridy = 4;
gridbag.setConstraints(previewLbl, c);
contentPane.add(previewLbl);
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
public static void main(String args[]) {
GridBagWindow window = new GridBagWindow();
window.setTitle("GridBagWindow");
window.pack();
window.setVisible(true);
}
}</pre>
<p>&nbsp;</p>
构造方法前的代码都不是很特殊，都是一些相当标准的import和变量定义。但是进入构造方法后，事情就变得有趣了。
<p>Container contentPane = getContentPane();</p>
<p>GridBagLayout gridbag = new GridBagLayout();</p>
<p>contentPane.setLayout(gridbag);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;我们以GridBagWindow的内容面板作为开始来创建一个GridBagLayout对象，准确地说，这个方法与过去我们所创建GridLayout对象和BorderLayout对象的方法是一样的。那么，现在我们就开始来设置GridBagLayout对象使它作为内容面板的布局。</p>
<p>GridBagConstraints c = new GridBagConstraints();</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;然后我要提到这整个进程中的一个独特的对象，那就是GridBagConstraints。这个对象在GridBagLayout中控制所有被安置在其中组件的约束。为了把一个组件增加到你的GridBagLayout中去，你首先必须将它与一个GridBagConstraints对象建立连接。</p>
<p>GridBagConstraints可以从11个方面来进行控制和操纵，也可以给你提供一些帮助。这些内容是：</p>
<ul>
    <li>Gridx——组件的横向坐标
    <li>Girdy——组件的纵向坐标
    <li>Gridwidth——组件的横向宽度，也就是指组件占用的列数，这与HTML的colspan类似
    <li>Gridheight——组件的纵向长度，也就是指组件占用的行数，这与HTML的rowspan类似
    <li>Weightx——指行的权重，告诉布局管理器如何分配额外的水平空间
    <li>Weighty——指列的权重，告诉布局管理器如何分配额外的垂直空间
    <li>Anchor——告诉布局管理器组件在表格空间中的位置
    <li>Fill——如果显示区域比组件的区域大的时候，可以用来控制组件的行为。控制组件是垂直填充，还是水平填充，或者两个方向一起填充
    <li>Insets——指组件与表格空间四周边缘的空白区域的大小
    <li>Ipadx——<strong>&nbsp;</strong>组件间的横向间距,组件的宽度就是这个组件的最小宽度加上ipadx值
    <li>ipady——<strong>&nbsp;</strong>组件间的纵向间距,组件的高度就是这个组件的最小高度加上ipady值 </li>
</ul>
<p>&nbsp;&nbsp;&nbsp;&nbsp;可能对于一个组件的每一个实例你都需要为它建立一个单独的GridBagConstraints；然而，这种方法我们并不推荐使用。最好的方法是，当你调用它的时候把对象设置为默认值，然后针对于每一个组件改变其相应的域。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;这个方法具有通用性，因为在一些域中，比如insets、padx、pady和fill这些域，对于每一个组件来说一般都是相同的，因此这样对一个域进行设置就会更轻松了，也能更轻松的在另外的组件中改变某些域的值。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;如果在改变了某些域值之后，你想回到原始的域值的话，你应该在增加下一个组件之前进行改变。这种方法使你更容易明白你正在修改的内容，也能使你更容易明白在一连串对象中的这11个参数的作用。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;也许你现在对这些内容还是一知半解，不过事实上一旦你理解了GridBagConstraints，值得安慰的是你以后做再困难的工作都会游刃有余了。</p>
<p>所以，如果我们已经明白了GridBagConstraints的详细用法了，那么现在就让我们来看看在实际应用中应该如何来实现它：</p>
<p>tagLbl = new JLabel("Tags");<br />
c.gridx = 0; //x grid position<br />
c.gridy = 0; //y grid position<br />
gridbag.setConstraints(tagLbl, c); //设置标签的限制</p>
<p>contentPane.add(tagLbl); //增加到内容面板</p>
<p>我们所做的是示例我们的标签、分配给它一个格位置，将它与一个约束对象联系起来并把它增加到我们的内容面板中。</p>
<p>tagModeLbl = new JLabel("Tag Mode");<br />
c.gridx = 0;<br />
c.gridy = 1;<br />
gridbag.setConstraints(tagModeLbl, c);</p>
<p>contentPane.add(tagModeLbl);</p>
<p>&nbsp;&nbsp;请注意，虽然我们已经在我们的约束对象中把gridx的值设置为0，但是在这里我们仍然要对它进行重新设置——这样做没有其它原因，只是为了增加可读性。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;下面，我们增加一个文本域以便能存储我们希望能搜索到的关键字，再增加一个组合框以便用来搜索多个关键字。除了我们希望的文本域有两列之外，这个概念其他的方面都与上面所说的是相同的，所以，我们需要在增加组合框之前重新设置文本域的值。</p>
<p>tagTxt = new JTextField("plinth");<br />
c.gridx = 1;<br />
c.gridy = 0;<br />
c.gridwidth = 2;<br />
gridbag.setConstraints(tagTxt, c);<br />
contentPane.add(tagTxt);</p>
<p>String[] options = {"all", "any"};<br />
modeCombo = new JComboBox(options);<br />
c.gridx = 1;<br />
c.gridy = 1;<br />
c.gridwidth = 1;<br />
gridbag.setConstraints(modeCombo, c);<br />
contentPane.add(modeCombo);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;做了这些之后，我们再在内容面板中增加一些其余的简单组件，这时候我们就能够浏览它了；其余的代码应该不会出现任何问题了。</p>
<p>到这个阶段，我们应该已经得到了一个类似于我们先前所设计的界面了。<br />
<br />
<img height="209" src="http://www.java3z.com/cwbwebhome/article/article2/img4/653364444.gif" width="233"  alt="" /></p>
<p><span class="STYLE1">进一步学习</span></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;当然，界面不是智能的。重新设置窗口的大小，看看将会发生些什么事情。为什么它会那样呢？那是因为我们设置了约束对象的weightx、weighty和fill的值。</p>
<p>关于其他类似的一些内容我们将在后面的章节中进行介绍，但是如果你希望能自己试试的话，参考<a href="http://java.sun.com/javase/6/docs/api/java/awt/GridBagLayout.html" target="_blank">GridBigLayout</a>和<a href="http://java.sun.com/javase/6/docs/api/java/awt/GridBagConstraints.html" target="_blank">GridBagConstraints</a>API文档会对扩充你的知识提供很好的帮助。</p>
<img src ="http://www.blogjava.net/yglwxl/aggbug/160646.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yglwxl/" target="_blank">九宝</a> 2007-11-14 23:24 <a href="http://www.blogjava.net/yglwxl/archive/2007/11/14/160646.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java中static用法简谈（转）</title><link>http://www.blogjava.net/yglwxl/archive/2007/11/07/158803.html</link><dc:creator>九宝</dc:creator><author>九宝</author><pubDate>Wed, 07 Nov 2007 05:42:00 GMT</pubDate><guid>http://www.blogjava.net/yglwxl/archive/2007/11/07/158803.html</guid><wfw:comment>http://www.blogjava.net/yglwxl/comments/158803.html</wfw:comment><comments>http://www.blogjava.net/yglwxl/archive/2007/11/07/158803.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yglwxl/comments/commentRss/158803.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yglwxl/services/trackbacks/158803.html</trackback:ping><description><![CDATA[请先看下面这段程序：<br />
　　　public class Hello{　 <br />
　　 public static void main(String[] args){ //(1)　　 <br />
　　 System.out.println("Hello,world!");　 //(2)　 <br />
　　 } <br />
　　 }<br />
　　看过这段程序，对于大多数学过Java 的从来说，都不陌生。即使没有学过Java，而学过其它的高<br />
　　级语言，例如C，那你也应该能看懂这段代码的意思。它只是简单的输出&#8220;Hello,world&#8221;，一点<br />
　　别的用处都没有，然而，它却展示了static关键字的主要用法。 <br />
　　在1处，我们定义了一个静态的方法名为main，这就意味着告诉Java编译器，我这个方法不需要创建一个此类的对象即可使用。你还得你是怎么运行这个程序吗？一般，我们都是在命令行下，打入如下的命令(加下划线为手动输入)：<br />
　　javac Hello.java<br />
　　java Hello<br />
　　Hello,world!<br />
　　这就是你运行的过程，第一行用来编译Hello.java这个文件，执行完后，如果你查看当前，会发现多了一个Hello.class文件，那就是第一行产生的Java二进制字节码。第二行就是执行一个Java程序的最普遍做法。执行结果如你所料。在2中，你可能会想，为什么要这样才能输出。好，我们来分解一下这条语句。（如果没有安装Java文档，请到Sun的官方网站浏览J2SE API）首先，System是位于java.lang包中的一个核心类，如果你查看它的定义，你会发现有这样一行：public static final PrintStream out;接着在进一步，点击PrintStream这个超链接，在METHOD页面，你会看到大量定义的方法，查找println，会有这样一行：<br />
　　public void println(String x)。好了，现在你应该明白为什么我们要那样调用了，out是System的一个静态变量，所以可以直接使用，而out所属的类有一个println方法。<br />
　　静态方法<br />
　　通常，在一个类中定义一个方法为static，那就是说，无需本类的对象即可调用此方法。如下所示：<br />
　　class Simple{　 <br />
　　static void go(){　　 <br />
　　System.out.println("Go...");　 <br />
　　}<br />
　　}<br />
　　public class Cal{ <br />
　　 public static void main(String[] args){　 <br />
　　 Simple.go(); <br />
　　 }<br />
　　}<br />
　　调用一个静态方法就是&#8220;类名.方法名&#8221;,静态方法的使用很简单如上所示。一般来说，静态方法常常为应用程序中的其它类提供一些实用工具所用，在Java的类库中大量的静态方法正是出于此目的而定义的。<br />
　　静态变量<br />
　　静态变量与静态方法类似。所有此类实例共享此静态变量，也就是说在类装载时，只分配一块存储空间，所有此类的对象都可以操控此块存储空间，当然对于final则另当别论了。看下面这段代码：<br />
　　class Value{　<br />
　　static int c=0;　<br />
　　static void inc(){　 <br />
　　 c++;　<br />
　　}}<br />
　　class Count{ <br />
　　 public static void prt(String s){　 <br />
　　 System.out.println(s); <br />
　　 } <br />
　　 public static void main(String[] args){　 <br />
　　 Value v1,v2;　<br />
　　　v1=new Value(); <br />
　　　 v2=new Value();　<br />
　　　prt("v1.c="+v1.c+" <br />
　　 v2.c="+v2.c);　　<br />
　　v1.inc();　<br />
　　　prt("v1.c="+v1.c+"　v2.c="+v2.c);　　<br />
　　}}<br />
　　结果如下：<br />
　　v1.c=0 v2.c=0<br />
　　v1.c=1 v2.c=1<br />
　　由此可以证明它们共享一块存储区。static变量有点类似于C中的全局变量的概念。值得探讨的是静态变量的初始化问题。我们修改上面的程序：<br />
　　class Value{ <br />
　　 static int c=0; <br />
　　 Value()　<br />
　　Value(int i){　 <br />
　　 c=i; <br />
　　 } <br />
　　 static void inc(){　 <br />
　　 c++; <br />
　　 }}<br />
　　class Count{　<br />
　　public static void prt(String s){　　<br />
　　System.out.println(s); <br />
　　 }　　<br />
　　Value v=new Value(10);　　<br />
　　static Value v1,v2;　 <br />
　　 static{　　 <br />
　　 prt("v1.c="+v1.c+"　<br />
　　v2.c="+v2.c);　　 <br />
　　 v1=new Value(27);　　 <br />
　　 prt("v1.c="+v1.c+"　v2.c="+v2.c);　　 <br />
　　 v2=new Value(15);　　 <br />
　　 prt("v1.c="+v1.c+"　v2.c="+v2.c); <br />
　　　 }　<br />
　　public static void main(String[] args){　　<br />
　　Count ct=new Count();　 <br />
　　 prt("ct.c="+ct.v.c);　 <br />
　　 prt("v1.c="+v1.c+"　v2.c="+v2.c);　 <br />
　　 v1.inc();　　<br />
　　prt("v1.c="+v1.c+"　v2.c="+v2.c);　　<br />
　　prt("ct.c="+ct.v.c); <br />
　　 }}<br />
　　运行结果如下：<br />
　　v1.c=0 v2.c=0<br />
　　v1.c=27 v2.c=27<br />
　　v1.c=15 v2.c=15<br />
　　ct.c=10<br />
　　v1.c=10 v2.c=10<br />
　　v1.c=11 v2.c=11<br />
　　ct.c=11<br />
　　这个程序展示了静态初始化的各种特性。如果你初次接触Java，结果可能令你吃惊。可能会对static后加大括号感到困惑。首先要告诉你的是，static定义的变量会优先于任何其它非static变量，不论其出现的顺序如何。正如在程序中所表现的，虽然v出现在v1和v2的前面，但是结果却是v1和v2的初始化在v的前面。在static{后面跟着一段代码，这是用来进行显式的静态变量初始化，这段代码只会初始化一次，且在类被第一次装载时。如果你能读懂并理解这段代码，会帮助你对static关键字的认识。在涉及到继承的时候，会先初始化父类的static变量，然后是子类的，依次类推。非静态变量不是本文的主题，在此不做详细讨论，请参考Think in Java中的讲解。<br />
　　静态类<br />
　　通常一个普通类不允许声明为静态的，只有一个内部类才可以。这时这个声明为静态的内部类可以直接作为一个普通类来使用，而不需实例一个外部类。如下代码所示：<br />
　　public class StaticCls{ <br />
　　 public static void main(String[] args){　 <br />
　　 OuterCls.InnerCls oi=new OuterCls.InnerCls();<br />
　　　}}<br />
　　class OuterCls{　<br />
　　public static class InnerCls{　　<br />
　　InnerCls(){　　 <br />
　　 System.out.println("InnerCls");　<br />
　　　} <br />
　　　}}<br />
　　输出结果会如你所料：<br />
　　InnerCls 
<img src ="http://www.blogjava.net/yglwxl/aggbug/158803.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yglwxl/" target="_blank">九宝</a> 2007-11-07 13:42 <a href="http://www.blogjava.net/yglwxl/archive/2007/11/07/158803.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>EasyMock 2.3 Readme（转 http://www.easymock.org/EasyMock2_3_Documentation.html）</title><link>http://www.blogjava.net/yglwxl/archive/2007/10/24/155581.html</link><dc:creator>九宝</dc:creator><author>九宝</author><pubDate>Wed, 24 Oct 2007 05:53:00 GMT</pubDate><guid>http://www.blogjava.net/yglwxl/archive/2007/10/24/155581.html</guid><wfw:comment>http://www.blogjava.net/yglwxl/comments/155581.html</wfw:comment><comments>http://www.blogjava.net/yglwxl/archive/2007/10/24/155581.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yglwxl/comments/commentRss/155581.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yglwxl/services/trackbacks/155581.html</trackback:ping><description><![CDATA[<h2>EasyMock 2.3 Readme</h2>
<p>Documentation for release 2.3 (July 9 2007)<br />
&#169; 2001-2007 <a title="OFFIS" href="http://www.offis.de/">OFFIS</a>, <a id="id" title="Tammo Freese" href="http://tammofreese.de/">Tammo Freese</a>. </p>
<p>EasyMock 2 is a library that provides an easy way to use Mock Objects for given interfaces. EasyMock 2 is available under the terms of the <a href="http://www.easymock.org/License.html">MIT license</a>. </p>
<p>Mock Objects simulate parts of the behavior of domain code, and are able to check whether they are used as defined. Domain classes can be tested in isolation by simulating their collaborators with Mock Objects. </p>
<p>Writing and maintaining Mock Objects often is a tedious task that may introduce errors. EasyMock 2 generates Mock Objects dynamically - no need to write them, and no generated code! </p>
<h3>EasyMock 2 Benefits </h3>
<ul>
    <li>Hand-writing classes for Mock Objects is not needed.
    <li>Supports refactoring-safe Mock Objects: test code will not break at runtime when renaming methods or reordering method parameters
    <li>Supports return values and exceptions.
    <li>Supports checking the order of method calls, for one or more Mock Objects. </li>
</ul>
<h3>EasyMock 2 Drawbacks </h3>
<ul>
    <li>EasyMock 2 does only work with Java 2 Version 5.0 and above. </li>
</ul>
<p>EasyMock by default supports the generation of Mock Objects for interfaces only. For those who would like to generate Mock Objects for classes, there is an extension available at the EasyMock home page. </p>
<h2>Installation </h2>
<ol>
    <li>Java 2 (at least 5.0) is required.
    <li>Unzip the EasyMock zip file (<code>easymock2.3.zip</code>). It contains a directory <code>easymock2.3</code>. Add the EasyMock jar file (<code>easymock.jar</code>) from this directory to your classpath. </li>
</ol>
<p>To execute the EasyMock tests, add <code>tests.zip</code> and the JUnit 4.1 jar to your class path and start <code>'java org.easymock.tests.AllTests'</code>. </p>
<p>The source code of EasyMock is stored in the zip file <code>src.zip</code>. </p>
<h2>Usage </h2>
<p>Most parts of a software system do not work in isolation, but collaborate with other parts to get their job done. In a lot of cases, we do not care about using collaborators in unit testing, as we trust these collaborators. If we <em>do</em> care about it, Mock Objects help us to test the unit under test in isolation. Mock Objects replace collaborators of the unit under test. </p>
<p>The following examples use the interface <code>Collaborator</code>: </p>
<pre>package org.easymock.samples;
public interface Collaborator {
void documentAdded(String title);
void documentChanged(String title);
void documentRemoved(String title);
byte voteForRemoval(String title);
byte[] voteForRemovals(String[] title);
}
</pre>
<p>Implementors of this interface are collaborators (in this case listeners) of a class named <code>ClassUnderTest</code>: </p>
<pre>public class ClassUnderTest {
// ...
public void addListener(Collaborator listener) {
// ...
}
public void addDocument(String title, byte[] document) {
// ...
}
public boolean removeDocument(String title) {
// ...
}
public boolean removeDocuments(String[] titles) {
// ...
}
}
</pre>
<p>The code for both the class and the interface may be found in the package <code>org.easymock.samples</code> in <code>samples.zip</code>. </p>
<p>The following examples assume that you are familiar with the JUnit testing framework. Although the tests shown here use JUnit in version 3.8.1, you may as well use JUnit 4 or TestNG. </p>
<h3>The first Mock Object </h3>
<p>We will now build a test case and toy around with it to understand the functionality of the EasyMock package. <code>samples.zip</code> contains a modified version of this test. Our first test should check whether the removal of a non-existing document does <strong>not </strong>lead to a notification of the collaborator. Here is the test without the definition of the Mock Object: </p>
<pre>package org.easymock.samples;
import junit.framework.TestCase;
public class ExampleTest extends TestCase {
private ClassUnderTest classUnderTest;
private Collaborator mock;
protected void setUp() {
classUnderTest = new ClassUnderTest();
classUnderTest.addListener(mock);
}
public void testRemoveNonExistingDocument() {
// This call should not lead to any notification
// of the Mock Object:
classUnderTest.removeDocument("Does not exist");
}
}
</pre>
<p>For many tests using EasyMock 2, we only need a static import of methods of <code>org.easymock.EasyMock</code>. This is the only non-internal, non-deprecated class of EasyMock 2. </p>
<pre>import static org.easymock.EasyMock.*;
import junit.framework.TestCase;
public class ExampleTest extends TestCase {
private ClassUnderTest classUnderTest;
private Collaborator mock;
}
</pre>
<p>To get a Mock Object, we need to </p>
<ol>
    <li>create a Mock Object for the interface we would like to simulate,
    <li>record the expected behavior, and
    <li>switch the Mock Object to replay state. </li>
</ol>
<p>Here is a first example: </p>
<pre>    protected void setUp() {
mock = createMock(Collaborator.class); // 1
classUnderTest = new ClassUnderTest();
classUnderTest.addListener(mock);
}
public void testRemoveNonExistingDocument() {
// 2 (we do not expect anything)
replay(mock); // 3
classUnderTest.removeDocument("Does not exist");
}
</pre>
<p>After activation in step 3, <code>mock</code> is a Mock Object for the <code>Collaborator</code> interface that expects no calls. This means that if we change our <code>ClassUnderTest</code> to call any of the interface's methods, the Mock Object will throw an <code>AssertionError</code>: </p>
<pre>java.lang.AssertionError:
Unexpected method call documentRemoved("Does not exist"):
at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:29)
at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:44)
at $Proxy0.documentRemoved(Unknown Source)
at org.easymock.samples.ClassUnderTest.notifyListenersDocumentRemoved(ClassUnderTest.java:74)
at org.easymock.samples.ClassUnderTest.removeDocument(ClassUnderTest.java:33)
at org.easymock.samples.ExampleTest.testRemoveNonExistingDocument(ExampleTest.java:24)
...
</pre>
<h3>Adding Behavior </h3>
<p>Let us write a second test. If a document is added on the class under test, we expect a call to <code>mock.documentAdded()</code> on the Mock Object with the title of the document as argument: </p>
<pre>    public void testAddDocument() {
mock.documentAdded("New Document"); // 2
replay(mock); // 3
classUnderTest.addDocument("New Document", new byte[0]);
}
</pre>
<p>So in the record state (before calling <code>replay</code>), the Mock Object does <em>not</em> behave like a Mock Object, but it records method calls. After calling <code>replay</code>, it behaves like a Mock Object, checking whether the expected method calls are really done. </p>
<p>If <code>classUnderTest.addDocument("New Document", new byte[0])</code> calls the expected method with a wrong argument, the Mock Object will complain with an <code>AssertionError</code>: </p>
<pre>java.lang.AssertionError:
Unexpected method call documentAdded("Wrong title"):
documentAdded("New Document"): expected: 1, actual: 0
at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:29)
at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:44)
at $Proxy0.documentAdded(Unknown Source)
at org.easymock.samples.ClassUnderTest.notifyListenersDocumentAdded(ClassUnderTest.java:61)
at org.easymock.samples.ClassUnderTest.addDocument(ClassUnderTest.java:28)
at org.easymock.samples.ExampleTest.testAddDocument(ExampleTest.java:30)
...
</pre>
<p>All missed expectations are shown, as well as all fulfilled expectations for the unexpected call (none in this case). If the method call is executed too often, the Mock Object complains, too: </p>
<pre>java.lang.AssertionError:
Unexpected method call documentAdded("New Document"):
documentAdded("New Document"): expected: 1, actual: 1 (+1)
at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:29)
at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:44)
at $Proxy0.documentAdded(Unknown Source)
at org.easymock.samples.ClassUnderTest.notifyListenersDocumentAdded(ClassUnderTest.java:62)
at org.easymock.samples.ClassUnderTest.addDocument(ClassUnderTest.java:29)
at org.easymock.samples.ExampleTest.testAddDocument(ExampleTest.java:30)
...
</pre>
<h3>Verifying Behavior </h3>
<p>There is one error that we have not handled so far: If we specify behavior, we would like to verify that it is actually used. The current test would pass if no method on the Mock Object is called. To verify that the specified behavior has been used, we have to call <code>verify(mock)</code>: </p>
<pre>    public void testAddDocument() {
mock.documentAdded("New Document"); // 2
replay(mock); // 3
classUnderTest.addDocument("New Document", new byte[0]);
verify(mock);
}
</pre>
<p>If the method is not called on the Mock Object, we now get the following exception: </p>
<pre>java.lang.AssertionError:
Expectation failure on verify:
documentAdded("New Document"): expected: 1, actual: 0
at org.easymock.internal.MocksControl.verify(MocksControl.java:70)
at org.easymock.EasyMock.verify(EasyMock.java:536)
at org.easymock.samples.ExampleTest.testAddDocument(ExampleTest.java:31)
...
</pre>
<p>The message of the exception lists all missed expectations. </p>
<h3>Expecting an Explicit Number of Calls </h3>
<p>Up to now, our test has only considered a single method call. The next test should check whether the addition of an already existing document leads to a call to <code>mock.documentChanged()</code> with the appropriate argument. To be sure, we check this three times (hey, it is an example ;-)): </p>
<pre>    public void testAddAndChangeDocument() {
mock.documentAdded("Document");
mock.documentChanged("Document");
mock.documentChanged("Document");
mock.documentChanged("Document");
replay(mock);
classUnderTest.addDocument("Document", new byte[0]);
classUnderTest.addDocument("Document", new byte[0]);
classUnderTest.addDocument("Document", new byte[0]);
classUnderTest.addDocument("Document", new byte[0]);
verify(mock);
}
</pre>
<p>To avoid the repetition of <code>mock.documentChanged("Document")</code>, EasyMock provides a shortcut. We may specify the call count with the method <code>times(int times)</code> on the object returned by <code>expectLastCall()</code>. The code then looks like: </p>
<pre>    public void testAddAndChangeDocument() {
mock.documentAdded("Document");
mock.documentChanged("Document");
expectLastCall().times(3);
replay(mock);
classUnderTest.addDocument("Document", new byte[0]);
classUnderTest.addDocument("Document", new byte[0]);
classUnderTest.addDocument("Document", new byte[0]);
classUnderTest.addDocument("Document", new byte[0]);
verify(mock);
}
</pre>
<p>If the method is called too often, we get an exception that tells us that the method has been called too many times. The failure occurs immediately at the first method call exceeding the limit: </p>
<pre>java.lang.AssertionError:
Unexpected method call documentChanged("Document"):
documentChanged("Document"): expected: 3, actual: 3 (+1)
at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:29)
at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:44)
at $Proxy0.documentChanged(Unknown Source)
at org.easymock.samples.ClassUnderTest.notifyListenersDocumentChanged(ClassUnderTest.java:67)
at org.easymock.samples.ClassUnderTest.addDocument(ClassUnderTest.java:26)
at org.easymock.samples.ExampleTest.testAddAndChangeDocument(ExampleTest.java:43)
...
</pre>
<p>If there are too few calls, <code>verify(mock)</code> throws an <code>AssertionError</code>: </p>
<pre>java.lang.AssertionError:
Expectation failure on verify:
documentChanged("Document"): expected: 3, actual: 2
at org.easymock.internal.MocksControl.verify(MocksControl.java:70)
at org.easymock.EasyMock.verify(EasyMock.java:536)
at org.easymock.samples.ExampleTest.testAddAndChangeDocument(ExampleTest.java:43)
...
</pre>
<h3>Specifying Return Values </h3>
<p>For specifying return values, we wrap the expected call in <code>expect(T value)</code> and specify the return value with the method <code>andReturn(Object returnValue)</code> on the object returned by <code>expect(T value)</code>. </p>
<p>As an example, we check the workflow for document removal. If <code>ClassUnderTest</code> gets a call for document removal, it asks all collaborators for their vote for removal with calls to <code>byte voteForRemoval(String title)</code> value. Positive return values are a vote for removal. If the sum of all values is positive, the document is removed and <code>documentRemoved(String title)</code> is called on all collaborators: </p>
<pre>    public void testVoteForRemoval() {
mock.documentAdded("Document");   // expect document addition
// expect to be asked to vote for document removal, and vote for it
expect(mock.voteForRemoval("Document")).andReturn((byte) 42);
mock.documentRemoved("Document"); // expect document removal
replay(mock);
classUnderTest.addDocument("Document", new byte[0]);
assertTrue(classUnderTest.removeDocument("Document"));
verify(mock);
}
public void testVoteAgainstRemoval() {
mock.documentAdded("Document");   // expect document addition
// expect to be asked to vote for document removal, and vote against it
expect(mock.voteForRemoval("Document")).andReturn((byte) -42);
replay(mock);
classUnderTest.addDocument("Document", new byte[0]);
assertFalse(classUnderTest.removeDocument("Document"));
verify(mock);
}
</pre>
<p>The type of the returned value is checked at compile time. As an example, the following code will not compile, as the type of the provided return value does not match the method's return value: </p>
<pre>    expect(mock.voteForRemoval("Document")).andReturn("wrong type");
</pre>
<p>Instead of calling <code>expect(T value)</code> to retrieve the object for setting the return value, we may also use the object returned by <code>expectLastCall()</code>. Instead of </p>
<pre>    expect(mock.voteForRemoval("Document")).andReturn((byte) 42);
</pre>
<p>we may use </p>
<pre>    mock.voteForRemoval("Document");
expectLastCall().andReturn((byte) 42);
</pre>
<p>This type of specification should only be used if the line gets too long, as it does not support type checking at compile time. </p>
<h3>Working with Exceptions </h3>
<p>For specifying exceptions (more exactly: Throwables) to be thrown, the object returned by <code>expectLastCall()</code> and <code>expect(T value)</code> provides the method <code>andThrow(Throwable throwable)</code>. The method has to be called in record state after the call to the Mock Object for which it specifies the <code>Throwable</code> to be thrown. </p>
<p>Unchecked exceptions (that is, <code>RuntimeException</code>, <code>Error</code> and all their subclasses) can be thrown from every method. Checked exceptions can only be thrown from the methods that do actually throw them. </p>
<h3>Creating Return Values or Exceptions </h3>
<p>Sometimes we would like our mock object to return a value or throw an exception that is created at the time of the actual call. Since EasyMock 2.2, the object returned by <code>expectLastCall()</code> and <code>expect(T value)</code> provides the method <code>andAnswer(IAnswer answer)</code> which allows to specify an implementation of the interface <code>IAnswer</code> that is used to create the return value or exception. </p>
<p>Inside an <code>IAnswer</code> callback, the arguments passed to the mock call are available via <code>EasyMock.getCurrentArguments()</code>. If you use these, refactorings like reordering parameters may break your tests. You have been warned. </p>
<h3>Changing Behavior for the Same Method Call </h3>
<p>It is also possible to specify a changing behavior for a method. The methods <code>times</code>, <code>andReturn</code>, and <code>andThrow</code> may be chained. As an example, we define <code>voteForRemoval("Document")</code> to </p>
<ul>
    <li>return 42 for the first three calls,
    <li>throw a <code>RuntimeException</code> for the next four calls,
    <li>return -42 once. </li>
</ul>
<pre>    expect(mock.voteForRemoval("Document"))
.andReturn((byte) 42).times(3)
.andThrow(new RuntimeException(), 4)
.andReturn((byte) -42);
</pre>
<h3>Relaxing Call Counts </h3>
<p>To relax the expected call counts, there are additional methods that may be used instead of <code>times(int count)</code>: </p>
<dl>
<dt><code>times(int min, int max)</code>
<dd>to expect between <code>min</code> and <code>max</code> calls,
<dt><code>atLeastOnce()</code>
<dd>to expect at least one call, and
<dt><code>anyTimes()</code>
<dd>to expected an unrestricted number of calls. </dd></dl>
<p>If no call count is specified, one call is expected. If we would like to state this explicitely, <code>once()</code> or <code>times(1)</code> may be used. </p>
<h3>Strict Mocks </h3>
<p>On a Mock Object returned by a <code>EasyMock.createMock()</code>, the order of method calls is not checked. If you would like a strict Mock Object that checks the order of method calls, use <code>EasyMock.create<em>Strict</em>Mock()</code> to create it.</p>
<p>If an unexpected method is called on a strict Mock Object, the message of the exception will show the method calls expected at this point followed by the first conflicting one. <code>verify(mock)</code> shows all missing method calls. </p>
<h3>Switching Order Checking On and Off </h3>
<p>Sometimes, it is necessary to have a Mock Object that checks the order of only some calls. In record phase, you may switch order checking on by calling <code>checkOrder(mock, true)</code> and switch it off by calling <code>checkOrder(mock, false)</code>. </p>
<p>There are two differences between a strict Mock Object and a normal Mock Object: </p>
<ol>
    <li>A strict Mock Object has order checking enabled after creation.
    <li>A strict Mock Object has order checking enabled after reset (see <em>Reusing a Mock Object</em>). </li>
</ol>
<h3>Flexible Expectations with Argument Matchers </h3>
<p>To match an actual method call on the Mock Object with an expectation, <code>Object</code> arguments are by default compared with <code>equals()</code>. This may lead to problems. As an example, we consider the following expectation: </p>
<pre>String[] documents = new String[] { "Document 1", "Document 2" };
expect(mock.voteForRemovals(documents)).andReturn(42);
</pre>
<p>If the method is called with another array with the same contents, we get an exception, as <code>equals()</code> compares object identity for arrays: </p>
<pre>java.lang.AssertionError:
Unexpected method call voteForRemovals([Ljava.lang.String;@9a029e):
voteForRemovals([Ljava.lang.String;@2db19d): expected: 1, actual: 0
documentRemoved("Document 1"): expected: 1, actual: 0
documentRemoved("Document 2"): expected: 1, actual: 0
at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:29)
at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:44)
at $Proxy0.voteForRemovals(Unknown Source)
at org.easymock.samples.ClassUnderTest.listenersAllowRemovals(ClassUnderTest.java:88)
at org.easymock.samples.ClassUnderTest.removeDocuments(ClassUnderTest.java:48)
at org.easymock.samples.ExampleTest.testVoteForRemovals(ExampleTest.java:83)
...
</pre>
<p>To specify that only array equality is needed for this call, we may use the method <code>aryEq</code> that is statically imported from the <code>EasyMock</code> class: </p>
<pre>String[] documents = new String[] { "Document 1", "Document 2" };
expect(mock.voteForRemovals(aryEq(documents))).andReturn(42);
</pre>
<p>If you would like to use matchers in a call, you have to specify matchers for all arguments of the method call. </p>
<p>There are a couple of predefined argument matchers available. </p>
<dl>
<dt><code>eq(X value)</code>
<dd>Matches if the actual value is equals the expected value. Available for all primitive types and for objects.
<dt><code>anyBoolean()</code>, <code>anyByte()</code>, <code>anyChar()</code>, <code>anyDouble()</code>, <code>anyFloat()</code>, <code>anyInt()</code>, <code>anyLong()</code>, <code>anyObject()</code>, <code>anyShort()</code>
<dd>Matches any value. Available for all primitive types and for objects.
<dt><code>eq(X value, X delta)</code>
<dd>Matches if the actual value is equal to the given value allowing the given delta. Available for <code>float</code> and <code>double</code>.
<dt><code>aryEq(X value)</code>
<dd>Matches if the actual value is equal to the given value according to <code>Arrays.equals()</code>. Available for primitive and object arrays.
<dt><code>isNull()</code>
<dd>Matches if the actual value is null. Available for objects.
<dt><code>notNull()</code>
<dd>Matches if the actual value is not null. Available for objects.
<dt><code>same(X value)</code>
<dd>Matches if the actual value is the same as the given value. Available for objects.
<dt><code>isA(Class clazz)</code>
<dd>Matches if the actual value is an instance of the given class, or if it is in instance of a class that extends or implements the given class. Available for objects.
<dt><code>lt(X value)</code>, <code>leq(X value)</code>, <code>geq(X value)</code>, <code>gt(X value)</code>
<dd>Matches if the actual value is less/less or equal/greater or equal/greater than the given value. Available for all numeric primitive types and <code>Comparable</code>.
<dt><code>startsWith(String prefix), contains(String substring), endsWith(String suffix)</code>
<dd>Matches if the actual value starts with/contains/ends with the given value. Available for <code>String</code>s.
<dt><code>matches(String regex), find(String regex)</code>
<dd>Matches if the actual value/a substring of the actual value matches the given regular expression. Available for <code>String</code>s.
<dt><code>and(X first, X second)</code>
<dd>Matches if the matchers used in <code>first</code> and <code>second</code> both match. Available for all primitive types and for objects.
<dt><code>or(X first, X second)</code>
<dd>Matches if one of the matchers used in <code>first</code> and <code>second</code> match. Available for all primitive types and for objects.
<dt><code>not(X value)</code>
<dd>Matches if the matcher used in <code>value</code> does not match.
<dt><code>cmpEq(X value)</code>
<dd>Matches if the actual value is equals according to <code>Comparable.compareTo(X o)</code>. Available for all numeric primitive types and <code>Comparable</code>.
<dt><code>cmp(X value, Comparator<x> comparator, LogicalOperator operator)</code>
<dd>Matches if <code>comparator.compare(actual, value) operator 0</code> where the operator is &lt;,&lt;=,&gt;,&gt;= or ==. Available for objects. </dd></dl>
<h3>Defining your own Argument Matchers </h3>
<p>Sometimes it is desirable to define own argument matchers. Let's say that an argument matcher is needed that matches an exception if the given exception has the same type and an equal message. It should be used this way: </p>
<pre>    IllegalStateException e = new IllegalStateException("Operation not allowed.")
expect(mock.logThrowable(eqException(e))).andReturn(true);
</pre>
<p>Two steps are necessary to achieve this: The new argument matcher has to be defined, and the static method <code>eqException</code> has to be declared. </p>
<p>To define the new argument matcher, we implement the interface <code>org.easymock.IArgumentMatcher</code>. This interface contains two methods: <code>matches(Object actual)</code> checks whether the actual argument matches the given argument, and <code>appendTo(StringBuffer buffer)</code> appends a string representation of the argument matcher to the given string buffer. The implementation is straightforward: </p>
<pre>import org.easymock.IArgumentMatcher;
public class ThrowableEquals implements IArgumentMatcher {
private Throwable expected;
public ThrowableEquals(Throwable expected) {
this.expected = expected;
}
public boolean matches(Object actual) {
if (!(actual instanceof Throwable)) {
return false;
}
String actualMessage = ((Throwable) actual).getMessage();
return expected.getClass().equals(actual.getClass())
&amp;&amp; expected.getMessage().equals(actualMessage);
}
public void appendTo(StringBuffer buffer) {
buffer.append("eqException(");
buffer.append(expected.getClass().getName());
buffer.append(" with message \"");
buffer.append(expected.getMessage());
buffer.append("\"")");
}
}
</pre>
<p>The method <code>eqException</code> must create the argument matcher with the given Throwable, report it to EasyMock via the static method <code>reportMatcher(IArgumentMatcher matcher)</code>, and return a value so that it may be used inside the call (typically <code>0</code>, <code>null</code> or <code>false</code>). A first attempt may look like: </p>
<pre>public static Throwable eqException(Throwable in) {
EasyMock.reportMatcher(new ThrowableEquals(in));
return null;
}
</pre>
<p>However, this only works if the method <code>logThrowable</code> in the example usage accepts <code>Throwable</code>s, and does not require something more specific like a <code>RuntimeException</code>. In the latter case, our code sample would not compile: </p>
<pre>    IllegalStateException e = new IllegalStateException("Operation not allowed.")
expect(mock.logThrowable(eqException(e))).andReturn(true);
</pre>
<p>Java 5.0 to the rescue: Instead of defining <code>eqException</code> with a <code>Throwable</code> as parameter and return value, we use a generic type that extends <code>Throwable</code>: </p>
<pre>public static &lt;T extends Throwable&gt; T eqException(T in) {
reportMatcher(new ThrowableEquals(in));
return null;
}
</pre>
<h3>Reusing a Mock Object </h3>
<p>Mock Objects may be reset by <code>reset(mock)</code>. </p>
<h3>Using Stub Behavior for Methods </h3>
<p>Sometimes, we would like our Mock Object to respond to some method calls, but we do not want to check how often they are called, when they are called, or even if they are called at all. This stub behavoir may be defined by using the methods <code>andStubReturn(Object value)</code>, <code>andStubThrow(Throwable throwable)</code>, <code>andStubAnswer(IAnswer<t> answer)</code> and <code>asStub()</code>. The following code configures the MockObject to answer 42 to <code>voteForRemoval("Document")</code> once and -1 for all other arguments: </p>
<pre>    expect(mock.voteForRemoval("Document")).andReturn(42);
expect(mock.voteForRemoval(not(eq("Document")))).andStubReturn(-1);
</pre>
<h3>Nice Mocks </h3>
<p>On a Mock Object returned by <code>createMock()</code> the default behavior for all methods is to throw an <code>AssertionError</code> for all unexpected method calls. If you would like a "nice" Mock Object that by default allows all method calls and returns appropriate empty values (<code>0</code>, <code>null</code> or <code>false</code>), use <code>create<em>Nice</em>Mock()</code> instead. </p>
<h3>Object Methods </h3>
<p>The behavior for the three object methods <code>equals()</code>, <code>hashCode()</code> and <code>toString()</code> cannot be changed for Mock Objects created with EasyMock, even if they are part of the interface for which the Mock Object is created. </p>
<h3>Checking Method Call Order Between Mocks</h3>
<p>Up to this point, we have seen a mock object as a single object that is configured by static methods on the class <code>EasyMock</code>. But many of these static methods just identify the hidden control of the Mock Object and delegate to it. A Mock Control is an object implementing the <code>IMocksControl</code> interface. </p>
<p>So instead of </p>
<pre>    IMyInterface mock = createStrictMock(IMyInterface.class);
replay(mock);
verify(mock);
reset(mock);
</pre>
<p>we may use the equivalent code: </p>
<pre>    IMocksControl ctrl = createStrictControl();
IMyInterface mock = ctrl.createMock(IMyInterface.class);
ctrl.replay();
ctrl.verify();
ctrl.reset();
</pre>
<p>The IMocksControl allows to create more than one Mock Object, and so it is possible to check the order of method calls between mocks. As an example, we set up two mock objects for the interface <code>IMyInterface</code>, and we expect the calls <code>mock1.a()</code> and <code>mock2.a()</code> ordered, then an open number of calls to <code>mock1.c()</code> and <code>mock2.c()</code>, and finally <code>mock2.b()</code> and <code>mock1.b()</code>, in this order: </p>
<pre>    IMocksControl ctrl = createStrictControl();
IMyInterface mock1 = ctrl.createMock(IMyInterface.class);
IMyInterface mock2 = ctrl.createMock(IMyInterface.class);
mock1.a();
mock2.a();
ctrl.checkOrder(false);
mock1.c();
expectLastCall().anyTimes();
mock2.c();
expectLastCall().anyTimes();
ctrl.checkOrder(true);
mock2.b();
mock1.b();
ctrl.replay();
</pre>
<h3>Naming Mock Objects</h3>
<p>Mock Objects can be named at creation using <code>createMock(String name, Class<t> toMock)</code>, <code>createStrictMock(String name, Class<t> toMock)</code> or <code>createNiceMock(String name, Class<t> toMock)</code>. The names will be shown in exception failures. </p>
<h3>Backward Compatibility </h3>
<p>EasyMock 2 contains a compatibility layer so that tests using EasyMock 1.2 for Java 1.5 should work without any modification. The only known differences are visible when failures occur: there are small changes in the failure messages and stack traces, and failures are now reported using Java's <code>AssertionError</code> instead of JUnit's <code>AssertionFailedError</code>. </p>
<p>EasyMock 2.1 introduced a callback feature that has been removed in EasyMock 2.2, as it was too complex. Since EasyMock 2.2, the <code>IAnswer</code> interface provides the functionality for callbacks. </p>
<h2>EasyMock Development </h2>
<p>EasyMock 1.0 has been developed by Tammo Freese at OFFIS. The development of EasyMock is now hosted on SourceForge to allow other developers and companies to contribute. </p>
<p>Thanks to the people who gave feedback or provided patches, including Nascif Abousalh-Neto, Dave Astels, Francois Beausoleil, George Dinwiddie, Shane Duan, Wolfgang Frech, Steve Freeman, Oren Gross, John D. Heintz, Dale King, Brian Knorr, Dierk Koenig, Chris Kreussling, Robert Leftwich, Patrick Lightbody, Johannes Link, Rex Madden, David McIntosh, Karsten Menne, Bill Michell, Stephan Mikaty, Ivan Moore, Ilja Preuss, Justin Sampson, Markus Schmidlin, Richard Scott, Joel Shellman, Jiř&#237; Mare&#353;, Alexandre de Pellegrin Shaun Smith, Marco Struck, Ralf Stuckert, Victor Szathmary, Henri Tremblay, Bill Uetrecht, Frank Westphal, Chad Woolley, Bernd Worsch, and numerous others. </p>
<p>Please check the <a href="http://www.easymock.org/">EasyMock home page</a> for new versions, and send bug reports and suggestions to the <a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#101;&#97;&#115;&#121;&#109;&#111;&#99;&#107;&#64;&#121;&#97;&#104;&#111;&#111;&#103;&#114;&#111;&#117;&#112;&#115;&#46;&#99;&#111;&#109;&#63;&#115;&#117;&#98;&#106;&#101;&#99;&#116;&#61;&#69;&#97;&#115;&#121;&#77;&#111;&#99;&#107;&#32;&#50;&#46;&#51;&#32;&#102;&#101;&#101;&#100;&#98;&#97;&#99;&#107;">EasyMock Yahoo!Group</a>. If you would like to subscribe to the EasyMock Yahoo!Group, send a message to <a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#101;&#97;&#115;&#121;&#109;&#111;&#99;&#107;&#45;&#115;&#117;&#98;&#115;&#99;&#114;&#105;&#98;&#101;&#64;&#121;&#97;&#104;&#111;&#111;&#103;&#114;&#111;&#117;&#112;&#115;&#46;&#99;&#111;&#109;">easymock-subscribe@yahoogroups.com</a>. </p>
<p>EasyMock Version 2.3 (July 9 2007) </p>
<p>Changes since 2.2: </p>
<ul>
    <li>French documentation
    <li>Matchers for Comparable parameters
    <li>Decimal comparison fix
    <li>Mock Objects can now be named
    <li>Include Bill Michell's ThreadLocal fix
    <li>Converted EasyMock's unit tests to JUnit 4 </li>
</ul>
<p>Changes since 2.1: </p>
<ul>
    <li>answers for expected calls can now be created at call time via <code>andAnswer(IAnswer answer)</code> and <code>andStubAnswer(IAnswer answer)</code>
    <li><code>callback(Runnable runnable)</code> has been removed, for callbacks, please switch to <code>andAnswer(IAnswer answer)</code> and <code>andStubAnswer(IAnswer answer)</code>
    <li><code>replay()</code>, <code>verify()</code> and <code>reset()</code> now accept multiple mock objects as arguments </li>
</ul>
<p>Changes since 2.0: </p>
<ul>
    <li>arguments passed to the mock object are now available in callbacks via <code>EasyMock.getCurrentArguments()</code>
    <li>fixed bug reported in http://groups.yahoo.com/group/easymock/message/558
    <li>earlier failing if unused matchers were specified </li>
</ul>
<p>Changes since 1.2: </p>
<ul>
    <li>support for flexible, refactoring-safe argument matchers
    <li>no mock control is needed for single Mock Objects
    <li>stub behavior replaces default behavior
    <li>support for call order checking for more than one mock, and to switch order checking on and off
    <li>support for callbacks
    <li>EasyMock now throws <code>java.lang.AssertionError</code> instead of <code>junit.framework.AssertionFailedError</code> so that it is now independent from the testing framework, you may use it with JUnit 3.8.x, JUnit 4 and TestNG
    <li>deprecated old API </li>
</ul>
<img src ="http://www.blogjava.net/yglwxl/aggbug/155581.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yglwxl/" target="_blank">九宝</a> 2007-10-24 13:53 <a href="http://www.blogjava.net/yglwxl/archive/2007/10/24/155581.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>EasyMock 2 使用指南(转)</title><link>http://www.blogjava.net/yglwxl/archive/2007/10/24/155579.html</link><dc:creator>九宝</dc:creator><author>九宝</author><pubDate>Wed, 24 Oct 2007 05:49:00 GMT</pubDate><guid>http://www.blogjava.net/yglwxl/archive/2007/10/24/155579.html</guid><wfw:comment>http://www.blogjava.net/yglwxl/comments/155579.html</wfw:comment><comments>http://www.blogjava.net/yglwxl/archive/2007/10/24/155579.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yglwxl/comments/commentRss/155579.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yglwxl/services/trackbacks/155579.html</trackback:ping><description><![CDATA[<p style="margin: 0cm 0cm 0pt; text-indent: 21pt">关于单元测试，模拟对象一直是不可缺少的，尤其对于复杂的应用来说。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这么多的模拟对象框架中，个人觉得比较好用的当属EasyMock了。当然JMock也不错。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 下面简单介绍一下EasyMock&nbsp;。（基本翻译EasyMock的文档，可能有些地方不是很恰当）<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;EasyMock 2 <span style="font-family: 宋体">主要用于给指定的接口提供模拟对象。</span> </p>
<p style="margin: 0cm 0cm 0pt; text-indent: 21pt"><span style="font-family: 宋体">模拟对象只是模拟领域代码直接的部分行为，能检测是否他们如定义中的被使用。使用</span> Mock <span style="font-family: 宋体">对象，来模拟合作接口，有助于隔离测试相应的领域类。</span> </p>
<p style="margin: 0cm 0cm 0pt; text-indent: 21pt"><span style="font-family: 宋体">创建和维持</span> Mock <span style="font-family: 宋体">对象经常是繁琐的任务，并且可能会引入错误。</span> EasyMock 2 <span style="font-family: 宋体">动态产生</span> Mock <span style="font-family: 宋体">对象，不需要创建，并且不会产生代码。</span> </p>
<p style="margin: 0cm 0cm 0pt; text-indent: 21pt"><span style="font-family: 宋体">有利的方面：</span> </p>
<p style="margin: 0cm 0cm 0pt; text-indent: 21pt"><span style="font-family: 宋体">不需要手工写类来处理</span> mock <span style="font-family: 宋体">对象。</span> </p>
<p style="margin: 0cm 0cm 0pt; text-indent: 21pt"><span style="font-family: 宋体">支持安全的重构</span> Mock <span style="font-family: 宋体">对象：测试代码不会在运行期打断当重新命名方法或者更改方法参数。</span> </p>
<p style="margin: 0cm 0cm 0pt; text-indent: 21pt"><span style="font-family: 宋体">支持返回值和例外。</span> </p>
<p style="margin: 0cm 0cm 0pt; text-indent: 21pt"><span style="font-family: 宋体">支持检察方法调用次序，对于一个或者多个</span> Mock <span style="font-family: 宋体">对象。</span> </p>
<p style="margin: 0cm 0cm 0pt; text-indent: 21pt"><span style="font-family: 宋体">不利的方面：</span> <font size="4"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">2.0</span> <span style="font-size: 10.5pt; font-family: 宋体">仅使用于</span> <span style="font-size: 10.5pt; font-family: 'Times New Roman'">java 2</span> <span style="font-size: 10.5pt; font-family: 宋体">版本</span> <span style="font-size: 10.5pt; font-family: 'Times New Roman'">5.0</span> </font><span style="font-size: 10.5pt; font-family: 宋体"><font size="4">或者以上</font> <br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
<br />
&nbsp;&nbsp;&nbsp; <font size="4">以一个例子来说明如何使用EasyMock:<br />
&nbsp;&nbsp;&nbsp;假设有一个合作接口<span style="font-size: 10.5pt; color: black">Collaborator：<br />
&nbsp;&nbsp;&nbsp;&nbsp;<font size="3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font></span></font>
<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
    <tbody>
        <tr>
            <td>
            <pre>
            <pre><span style="font-size: 10.5pt">package org.easymock.samples;</span></pre>
            <pre>&nbsp;</pre>
            <pre><span style="font-size: 10.5pt">public interface Collaborator {</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp; void documentAdded(String title);</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp; void documentChanged(String title);</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp; void documentRemoved(String title);</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp; byte voteForRemoval(String title);</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp; byte[] voteForRemovals(String[] title);</span></pre>
            <pre><span style="font-size: 10.5pt">}<font size="4"></font></span></pre>
            </pre>
            </td>
        </tr>
    </tbody>
</table>
</span></p>
我们主要的测试类为：<br />
<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
    <tbody>
        <tr>
            <td>
            <pre>
            <pre><span style="font-size: 10.5pt">package org.easymock.samples;</span><br />
            import java.util.HashMap;<br />
            import java.util.HashSet;<br />
            import java.util.Map;<br />
            import java.util.Set;</pre>
            <pre>public class ClassUnderTest {</pre>
            <pre>&nbsp;&nbsp;&nbsp; private Set&lt;Collaborator&gt; listeners = new HashSet&lt;Collaborator&gt;();</pre>
            <pre>&nbsp;&nbsp;&nbsp; private Map&lt;String, byte[]&gt; documents = new HashMap&lt;String, byte[]&gt;();</pre>
            <pre>&nbsp;&nbsp;&nbsp; public void addListener(Collaborator listener) {<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; listeners.add(listener);<br />
            &nbsp;&nbsp;&nbsp; }</pre>
            <pre>&nbsp;&nbsp;&nbsp; public void addDocument(String title, byte[] document) {<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; boolean documentChange = documents.containsKey(title);<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; documents.put(title, document);<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (documentChange) {<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; notifyListenersDocumentChanged(title);<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else {<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; notifyListenersDocumentAdded(title);<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
            &nbsp;&nbsp;&nbsp; }</pre>
            <pre>&nbsp;&nbsp;&nbsp; public boolean removeDocument(String title) {<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!documents.containsKey(title)) {<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return true;<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</pre>
            <pre>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!listenersAllowRemoval(title)) {<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return false;<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</pre>
            <pre>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; documents.remove(title);<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; notifyListenersDocumentRemoved(title);</pre>
            <pre>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return true;<br />
            &nbsp;&nbsp;&nbsp; }</pre>
            <pre>&nbsp;&nbsp;&nbsp; public boolean removeDocuments(String[] titles) {<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!listenersAllowRemovals(titles)) {<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return false;<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</pre>
            <pre>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (String title : titles) {<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; documents.remove(title);<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; notifyListenersDocumentRemoved(title);<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return true;<br />
            &nbsp;&nbsp;&nbsp; }</pre>
            <pre>&nbsp;&nbsp;&nbsp; private void notifyListenersDocumentAdded(String title) {<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (Collaborator listener : listeners) {<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; listener.documentAdded(title);<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
            &nbsp;&nbsp;&nbsp; }</pre>
            <pre>&nbsp;&nbsp;&nbsp; private void notifyListenersDocumentChanged(String title) {<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (Collaborator listener : listeners) {<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; listener.documentChanged(title);<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
            &nbsp;&nbsp;&nbsp; }</pre>
            <pre>&nbsp;&nbsp;&nbsp; private void notifyListenersDocumentRemoved(String title) {<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (Collaborator listener : listeners) {<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; listener.documentRemoved(title);<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
            &nbsp;&nbsp;&nbsp; }</pre>
            <pre>&nbsp;&nbsp;&nbsp; private boolean listenersAllowRemoval(String title) {<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int result = 0;<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (Collaborator listener : listeners) {<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; result += listener.voteForRemoval(title);<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return result &gt; 0;<br />
            &nbsp;&nbsp;&nbsp; }</pre>
            <pre>&nbsp;&nbsp;&nbsp; private boolean listenersAllowRemovals(String[] titles) {<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int result = 0;<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (Collaborator listener : listeners) {<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; result += listener.voteForRemovals(titles);<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return result &gt; 0;<br />
            &nbsp;&nbsp;&nbsp; }</pre>
            <pre>}</pre>
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<p style="margin: 0cm 0cm 0pt; text-indent: 21pt"><span style="background: lime 0% 50%; font-family: 宋体; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial">第一个</span><span style="background: lime 0% 50%; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial">Mock </span><span style="background: lime 0% 50%; font-family: 宋体; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial">对象</span></p>
<span style="font-size: 10.5pt; font-family: 宋体">我们将创建</span><span style="font-size: 10.5pt; font-family: 'Times New Roman'">test case </span><span style="font-size: 10.5pt; font-family: 宋体">并且围绕此理解相关的</span><span style="font-size: 10.5pt; font-family: 'Times New Roman'">EasyMock </span><span style="font-size: 10.5pt; font-family: 宋体">包的功能。第一个测试方法，用于检测是否删除一个不存在的文档，不会发通知给合作类。<br />
&nbsp;&nbsp;&nbsp;&nbsp;<font size="3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font>
<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
    <tbody>
        <tr>
            <td>
            <pre>
            <pre><span style="font-size: 10.5pt">
            <pre><span style="font-size: 10.5pt">package org.easymock.samples;</span></pre>
            <pre>&nbsp;</pre>
            <pre><span style="font-size: 10.5pt">import junit.framework.TestCase;</span></pre>
            <pre>&nbsp;</pre>
            <pre><span style="font-size: 10.5pt">public class ExampleTest extends TestCase {</span></pre>
            <pre>&nbsp;</pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp; private ClassUnderTest classUnderTest;</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp; private Collaborator mock;</span></pre>
            <pre>&nbsp;</pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp; protected void setUp() {</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; classUnderTest = new ClassUnderTest();</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; classUnderTest.addListener(mock);</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp; }</span></pre>
            <pre>&nbsp;</pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp; public void testRemoveNonExistingDocument() {&nbsp;&nbsp;&nbsp; </span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// This call should not lead to any notification</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;// of the Mock Object: </span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;classUnderTest.removeDocument("Does not exist");</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp; }</span></pre>
            <pre><span style="font-size: 10.5pt">}</span></pre>
            </span></pre>
            </pre>
            </td>
        </tr>
    </tbody>
</table>
</span><font face="宋体">&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 10.5pt; font-family: 宋体">对于多数测试类，使用</span><span style="font-size: 10.5pt; font-family: 'Times New Roman'">EasyMock 2,</span><span style="font-size: 10.5pt; font-family: 宋体">我们只需要静态引入</span></font><font face="宋体"><code><span style="font-size: 10.5pt; color: black">org.easymock.EasyMock</span></code><code><span style="font-size: 10.5pt; color: black">的方法。</span></code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font>
<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
    <tbody>
        <tr>
            <td>
            <pre>
            <pre>&nbsp;
            <p style="background: rgb(204,204,204) 0% 50%; margin: 0cm 0cm 0pt; text-align: left; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial" align="left"><span style="color: red; font-family: 'Courier New'">import static org.easymock.EasyMock.*;</span></p>
            <p style="background: rgb(204,204,204) 0% 50%; margin: 0cm 0cm 0pt; text-align: left; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial" align="left"><span style="color: black; font-family: 'Courier New'">import junit.framework.TestCase;</span></p>
            <p style="background: rgb(204,204,204) 0% 50%; margin: 0cm 0cm 0pt; text-align: left; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial" align="left"><span style="color: black; font-family: 'Courier New'">public class ExampleTest extends TestCase {</span></p>
            <p style="background: rgb(204,204,204) 0% 50%; margin: 0cm 0cm 0pt; text-align: left; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial" align="left"><span style="color: black; font-family: 'Courier New'">&nbsp;&nbsp;&nbsp; private ClassUnderTest classUnderTest;</span></p>
            <p style="background: rgb(204,204,204) 0% 50%; margin: 0cm 0cm 0pt; text-align: left; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial" align="left"><span style="color: black; font-family: 'Courier New'">&nbsp;&nbsp;&nbsp; private Collaborator mock;</span></p>
            <p style="background: rgb(204,204,204) 0% 50%; margin: 0cm 0cm 0pt; text-align: left; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial" align="left"><span style="color: black; font-family: 'Courier New'">&nbsp;&nbsp;&nbsp; </span></p>
            <p style="background: rgb(204,204,204) 0% 50%; margin: 0cm 0cm 0pt; text-align: left; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial" align="left"><span style="color: black; font-family: 'Courier New'">}</span></p>
            </pre>
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<font face="宋体">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<p style="margin: 0cm 0cm 0pt; text-indent: 21pt"><span style="font-family: 宋体">为了取得</span><font face="Times New Roman">Mock </font><span style="font-family: 宋体">对象，需要：</span></p>
<p style="margin: 0cm 0cm 0pt 45pt; text-indent: -21pt"><span style="font-family: Wingdings">l<span style="font: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 宋体">创建</span><font face="Times New Roman">Mock </font><span style="font-family: 宋体">对象从需要模拟的接口</span></p>
<p style="margin: 0cm 0cm 0pt 45pt; text-indent: -21pt"><span style="font-family: Wingdings">l<span style="font: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 宋体">记录期待的行为</span></p>
<p style="margin: 0cm 0cm 0pt 45pt; text-indent: -21pt"><span style="font-family: Wingdings">l<span style="font: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 宋体">转换到</span><font face="Times New Roman">Mock</font><span style="font-family: 宋体">对象，</span><font face="Times New Roman">replay</font><span style="font-family: 宋体">状态。</span></p>
<span style="font-size: 10.5pt; font-family: 宋体">例如：</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font>
<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
    <tbody>
        <tr>
            <td>
            <pre>
            <pre>&nbsp;
            <pre><span style="font-size: 10.5pt">protected void setUp() {</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp; </span><span style="font-size: 10.5pt; color: red">&nbsp;&nbsp;&nbsp;&nbsp;mock = createMock(Collaborator.class); // 1</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; classUnderTest = new ClassUnderTest();</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; classUnderTest.addListener(mock);</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp; }<br />
            <br />
            <pre><span style="font-size: 10.5pt">&nbsp;public void testRemoveNonExistingDocument() {</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 2 (we do not expect anything)</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-size: 10.5pt; color: red">replay(mock); // 3</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; classUnderTest.removeDocument("Does not exist");</span></pre>
            <span style="font-size: 10.5pt; font-family: 'Times New Roman'">&nbsp;&nbsp;&nbsp; }</span></span></pre>
            </pre>
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<font face="宋体">&nbsp;&nbsp;
<p style="margin: 0cm 0cm 0pt; text-indent: 21pt"><span style="font-family: 宋体">在执行第三步后，</span><font face="Times New Roman">mock </font><span style="font-family: 宋体">为</span><code><span style="color: black"><font face="宋体">Collaborator</font></span></code><span style="color: black; font-family: 宋体">接口的</span><font face="Times New Roman">Mock</font><span style="font-family: 宋体">对象，并且期待没有什么调用。这就意味着，如果我们改变</span><font face="Times New Roman">ClassUnderTest</font><span style="font-family: 宋体">去调用此接口的任何方法，则</span><font face="Times New Roman">Mock</font><span style="font-family: 宋体">对象会抛出</span><font face="Times New Roman">AssertionError</font><span style="font-family: 宋体">：</span></p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font>
<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
    <tbody>
        <tr>
            <td>
            <pre>
            <pre>&nbsp;
            <pre><span style="font-size: 10.5pt">java.lang.AssertionError: </span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;Unexpected method call documentRemoved("Does not exist"):</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp; at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:29)</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp; at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:44)</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp; at $Proxy0.documentRemoved(Unknown Source)</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp; at org.easymock.samples.ClassUnderTest.notifyListenersDocumentRemoved(ClassUnderTest.java:74)</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp; at org.easymock.samples.ClassUnderTest.removeDocument(ClassUnderTest.java:33)</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp; at org.easymock.samples.ExampleTest.testRemoveNonExistingDocument(ExampleTest.java:24)</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp; ...</span></pre>
            </pre>
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<p style="margin: 0cm 0cm 0pt; text-indent: 21pt"><span style="background: lime 0% 50%; font-family: 宋体; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial">增加行为</span></p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">让我们开始第二个测试。如果</span>document<span style="font-family: 宋体">被</span>classUnderTest<span style="font-family: 宋体">增加，我们期待调用</span><br />
<font face="宋体"><code><span style="color: black">mock.documentAdded()</span></code><code><span style="color: black">在Mock对象使用document的标题作为参数：</span></code></font><br />
<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
    <tbody>
        <tr>
            <td>
            <pre>
            <pre>&nbsp;
            <pre><span style="font-size: 10.5pt">&nbsp;public void testAddDocument() {</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-size: 10.5pt; color: red">&nbsp;mock.documentAdded("New Document");</span><span style="font-size: 10.5pt"> // 2</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; replay(mock); // 3</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; classUnderTest.addDocument("New Document", new byte[0]); </span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp;&nbsp;}</span></pre>
            </pre>
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<span style="font-size: 10.5pt; font-family: 宋体">如果</span><font face="宋体"><code><span style="font-size: 10.5pt; color: black">classUnderTest.addDocument("New Document", new byte[0])</span></code><code><span style="font-size: 10.5pt; color: black">调用期待的方法，使用错误的参数，Mock对象会抛出AssertionError:</span></code></font><br />
<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
    <tbody>
        <tr>
            <td>
            <pre>
            <pre>&nbsp;
            <pre><span style="font-size: 10.5pt">java.lang.AssertionError: </span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;Unexpected method call documentAdded("Wrong title"):</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp; documentAdded("New Document"): expected: 1, actual: 0</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp; at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:29)</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp; at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:44)</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp; at $Proxy0.documentAdded(Unknown Source)</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp; at org.easymock.samples.ClassUnderTest.notifyListenersDocumentAdded(ClassUnderTest.java:61)</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp; at org.easymock.samples.ClassUnderTest.addDocument(ClassUnderTest.java:28)</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp; at org.easymock.samples.ExampleTest.testAddDocument(ExampleTest.java:30)</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp; ...</span></pre>
            </pre>
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<p style="margin: 0cm 0cm 0pt; text-indent: 21pt"><span style="font-family: 宋体">同样，如果调用多次此方法，则也会抛出例外：</span><br />
</p>
<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
    <tbody>
        <tr>
            <td>
            <pre>
            <pre>&nbsp;
            <pre><span style="font-size: 10.5pt">java.lang.AssertionError: </span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;Unexpected method call documentAdded("New Document"):</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp; documentAdded("New Document"): expected: 1, actual: 1 (+1)</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp; at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:29)</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp; at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:44)</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp; at $Proxy0.documentAdded(Unknown Source)</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp; at org.easymock.samples.ClassUnderTest.notifyListenersDocumentAdded(ClassUnderTest.java:62)</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp; at org.easymock.samples.ClassUnderTest.addDocument(ClassUnderTest.java:29)</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp; at org.easymock.samples.ExampleTest.testAddDocument(ExampleTest.java:30)</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp; ...</span></pre>
            </pre>
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<p style="margin: 0cm 0cm 0pt; text-indent: 21pt"><span style="background: lime 0% 50%; font-family: 宋体; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial">验证行为</span></p>
<p style="margin: 0cm 0cm 0pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">当我们指定行为后，我们将验证实际发生的。当前的测试将会判断是否</span>Mock<span style="font-family: 宋体">对象会真实调用。可以调用</span><font face="宋体"><code><span style="color: black">verify(mock)</span></code><code><span style="color: black">来山正是否指定的行为被调用。</span></code></font><br />
</p>
<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
    <tbody>
        <tr>
            <td>
            <pre>
            <pre>&nbsp;
            <pre><span style="font-size: 10.5pt">public void testAddDocument() {</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mock.documentAdded("New Document"); // 2 </span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;replay(mock); // 3</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; classUnderTest.addDocument("New Document", new byte[0]);</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-size: 10.5pt; color: red">&nbsp;verify(mock);</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp; }</span></pre>
            </pre>
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<p style="margin: 0cm 0cm 0pt; text-indent: 21pt"><span style="font-family: 宋体">如果失败，则抛出</span>AssertionError</p>
<p style="margin: 0cm 0cm 0pt; text-indent: 21pt"><span style="background: lime 0% 50%; font-family: 宋体; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial">期待明显数量的调用</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-size: 10.5pt; font-family: 宋体">到现在，我们的测试只是调用一个简单的方法。下一个测试将会检测是否已经存在</span><span style="font-size: 10.5pt; font-family: 'Times New Roman'">document</span><span style="font-size: 10.5pt; font-family: 宋体">导致</span><font face="宋体"><code><span style="font-size: 10.5pt; color: black">mock.documentChanged()</span></code><code><span style="font-size: 10.5pt; color: black">调用。为了确认，调用三次</span></code></font></p>
<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
    <tbody>
        <tr>
            <td>
            <pre>
            <pre>&nbsp;
            <pre><span style="font-size: 10.5pt">public void testAddAndChangeDocument() {</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mock.documentAdded("Document");</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mock.documentChanged("Document");</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mock.documentChanged("Document");</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mock.documentChanged("Document");</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; replay(mock);</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; classUnderTest.addDocument("Document", new byte[0]);</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; classUnderTest.addDocument("Document", new byte[0]);</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; classUnderTest.addDocument("Document", new byte[0]);</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; classUnderTest.addDocument("Document", new byte[0]);</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; verify(mock);</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp; }</span></pre>
            </pre>
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<p style="margin: 0cm 0cm 0pt; text-indent: 21pt"><span style="font-family: 宋体">为了避免重复的</span><code><span style="color: black"><font face="宋体">mock.documentChanged("Document")</font></span></code><span style="color: black; font-family: Arial">,EasyMock</span><span style="color: black; font-family: 宋体">提供一个快捷方式。可以通过调用方法</span><font face="宋体"><code><span style="color: black">expectLastCall().times(int times)</span></code><code><span style="color: black">来指定最后一次调用的次数。</span></code></font><br />
</p>
<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
    <tbody>
        <tr>
            <td>
            <pre>
            <pre>&nbsp;
            <pre><span style="font-size: 10.5pt">&nbsp;public void testAddAndChangeDocument() {</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mock.documentAdded("Document");</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mock.documentChanged("Document");</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-size: 10.5pt; color: red">expectLastCall().times(3);</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; replay(mock);</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; classUnderTest.addDocument("Document", new byte[0]);</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; classUnderTest.addDocument("Document", new byte[0]);</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; classUnderTest.addDocument("Document", new byte[0]);</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; classUnderTest.addDocument("Document", new byte[0]);</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; verify(mock);</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp; }</span></pre>
            </pre>
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p style="margin: 0cm 0cm 0pt; text-indent: 21pt"><span style="background: lime 0% 50%; font-family: 宋体; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial">指定返回值</span></p>
<p style="margin: 0cm 0cm 0pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">对于指定返回值，我们通过封装</span><font face="宋体"><code><span style="color: black">expect(T value)</span></code><code><span style="color: black">返回的对象并且指定返回的值，使用方法andReturn(Object returnValue)于expect(T value)</span></code></font><span style="color: black; font-family: Arial">.</span><span style="color: black; font-family: 宋体">返回的对象。</span></p>
<p style="margin: 0cm 0cm 0pt; text-indent: 21pt"><span style="color: black; font-family: 宋体">例如：</span></p>
<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
    <tbody>
        <tr>
            <td>
            <pre>
            <pre>&nbsp;
            <pre><span style="font-size: 10.5pt">public void testVoteForRemoval() {</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mock.documentAdded("Document");&nbsp;&nbsp; // expect document addition</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // expect to be asked to vote for document removal, and vote for it</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-size: 10.5pt; color: red">expect(mock.voteForRemoval("Document")).andReturn((byte) 42);</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mock.documentRemoved("Document"); // expect document removal</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; replay(mock);</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; classUnderTest.addDocument("Document", new byte[0]);</span></pre>
            <pre style="margin-left: 42pt; text-indent: -42pt"><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; assertTrue(classUnderTest.removeDocument("Document"));</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; verify(mock);</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp; } </span></pre>
            <pre>&nbsp;</pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp; public void testVoteAgainstRemoval() {</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mock.documentAdded("Document");&nbsp;&nbsp; // expect document addition</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // expect to be asked to vote for document removal, and vote against it</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-size: 10.5pt; color: red">expect(mock.voteForRemoval("Document")).andReturn((byte) -42);</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; replay(mock);</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; classUnderTest.addDocument("Document", new byte[0]);</span></pre>
            <pre style="margin-left: 42pt; text-indent: -42pt"><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; assertFalse(classUnderTest.removeDocument("Document"));</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;verify(mock);</span></pre>
            <pre><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp; }</span></pre>
            </pre>
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<span style="font-size: 10.5pt; font-family: 宋体">取代</span><font face="宋体"><code><span style="font-size: 10.5pt; color: black">expect(T value)</span></code><code><span style="font-size: 10.5pt; color: black">调用，可以通过expectLastCall()</span></code></font><span style="font-size: 10.5pt; color: black; font-family: Arial">.</span><span style="font-size: 10.5pt; color: black; font-family: 宋体">来代替</span><br />
<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
    <tbody>
        <tr>
            <td>
            <pre>
            <pre>&nbsp;<span style="font-size: 10.5pt; font-family: 'Times New Roman'">expect(mock.voteForRemoval("Document")).andReturn((byte) 42);</span></pre>
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<p style="margin: 0cm 0cm 0pt; text-indent: 21pt"><span style="font-family: 宋体">等同于</span><br />
</p>
<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
    <tbody>
        <tr>
            <td>
            <pre>
            <pre>&nbsp;
            <pre><span style="font-size: 10.5pt">mock.voteForRemoval("Document");</span></pre>
            <pre><span style="font-size: 10.5pt">expectLastCall().andReturn((byte) 42);</span></pre>
            </pre>
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<p style="margin: 0cm 0cm 0pt; text-indent: 21pt"><span style="background: lime 0% 50%; font-family: 宋体; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial">处理例外</span></p>
<p style="margin: 0cm 0cm 0pt; text-indent: 21pt"><span style="font-family: 宋体">对于指定的例外</span>(<span style="font-family: 宋体">更确切的</span>:Throwables)<span style="font-family: 宋体">被抛出，由</span><font face="宋体"><code><span style="font-size: 12pt; color: black">expectLastCall()</span></code><code><span style="font-size: 12pt; color: black">和expect(T value)</span></code><span style="font-family: 宋体">返回的对象，提供了方法</span><code><span style="font-size: 12pt; color: black">andThrow(Throwable throwable)</span></code><code><span style="font-size: 12pt; color: black">。方法不得不被调用记录状态，在调用Mock对象后，对于此指定了要抛出的Throwable。</span></code></font></p>
<br />
基本的方法，已经说完了，当然这不能完全说明EasyMock的使用。更多的因素请参考EasyMock的文档<br />
<a href="http://www.easymock.org/Documentation.html">http://www.easymock.org/Documentation.html</a>
<img src ="http://www.blogjava.net/yglwxl/aggbug/155579.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yglwxl/" target="_blank">九宝</a> 2007-10-24 13:49 <a href="http://www.blogjava.net/yglwxl/archive/2007/10/24/155579.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JUnit 学习笔记 2007版(转)</title><link>http://www.blogjava.net/yglwxl/archive/2007/10/24/155564.html</link><dc:creator>九宝</dc:creator><author>九宝</author><pubDate>Wed, 24 Oct 2007 05:10:00 GMT</pubDate><guid>http://www.blogjava.net/yglwxl/archive/2007/10/24/155564.html</guid><wfw:comment>http://www.blogjava.net/yglwxl/comments/155564.html</wfw:comment><comments>http://www.blogjava.net/yglwxl/archive/2007/10/24/155564.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yglwxl/comments/commentRss/155564.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yglwxl/services/trackbacks/155564.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 一、简介&nbsp;&nbsp;&nbsp;&nbsp;JUnit是一款由Erich Gamma（《设计模式》的作者）和Kent Beck（极限编程的提出者）编写的开源的回归测试框架，供Java编码人员做单元测试之用。当前版本4.1，可以从www.junit.org网站上获得。与早期的JUnit 3相比，JUnit 4.1依赖于Java 5.0的新特性，因此无法兼容于jdk 1.4，可以说是一...&nbsp;&nbsp;<a href='http://www.blogjava.net/yglwxl/archive/2007/10/24/155564.html'>阅读全文</a><img src ="http://www.blogjava.net/yglwxl/aggbug/155564.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yglwxl/" target="_blank">九宝</a> 2007-10-24 13:10 <a href="http://www.blogjava.net/yglwxl/archive/2007/10/24/155564.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Windows 下java获得文件创建时间的办法 (转)</title><link>http://www.blogjava.net/yglwxl/archive/2007/10/23/155224.html</link><dc:creator>九宝</dc:creator><author>九宝</author><pubDate>Tue, 23 Oct 2007 03:20:00 GMT</pubDate><guid>http://www.blogjava.net/yglwxl/archive/2007/10/23/155224.html</guid><wfw:comment>http://www.blogjava.net/yglwxl/comments/155224.html</wfw:comment><comments>http://www.blogjava.net/yglwxl/archive/2007/10/23/155224.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yglwxl/comments/commentRss/155224.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yglwxl/services/trackbacks/155224.html</trackback:ping><description><![CDATA[public static String getFileCreateDate(File _file){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; File file=_file;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;Process ls_proc = Runtime.getRuntime().exec("cmd.exe /c dir " + file.getAbsolutePath() + " /tc");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;DataInputStream in = new DataInputStream(ls_proc.getInputStream());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;for (int i = 0; i &lt; 5; i++ )<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;in.readLine();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;String stuff = in.readLine();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;StringTokenizer st = new StringTokenizer(stuff);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;String dateC = st.nextToken();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String&nbsp; time=st.nextToken();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; in.close();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return dateC;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;}catch (Exception e){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;return null;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;}<br />
&nbsp;}<br />
<br />
在jdk中，File的操作并没有取得文件创建时间的方法。唯一提供提供的方法是<strong>lastModified</strong>()返回long值。牺牲创建时间的方法实在是为了满足跨平台的需要。但在windows环境中，需要取得文件创建时间的情况是存在的。<br />
实现的办法是通过windows本地命令行来取得创建日期。以上代码主要取自http://forum.java.sun.com/thread.jspa?threadID=311281&amp;messageID=1247450<br />
但此文提供的原始代码尚有不足，无法解析带有空格的文件夹名，如:C:\\Program files\等，解决办法是在路径前后加上"，执行语句变为<span id="_50_603_Open_Text"><span id="_81_543_Open_Text"><span style="color: rgb(0,0,0)">"</span><span style="color: rgb(0,0,0)">cmd.exe&nbsp;/c&nbsp;dir&nbsp;"</span><span style="color: rgb(0,0,0)">"</span><span style="color: rgb(0,0,0)">&nbsp;</span><span style="color: rgb(0,0,0)">+</span><span style="color: rgb(0,0,0)">&nbsp;file.getAbsolutePath()&nbsp;</span><span style="color: rgb(0,0,0)">+</span><span style="color: rgb(0,0,0)">&nbsp;</span><span style="color: rgb(0,0,0)">"</span><span style="color: rgb(0,0,0)">"&nbsp;/tc</span><span style="color: rgb(0,0,0)">"。以上方法返回的是我实际程序需要的数据格式，大家有兴趣可以自行改编</span></span></span>
<img src ="http://www.blogjava.net/yglwxl/aggbug/155224.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yglwxl/" target="_blank">九宝</a> 2007-10-23 11:20 <a href="http://www.blogjava.net/yglwxl/archive/2007/10/23/155224.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>