﻿<?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-【永恒的瞬间】  -文章分类-Java基础</title><link>http://www.blogjava.net/19851985lili/category/18943.html</link><description>☜GivE mE HapPy ☞




</description><language>zh-cn</language><lastBuildDate>Tue, 15 May 2007 11:54:50 GMT</lastBuildDate><pubDate>Tue, 15 May 2007 11:54:50 GMT</pubDate><ttl>60</ttl><item><title>java.io.Serializable 初探序列化</title><link>http://www.blogjava.net/19851985lili/articles/117528.html</link><dc:creator>☜♥☞MengChuChen</dc:creator><author>☜♥☞MengChuChen</author><pubDate>Tue, 15 May 2007 02:37:00 GMT</pubDate><guid>http://www.blogjava.net/19851985lili/articles/117528.html</guid><wfw:comment>http://www.blogjava.net/19851985lili/comments/117528.html</wfw:comment><comments>http://www.blogjava.net/19851985lili/articles/117528.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/19851985lili/comments/commentRss/117528.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/19851985lili/services/trackbacks/117528.html</trackback:ping><description><![CDATA[<dl>
<dt>
<pre>序列化是什么：<br>序列化就是将一个对象的状态（各个属性量）保存起来，然后在适当的时候再获得。<br>序列化分为两大部分：序列化和反序列化。序列化是这个过程的第一部分，将数据分解成字节流，以便存储在文件中或在网络上传输。反序列化就是打开字节流并重构对象。对象序列化不仅要将基本数据类型转换成字节表示，有时还要恢复数据。恢复数据要求有恢复数据的对象实例<br><br><br>序列化的什么特点：<br>如果某个类能够被序列化，其子类也可以被序列化。声明为static和transient类型的成员数据不能被序列化。因为static代表类的状态， transient代表对象的临时数据。<br>public interface <strong>Serializable (API5.0)</strong></pre>
</dt></dl>
<pre></pre>
<p>类通过实现 java.io.Serializable 接口以启用其序列化功能。未实现此接口的类将无法使其任何状态序列化或反序列化。可序列化类的所有子类型本身都是可序列化的。序列化接口没有方法或字段，仅用于标识可序列化的语义。
<p>要允许不可序列化类的子类型序列化，可以假定该子类型负责保存和还原超类型的公用 (public)、受保护的 (protected) 和（如果可访问）包 (package) 字段的状态。仅在子类型扩展的类有一个可访问的无参数构造方法来初始化该类的状态时，才可以假定子类型有此责任。如果不是这种情况，则声明一个类为可序列化类是错误的。该错误将在运行时检测到。
<p>在反序列化过程中，将使用该类的公用或受保护的无参数构造方法初始化不可序列化类的字段。可序列化的子类必须能够访问无参数的构造方法。可序列化子类的字段将从该流中还原。
<p>当遍历一个图形时，可能会遇到不支持可序列化接口的对象。在此情况下，将抛出 NotSerializableException，并将标识不可序列化对象的类。
<p>在序列化和反序列化过程中需要特殊处理的类必须使用下列准确签名来实现特殊方法：
<p>
<pre> private void writeObject(java.io.ObjectOutputStream out)
throws IOException
private void readObject(java.io.ObjectInputStream in)
throws IOException, ClassNotFoundException;
</pre>
<p>writeObject 方法负责写入特定类的对象的状态，以便相应的 readObject 方法可以还原它。通过调用 out.defaultWriteObject 可以调用保存 Object 的字段的默认机制。该方法本身不需要涉及属于其超类或子类的状态。状态是通过使用 writeObject 方法或使用 DataOutput 支持的用于基本数据类型的方法将各个字段写入 ObjectOutputStream 来保存的。
<p>readObject 方法负责从流中读取并还原类字段。它可以调用 in.defaultReadObject 来调用默认机制，以还原对象的非静态和非瞬态字段。defaultReadObject 方法使用流中的信息来分配流中通过当前对象中相应命名字段保存的对象的字段。这用于处理类发展后需要添加新字段的情形。该方法本身不需要涉及属于其超类或子类的状态。状态是通过使用 writeObject 方法或使用 DataOutput 支持的用于基本数据类型的方法将各个字段写入 ObjectOutputStream 来保存的。
<p>将对象写入流时需要指定要使用的替代对象的可序列化类，应使用准确的签名来实现此特殊方法：
<p>
<pre> ANY-ACCESS-MODIFIER Object writeReplace() throws ObjectStreamException;
</pre>
<p>此 writeReplace 方法将由序列化调用，前提是如果此方法存在，而且它可以通过被序列化对象的类中定义的一个方法访问。因此，该方法可以拥有私有 (private)、受保护的 (protected) 和包私有 (package-private) 访问。子类对此方法的访问遵循 java 访问规则。
<p>在从流中读取类的一个实例时需要指定替代的类应使用的准确签名来实现此特殊方法。
<p>
<pre> ANY-ACCESS-MODIFIER Object readResolve() throws ObjectStreamException;
</pre>
<p>此 readResolve 方法遵循与 writeReplace 相同的调用规则和访问规则。
<p>序列化运行时使用一个称为 serialVersionUID 的版本号与每个可序列化类相关联，该序列号在反序列化过程中用于验证序列化对象的发送者和接收者是否为该对象加载了与序列化兼容的类。如果接收者加载的该对象的类的 serialVersionUID 与对应的发送者的类的版本号不同，则反序列化将会导致 <a title="java.io 中的类" href="mk:@MSITStore:C:\Documents%20and%20Settings\LILY\デスクトップ\jdk150.chm::/jdk150/api/java/io/InvalidClassException.html"><code><u><font color=#0000ff>InvalidClassException</font></u></code></a>。可序列化类可以通过声明名为 <code>"serialVersionUID"</code> 的字段（该字段必须是静态 (static)、最终 (final) 的 <code>long</code> 型字段）显式声明其自己的 serialVersionUID：
<p>
<pre> ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;
</pre>
<p>如果可序列化类未显式声明 serialVersionUID，则序列化运行时将基于该类的各个方面计算该类的默认 serialVersionUID 值，如&#8220;Java(TM) 对象序列化规范&#8221;中所述。不过，<em>强烈建议</em> 所有可序列化类都显式声明 serialVersionUID 值，原因计算默认的 serialVersionUID 对类的详细信息具有较高的敏感性，根据编译器实现的不同可能千差万别，这样在反序列化过程中可能会导致意外的 <code>InvalidClassException</code>。因此，为保证 serialVersionUID 值跨不同 java 编译器实现的一致性，序列化类必须声明一个明确的 serialVersionUID 值。还强烈建议使用 <code>private</code> 修改器显示声明 serialVersionUID（如果可能），原因是这种声明仅应用于立即声明类 -- serialVersionUID 字段作为继承成员没有用处<br><br><strong>实用意义:<br></strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一：对象序列化可以实现分布式对象。主要应用例如：RMI要利用对象序列化运行远程主机上的服务，就像在本地机上运行对象时一样。<br>二：java对象序列化不仅保留一个对象的数据，而且递归保存对象引用的每个对象的数据。可以将整个对象层次写入字节流中，可以保存在文件中或在网络连接上传递。利用对象序列化可以进行对象的&#8220;深复制&#8221;，即复制对象本身及引用的对象本身。序列化一个对象可能得到整个对象序列。<br><br><strong>EP:<br></strong><span style="COLOR: #0000ff"><font color=#000000>import java.io.Serializable;<br>import java.io.FileOutputStream;<br>import java.io.ObjectOutputStream;<br>import java.io.FileInputStream;<br>import java.io.ObjectInputStream;</font></span></p>
<p><span style="COLOR: #0000ff"><font color=#000000>class MeTree implements Serializable {<br>&nbsp;private static final long serialVersionUID = 42L;<br>&nbsp;public MeTree left;<br>&nbsp;public MeTree right; <br>&nbsp;public int&nbsp; id; <br>&nbsp;public int level; <br>&nbsp;&nbsp;&nbsp; private static int count&nbsp; =&nbsp;&nbsp; 0 ;&nbsp;</font></span></p>
<p><span style="COLOR: #0000ff"><font color=#000000>&nbsp;&nbsp;&nbsp; public&nbsp; MeTree( int&nbsp; depth)&nbsp;&nbsp; { <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; id&nbsp; = count ++ ; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; level&nbsp; =&nbsp; depth; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if&nbsp; (depth&nbsp; &gt;&nbsp;&nbsp; 0 )&nbsp;&nbsp; { <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; left&nbsp; =&nbsp;&nbsp; new&nbsp; MeTree(depth - 1 ); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; right&nbsp; =&nbsp;&nbsp; new&nbsp; MeTree(depth - 1 ); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp; public&nbsp;&nbsp; void&nbsp; print( int&nbsp; levels)&nbsp;&nbsp; { <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for&nbsp; ( int&nbsp; i&nbsp; =&nbsp;&nbsp; 0 ; i&nbsp; &lt;&nbsp; level; i ++ ) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.print( "&nbsp;&nbsp;&nbsp; " ); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println( " node&nbsp; "&nbsp;&nbsp; +&nbsp; id); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if&nbsp; (level&nbsp; &lt;=&nbsp; levels&nbsp; &amp;&amp;&nbsp; left&nbsp; !=&nbsp;&nbsp; null ) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; left.print(levels);&nbsp;</font></span></p>
<p><span style="COLOR: #0000ff"><font color=#000000>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if&nbsp; (level&nbsp; &lt;=&nbsp; levels&nbsp; &amp;&amp;&nbsp; right&nbsp; !=&nbsp;&nbsp; null ) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; right.print(levels); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp; }</font></span></p>
<p><span style="COLOR: #0000ff"><font color=#000000></font></span>&nbsp;</p>
<p><span style="COLOR: #0000ff"><font color=#000000>&nbsp;&nbsp;&nbsp;&nbsp; public&nbsp;&nbsp; static&nbsp;&nbsp; void&nbsp; main (String argv[])&nbsp;&nbsp; { </font></span></p>
<p><span style="COLOR: #0000ff"><font color=#000000>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try&nbsp;&nbsp;&nbsp; { <br>&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; FileOutputStream ostream&nbsp; =&nbsp;&nbsp; new&nbsp; FileOutputStream( " MeTree.tmp " ); <br>&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; ObjectOutputStream p&nbsp; =&nbsp;&nbsp; new&nbsp; ObjectOutputStream(ostream); </font></span></p>
<p><span style="COLOR: #0000ff"><font color=#000000>&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; MeTree base&nbsp; =&nbsp;&nbsp; new&nbsp; MeTree( 2 ); </font></span></p>
<p><span style="COLOR: #0000ff"><font color=#000000>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; p.writeObject(base);&nbsp; // 将树写入流中。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; p.writeObject( " LiLy is 惠止南国 " );<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; p.flush(); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ostream.close();&nbsp;&nbsp;&nbsp;&nbsp; // 关闭文件。<br>&nbsp;<br>&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; FileInputStream istream&nbsp; =&nbsp;&nbsp; new&nbsp; FileInputStream( " MeTree.tmp " ); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ObjectInputStream q&nbsp; =&nbsp;&nbsp; new&nbsp; ObjectInputStream(istream); </font></span></p>
<p><span style="COLOR: #0000ff"><font color=#000000>&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; MeTree new_MeTree&nbsp; =&nbsp; (MeTree)q.readObject(); </font></span></p>
<p><span style="COLOR: #0000ff"><font color=#000000>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new_MeTree.print( 2 );&nbsp;&nbsp; // 打印出树形结构的最上面 ２级<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String name&nbsp; =&nbsp; (String)q.readObject();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println( " \n " + name);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp; catch&nbsp; (Exception ex)&nbsp;&nbsp; { <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ex.printStackTrace(); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp; }<br>}<br></font></span></p>
<p>可以看到，在序列化的时候，writeObject与readObject之间的先后顺序。readObject将最先write的object read出来。用数据结构的术语来讲就姑且称之为先进先出吧！<br><font color=#000080><strong>在序列化时，有几点要注意的：<br></strong>　&nbsp; １：当一个对象被序列化时，只保存对象的非静态成员变量，不能保存任何的成员方法和静态的成员变量。<br>　　２：如果一个对象的成员变量是一个对象，那么这个对象的数据成员也会被保存。<br>　　３：如果一个可序列化的对象包含对某个不可序列化的对象的引用，那么整个序列化操作将会失败，并且会抛出一个NotSerializableException。我们可以将这个引用标记为transient，那么对象仍然可以序列化</font><br><br><font color=#000080>还有我们对某个对象进行序列化时候，往往对整个对象全部序列化了，比如说类里有些数据比较敏感，不希望序列化，一个方法可以用transient来标识，另一个方法我们可以在类里重写</font>&nbsp;<br><br>可以通过指定关键transient使对象中的某个数据元素不被还原，这种方式常用于安全上的保护。比如对象中保存的密码。<br><span style="COLOR: red">//**</span><br>transient 只能用在类的成员变量上,不能用在方法里.&nbsp;<br>transient 变量不能是final和static的 </p>
<p>transient（临时）关键字<br>控制序列化过程时，可能有一个特定的子对象不愿让Java的序列化机制自动保存与恢复。一般地，若那个子对象包含了不想序列化的敏感信息（如密码），就会面临这种情况。即使那种信息在对象中具有&#8220;private&#8221;（私有）属性，但一旦经序列化处理，人们就可以通过读取一个文件，或者拦截网络传输得到它。<br>为防止对象的敏感部分被序列化，一个办法是将自己的类实现为Externalizable，就象前面展示的那样。这样一来，没有任何东西可以自动序列化，只能在writeExternal()明确序列化那些需要的部分。<br>然而，若操作的是一个Serializable对象，所有序列化操作都会自动进行。为解决这个问题，可以用transient（临时）逐个字段地关闭序列化，它的意思是&#8220;不要麻烦你（指自动机制）保存或恢复它了——我会自己处理的&#8221;。<br>例如，假设一个Login对象包含了与一个特定的登录会话有关的信息。校验登录的合法性时，一般都想将数据保存下来，但不包括密码。为做到这一点，最简单的办法是实现Serializable，并将password字段设为transient。<br><br>password被设为transient，所以不会自动保存到磁盘；另外，自动序列化机制也不会作恢复它的尝试。<br><br>一旦对象恢复成原来的样子，password字段就会变成null。注意必须用toString()检查password是否为null，因为若用过载的&#8220;+&#8221;运算符来装配一个String对象，而且那个运算符遇到一个null句柄，就会造成一个名为NullPointerException的违例（新版Java可能会提供避免这个问题的代码）。<br>我们也发现date字段被保存到磁盘，并从磁盘恢复，没有重新生成。<br>由于Externalizable对象默认时不保存它的任何字段，所以transient关键字只能伴随Serializable使用。</p>
<p><span style="COLOR: red">**//<font color=#000080>　还有我们对某个对象进行序列化时候，往往对整个对象全部序列化了，比如说类里有些数据比较敏感，不希望序列化，一个方法可以用transient来标识，另一个方法我们可以在类里重写</font> <br><br></p>
<pre><span style="COLOR: #000000">1、实现Serializable会导致发布的API难以更改，并且使得package-private和private
这两个本来封装的较好的咚咚也不能得到保障
2、Serializable会为每个类生成一个序列号，生成依据是类名、类实现的接口名、
public和protected方法，所以只要你一不小心改了一个已经publish的API，并且没有自
己定义一个long类型的叫做serialVersionUID的field，哪怕只是添加一个getXX，就会
让你读原来的序列化到文件中的东西读不出来（不知道为什么要把方法名算进去？）
3、不用构造函数用Serializable就可以构造对象，看起来不大合理，这被称为
extralinguistic mechanism，所以当实现Serializable时应该注意维持构造函数中所维
持的那些不变状态
4、增加了发布新版本的类时的测试负担
5、1.4版本后，JavaBeans的持久化采用基于XML的机制，不再需要Serializable6、设计用来被继承的类时，尽量不实现Serializable，用来被继承的interface也不要
继承Serializable。但是如果父类不实现Serializable接口，子类很难实现它，特别是
对于父类没有可以访问的不含参数的构造函数的时候。所以，一旦你决定不实现
Serializable接口并且类被用来继承的时候记得提供一个无参数的构造函数
7、内部类还是不要实现Serializable好了，除非是static的，(偶也觉得内部类不适合
用来干这类活的)
8、使用一个自定义的序列化方法<br>  看看下面这个保存一个双向链表的例子：<br><br><br><br>publicclass StringList implementsSerializable<br>{<br>?privateint size = 0;<br>?private Entry head = null;<br>?<br>?privatestaticclass Entry implements Serializable<br>?{<br>? String data;<br>? Entry next;<br>? Entry previous;<br>?}<br>?...//Remainder ommitted<br>}<br>
这样会导致链表的每个元素以及元素之间的关系（双向链表之间的连接）<br>都保存下来，更好的方法是提供一个自定义的序列化如下：
//String List with a resonable custom serialized form<br>class StringList implementsSerializable<br>{<br>? privatetransientint size = 0;?????? //!transient<br>? privatetransient Entry head = null;? //!transient<br>? <br>? //no longer serializable!<br>? privatestaticclass Entry<br>? {<br>??? String data;<br>??? Entry next;<br>??? Entry previous;<br>? }<br>? <br>? //Appends the specified string to the list<br>? publicvoid add(String s) {/*...*/};<br>? <br>? /**<br>?? * Serialize this <code>StringList</code> instance <br>?? * @author yuchifang<br>?? * @serialData The size of the list (the number of strings<br>   * it contains) is emitted(int), in the proper sequence<br>?? */<br>? privatevoid writeObject(ObjectOutputStream s)<br>throws IOException<br>? {<br>??? s.defaultWriteObject();<br>??? s.writeInt(size);<br>??? //Write out all elements in the proper order<br>??? for (Entry e = head; e != null; e = e.next)<br>????? s.writeObject(e.data);<br>? }<br>? <br>? privatevoid readObject(ObjectInputStream s)<br>throws IOException, ClassNotFoundException<br>? {<br>??? int numElements = s.readInt();<br>??? <br>??? //Read in all elements andd insert them in list<br>??? for (int i = 0; i &lt; numElements; i++)<br>????? add((String)s.readObject());<br>? }<br>? //...remainder omitted<br>}<br>9、不管你选择什么序列化形式，声明一个显式的UID：
private static final long serialVersionUID = randomLongValue;10、不需要序列化的东西使用transient注掉它吧，别什么都留着
11、writeObject/readObject重载以完成更好的序列化
readResolve 与 writeReplace重载以完成更好的维护invariant controllers</span></span><br><br><br>&nbsp;&nbsp;完全定制序列化过程:<br><br>如果一个类要完全负责自己的序列化，则实现Externalizable接口而不是Serializable接口。Externalizable接口定义包括两个方法writeExternal()与readExternal()。利用这些方法可以控制对象数据成员如何写入字节流.类实现Externalizable时，头写入对象流中，然后类完全负责序列化和恢复数据成员，除了头以外，根本没有自动序列化。这里要注意了。声明类实现Externalizable接口会有重大的安全风险。writeExternal()与readExternal()方法声明为public，恶意类可以用这些方法读取和写入对象数据。如果对象包含敏感信息，则要格外小心。这包括使用安全套接或加密整个字节流。到此为至，我们学习了序列化的基础部分知识。关于序<br>列化的高级教程，以后再述。<br></pre>
<img src ="http://www.blogjava.net/19851985lili/aggbug/117528.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/19851985lili/" target="_blank">☜♥☞MengChuChen</a> 2007-05-15 10:37 <a href="http://www.blogjava.net/19851985lili/articles/117528.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>使用JDBC连接Oracle数据库  [精華] </title><link>http://www.blogjava.net/19851985lili/articles/113908.html</link><dc:creator>☜♥☞MengChuChen</dc:creator><author>☜♥☞MengChuChen</author><pubDate>Thu, 26 Apr 2007 13:27:00 GMT</pubDate><guid>http://www.blogjava.net/19851985lili/articles/113908.html</guid><wfw:comment>http://www.blogjava.net/19851985lili/comments/113908.html</wfw:comment><comments>http://www.blogjava.net/19851985lili/articles/113908.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/19851985lili/comments/commentRss/113908.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/19851985lili/services/trackbacks/113908.html</trackback:ping><description><![CDATA[<pre><font class=java-reserved_word><strong>import</strong></font> java.sql.*;
<font class=java-reserved_word><strong>import</strong></font> java.io.*;
<font class=java-comment>/**
* &lt;p&gt;Title: JDBC连接数据库&lt;/p&gt;
* &lt;p&gt;Description: 本实例演示如何使用JDBC连接Oracle数据库，并演示添加数据和查询数据。&lt;/p&gt;
*/</font>
<font class=java-reserved_word><strong>public</strong></font> <font class=java-reserved_word><strong>class</strong></font> JDBCConn<font class=java-bracket>{</font>
<font class=java-reserved_word><strong>private</strong></font>  String url=<font class=java-string>""</font>;<font class=java-comment>//数据库连接字符串</font>
<font class=java-reserved_word><strong>private</strong></font>  String username=<font class=java-string>""</font>;<font class=java-comment>//数据库用户名</font>
<font class=java-reserved_word><strong>private</strong></font>  String password=<font class=java-string>""</font>;<font class=java-comment>//数据库密码</font>
&nbsp;
<font class=java-comment>/**
*&lt;br&gt;方法说明：获得数据连接
*&lt;br&gt;输入参数：
*&lt;br&gt;返回类型：Connection 连接对象
*/</font>
<font class=java-reserved_word><strong>public</strong></font> Connection conn()<font class=java-bracket>{</font>
<font class=java-reserved_word><strong>try</strong></font> <font class=java-bracket>{</font>
&nbsp;&nbsp;<font class=java-comment>//第一步：加载JDBC驱动</font>
Class.forName(<font class=java-string>"oracle.jdbc.driver.OracleDriver"</font>);
<font class=java-comment>//第二步：创建数据库连接</font>
Connection con =DriverManager.getConnection(url, username, password);
<font class=java-reserved_word><strong>return</strong></font> con;
<font class=java-bracket>}</font><font class=java-reserved_word><strong>catch</strong></font>(ClassNotFoundException cnf)<font class=java-bracket>{</font>
&nbsp;&nbsp;System.out.println(<font class=java-string>"driver not find:"</font>+cnf);
&nbsp;&nbsp;<font class=java-reserved_word><strong>return</strong></font> <font class=java-reserved_word><strong>null</strong></font>;
<font class=java-bracket>}</font><font class=java-reserved_word><strong>catch</strong></font>(SQLException sqle)<font class=java-bracket>{</font>
&nbsp;&nbsp;System.out.println(<font class=java-string>"can't connection db:"</font>+sqle);
&nbsp;&nbsp;<font class=java-reserved_word><strong>return</strong></font> <font class=java-reserved_word><strong>null</strong></font>;
<font class=java-bracket>}</font>
&nbsp;&nbsp;<font class=java-reserved_word><strong>catch</strong></font> (Exception e) <font class=java-bracket>{</font>
System.out.println(<font class=java-string>"Failed to load JDBC/ODBC driver."</font>);
<font class=java-reserved_word><strong>return</strong></font> <font class=java-reserved_word><strong>null</strong></font>;
<font class=java-bracket>}</font>
<font class=java-bracket>}</font>
<font class=java-comment>/**
*&lt;br&gt;方法说明：执行查询SQL语句
*&lt;br&gt;输入参数：Connection con 数据库连接
*&lt;br&gt;输入参数：String sql 要执行的SQL语句
*&lt;br&gt;返回类型：void
*/</font>
<font class=java-reserved_word><strong>public</strong></font> <font class=java-reserved_word><strong>void</strong></font> query(Connection con, String sql)<font class=java-bracket>{</font>
<font class=java-reserved_word><strong>try</strong></font><font class=java-bracket>{</font>
<font class=java-reserved_word><strong>if</strong></font>(con==<font class=java-reserved_word><strong>null</strong></font>)<font class=java-bracket>{</font>
<font class=java-reserved_word><strong>throw</strong></font> <font class=java-reserved_word><strong>new</strong></font> Exception(<font class=java-string>"database connection can't use!"</font>);
<font class=java-bracket>}</font>
<font class=java-reserved_word><strong>if</strong></font>(sql==<font class=java-reserved_word><strong>null</strong></font>) <font class=java-reserved_word><strong>throw</strong></font> <font class=java-reserved_word><strong>new</strong></font> Exception(<font class=java-string>"check your parameter: 'sql'! don't input null!"</font>);
<font class=java-comment>//第三步：获取Staetment对象</font>
Statement stmt = con.createStatement();
<font class=java-comment>//第四步：执行数据库操作（查询操作）</font>
ResultSet rs = stmt.executeQuery(sql);
<font class=java-comment>//第五步：处理结果集</font>
&nbsp;&nbsp; ResultSetMetaData rmeta = rs.getMetaData();
&nbsp;&nbsp; <font class=java-comment>//获得数据字段个数</font>
<font class=java-reserved_word><strong>int</strong></font> numColumns = rmeta.getColumnCount();
<font class=java-reserved_word><strong>while</strong></font>(rs.next())
&nbsp;&nbsp; <font class=java-bracket>{</font>
&nbsp;&nbsp;   <font class=java-reserved_word><strong>for</strong></font>(<font class=java-reserved_word><strong>int</strong></font> i = 0;i&lt; numColumns;i++)
&nbsp;&nbsp;   <font class=java-bracket>{</font>
&nbsp;&nbsp;&nbsp;&nbsp;String sTemp = rs.getString(i+1);
&nbsp;&nbsp;&nbsp;&nbsp;System.out.print(sTemp+<font class=java-string>"  "</font>);
&nbsp;&nbsp;   <font class=java-bracket>}</font>
&nbsp;&nbsp;  System.out.println(<font class=java-string>""</font>);
&nbsp;&nbsp; <font class=java-bracket>}</font>
<font class=java-bracket>}</font><font class=java-reserved_word><strong>catch</strong></font>(Exception e)<font class=java-bracket>{</font>
System.out.println(<font class=java-string>"query error:"</font>+e);
<font class=java-bracket>}</font>
<font class=java-bracket>}</font>
<font class=java-comment>/**
*&lt;br&gt;方法说明：执行插入、更新、删除等没有返回结果集的SQL语句
*&lt;br&gt;输入参数：Connection con 数据库连接
*&lt;br&gt;输入参数：String sql 要执行的SQL语句
*&lt;br&gt;返回类型：void
*/</font>
<font class=java-reserved_word><strong>public</strong></font> <font class=java-reserved_word><strong>void</strong></font> execute(Connection con, String sql)<font class=java-bracket>{</font>
<font class=java-reserved_word><strong>try</strong></font><font class=java-bracket>{</font>
<font class=java-reserved_word><strong>if</strong></font>(con==<font class=java-reserved_word><strong>null</strong></font>) <font class=java-reserved_word><strong>return</strong></font>;
<font class=java-comment>//第三步：获取Statement对象</font>
&nbsp;&nbsp;  Statement stmt = con.createStatement();
<font class=java-comment>//第四步：执行数据库操作（更新操作）</font>
&nbsp;&nbsp;  stmt.executeUpdate(sql);
&nbsp;&nbsp;  System.out.println(<font class=java-string>"update executed successly"</font>);
<font class=java-bracket>}</font><font class=java-reserved_word><strong>catch</strong></font>(Exception e)<font class=java-bracket>{</font>
System.out.println(<font class=java-string>"execute error: sql = "</font>+sql);
System.out.println(e);
<font class=java-bracket>}</font><font class=java-comment>//end try catch</font>
<font class=java-bracket>}</font><font class=java-comment>//end execute</font>
<font class=java-comment>/**
*&lt;br&gt;方法说明：实例演示
*&lt;br&gt;输入参数：无
*&lt;br&gt;返回类型：void
*/</font>
<font class=java-reserved_word><strong>public</strong></font> <font class=java-reserved_word><strong>void</strong></font> demo()<font class=java-bracket>{</font>
String sSQL=<font class=java-string>""</font>;
BufferedReader stdin=<font class=java-reserved_word><strong>new</strong></font> BufferedReader(<font class=java-reserved_word><strong>new</strong></font>  InputStreamReader(System.in));
<font class=java-reserved_word><strong>try</strong></font><font class=java-bracket>{</font>
System.out.println(<font class=java-string>"please input update SQL string"</font>);
sSQL=stdin.readLine();<font class=java-comment>//获取命令行输入（更新字符串）</font>
Connection conn = conn();<font class=java-comment>//执行自定义连接方法（获取数据库连接对象）</font>
execute(conn,sSQL);<font class=java-comment>//执行自定义更新方法</font>
String sql = <font class=java-string>"select * from TBL_USER"</font>;
query(conn,sql);<font class=java-comment>//执行自定义查询方法（查询并处理结果集）</font>
<font class=java-comment>//第六步：关闭数据库连接</font>
conn.close();
<font class=java-bracket>}</font><font class=java-reserved_word><strong>catch</strong></font>(SQLException se)<font class=java-bracket>{</font>
System.out.println(se);
<font class=java-bracket>}</font><font class=java-reserved_word><strong>catch</strong></font>(Exception e)<font class=java-bracket>{</font>
System.out.println(e);
<font class=java-bracket>}</font>
&nbsp;
<font class=java-bracket>}</font>
<font class=java-comment>/**
*&lt;br&gt;方法说明：主方法
*&lt;br&gt;输入参数：String[] args 命令行参数（包括：数据库连接URL，
*&lt;br&gt;用户名，密码）
*&lt;br&gt;返回类型：void
*/</font>
<font class=java-reserved_word><strong>public</strong></font> <font class=java-reserved_word><strong>static</strong></font> <font class=java-reserved_word><strong>void</strong></font> main(String[] arg)<font class=java-bracket>{</font>
<font class=java-reserved_word><strong>if</strong></font>(arg.length!=3)<font class=java-bracket>{</font>
System.out.println(<font class=java-string>"use: java JDBCConn url username password"</font>);
<font class=java-reserved_word><strong>return</strong></font>;
<font class=java-bracket>}</font>
JDBCConn oc = <font class=java-reserved_word><strong>new</strong></font> JDBCConn();
oc.url = arg[0];
oc.username=arg[1];
oc.password=arg[2];
oc.demo();
<font class=java-bracket>}</font>
<font class=java-bracket>}</font>
<table cellSpacing=1 cellPadding=4 width="95%" border=0>
    <tbody>
        <tr class=odd>
            <td vAlign=top width=150></td>
            <td vAlign=top width="100%"><span class=timestamp><img src="http://www.javaworld.com.tw/jute/images_zh_TW/post.gif" align=absMiddle border=0>於 2005-07-09 21:09</span> <a href="http://www.javaworld.com.tw/jute/user/info?uid=51684"><img alt="user profile" src="http://www.javaworld.com.tw/jute/images_zh_TW/icons/icon_profile.gif" align=absMiddle border=0></a><a href="http://www.javaworld.com.tw/jute/user/message?action=WriteMessage&amp;to=hkme&amp;subject=Re%3ARe%3A%E4%BD%BF%E7%94%A8JDBC%26%2336830%3B%E6%8E%A5Oracle%26%2325968%3B%E6%8D%AE%26%2324211%3B+%EF%BC%88%E4%BE%8B%E5%AD%90%E5%8F%8A%E5%85%B6%26%2335828%3B%E6%98%8E%EF%BC%89" target=_blank><img alt="send a private message to user" src="http://www.javaworld.com.tw/jute/images_zh_TW/icons/icon_pm.gif" align=absMiddle border=0></a><a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#112;&#115;&#107;&#121;&#114;&#111;&#110;&#103;&#50;&#48;&#48;&#52;&#64;&#121;&#97;&#104;&#111;&#111;&#46;&#99;&#111;&#109;&#46;&#99;&#110;"><img alt="send email to hkme" src="http://www.javaworld.com.tw/jute/images_zh_TW/icons/icon_email.gif" align=absMiddle border=0></a><a href="http://www.javaworld.com.tw/jute/post/reply?bid=21&amp;parent=116312&amp;done=%2Fjute%2Fpost%2Fview%3Fbid%3D21%26id%3D116281%26sty%3D1%26tpg%3D2%26age%3D-1&amp;quote=1"><img alt="reply to post" src="http://www.javaworld.com.tw/jute/images_zh_TW/icons/icon_quote.gif" align=absMiddle border=0></a><a href="http://www.javaworld.com.tw/jute/post/search?username=hkme&amp;action=Search"><img alt="search all posts by" src="http://www.javaworld.com.tw/jute/images_zh_TW/icons/icon_find.gif" align=absMiddle border=0></a><a href="javascript:copyText(document.all.text116312);"><img alt="select and copy to clipboard. &#13;&#10;ie only, sorry for netscape users:-)" src="http://www.javaworld.com.tw/jute/images_zh_TW/icons/icon_copy.gif" align=absMiddle border=0></a><a href="http://www.javaworld.com.tw/jute/user/favorite?action=Add&amp;bid=21&amp;id=116312" target=_blank><img alt="add this post to my favorite list" src="http://www.javaworld.com.tw/jute/images_zh_TW/icons/icon_favorite.gif" align=absMiddle border=0></a> <!-- hemidemi and delicious -->&nbsp;&nbsp;&nbsp; <span class=bookmarks><font color=#085278>收藏文章?&nbsp;</font><a onclick="window.open('http://del.icio.us/post?v=4&amp;noui&amp;jump=close&amp;url='+encodeURIComponent('http://www.javaworld.com.tw/jute/post/view?bid=21&amp;id=116312&amp;sty=1&amp;age=-1&amp;tpg=2&amp;ppg=1#116312')+'&amp;title='+encodeURIComponent('Re:使用JDBC连接Oracle数据库 （例子及其说明）'), 'delicious','toolbar=no,width=700,height=400'); return false;" href="http://del.icio.us/post"><font color=#085278><img style="VERTICAL-ALIGN: middle" alt=del.icio.us src="http://www.javaworld.com.tw/jute/upload/delicious.gif" border=0></font></a><font color=#085278>|</font><a onclick="window.open('http://www.hemidemi.com/user_bookmark/new?title='+encodeURIComponent('Re:使用JDBC连接Oracle数据库 （例子及其说明）')+'&amp;url='+encodeURIComponent('http://www.javaworld.com.tw/jute/post/view?bid=21&amp;id=116312&amp;sty=1&amp;age=-1&amp;tpg=2&amp;ppg=1#116312')+'&amp;description=&amp;via=sticker'); return false;" href="http://www.hemidemi.com/user_bookmark/new"><font color=#085278><img style="VERTICAL-ALIGN: middle" alt=HEMiDEMi src="http://www.hemidemi.com/sticker/user/www.braverobbin.com.gif" border=0></font></a><font color=#085278>|</font><a onclick="window.open('http://search20.portal20.com.tw/x.jsp?t='+encodeURIComponent('Re:使用JDBC连接Oracle数据库 （例子及其说明）')+'&amp;u='+encodeURIComponent('http://www.javaworld.com.tw/jute/post/view?bid=21&amp;id=116312&amp;sty=1&amp;age=-1&amp;tpg=2&amp;ppg=1#116312')+'&amp;g=javaworld'); return false;" href="http://search20.portal20.com.tw/"><font color=#085278><img style="VERTICAL-ALIGN: middle" alt="Search 2.0" src="http://www.javaworld.com.tw/jute/upload/search20.gif" border=0></font></a><font color=#085278> </font></span><font color=#085278><hr color=#000000 noShade SIZE=1></font><span class=javascript id=text116312>使用结果集元数据对象获取数据库信息 <br><br>
            <table class=java cellSpacing=1 cellPadding=3 bgColor=#999999 border=0>
                <tbody>
                    <tr>
                        <td vAlign=top align=left width=1 bgColor=#dddddd>
                        <pre><font color=#555555>1<br>2<br>3<br>4<br>5<br>6<br>7<br>8<br>9<br>10<br>11<br>12<br>13<br>14<br>15<br>16<br>17<br>18<br>19<br>20<br>21<br>22<br>23<br>24<br>25<br>26<br>27<br>28<br>29<br>30<br>31<br>32<br>33<br>34<br>35<br>36<br>37<br>38<br>39<br>40<br>41<br>42<br>43<br>44<br>45<br>46<br>47<br>48<br>49<br>50<br>51<br>52<br>53<br>54<br>55<br>56<br>57<br>58<br>59<br>60<br>61<br>62<br>63<br>64<br>65<br>66<br>67<br>68<br>69<br>70<br>71<br>72<br>73<br>74<br>75<br>76<br>77<br>78<br>79<br>80<br>81<br>82<br>83<br>84<br>85<br>86<br>87<br></font></pre>
                        </td>
                        <td vAlign=top align=left bgColor=#ffffff>
                        <pre><font class=java-reserved_word><strong>import</strong></font> java.sql.*;
                        <font class=java-comment>/**
                        * &lt;p&gt;Title: 结果集元数据&lt;/p&gt;
                        * &lt;p&gt;Description: 使用结果集元数据对象获取数据库信息。&lt;/p&gt;
                        */</font>
                        <font class=java-reserved_word><strong>public</strong></font> <font class=java-reserved_word><strong>class</strong></font> JDBCResultMeta <font class=java-bracket>{</font>
                        <font class=java-reserved_word><strong>private</strong></font> String url=<font class=java-string>""</font>;
                        <font class=java-reserved_word><strong>private</strong></font> String username=<font class=java-string>""</font>;
                        <font class=java-reserved_word><strong>private</strong></font> String password=<font class=java-string>""</font>;
                        <font class=java-comment>/**
                        *&lt;br&gt;方法说明：主方法
                        *&lt;br&gt;输入参数：
                        *&lt;br&gt;返回类型：
                        */</font>
                        <font class=java-reserved_word><strong>public</strong></font> <font class=java-reserved_word><strong>static</strong></font> <font class=java-reserved_word><strong>void</strong></font> main(java.lang.String[] args) <font class=java-bracket>{</font>
                        <font class=java-reserved_word><strong>if</strong></font>(args.length!=4)<font class=java-bracket>{</font>
                        System.out.println(<font class=java-string>"use: java JDBCResultMeta url username password tablename"</font>);
                        <font class=java-reserved_word><strong>return</strong></font>;
                        <font class=java-bracket>}</font>
                        JDBCResultMeta JRM = <font class=java-reserved_word><strong>new</strong></font> JDBCResultMeta();
                        JRM.url = args[0];
                        JRM.username=args[1];
                        JRM.password=args[2];
                        JRM.getMeta(JRM.conn(),args[3]);
                        <font class=java-bracket>}</font>
                        &nbsp;
                        <font class=java-comment>/**
                        *&lt;br&gt;方法说明：获得数据连接
                        *&lt;br&gt;输入参数：
                        *&lt;br&gt;返回类型：Connection 连接对象
                        */</font>
                        <font class=java-reserved_word><strong>public</strong></font> Connection conn()<font class=java-bracket>{</font>
                        <font class=java-reserved_word><strong>try</strong></font> <font class=java-bracket>{</font>
                        Class.forName(<font class=java-string>"com.mysql.jdbc.Driver"</font>);
                        &nbsp;&nbsp;&nbsp;&nbsp;Class.forName(<font class=java-string>"oracle.jdbc.driver.OracleDriver"</font>);
                        Connection con = DriverManager.getConnection(url, username, password);
                        <font class=java-reserved_word><strong>return</strong></font> con;
                        <font class=java-bracket>}</font><font class=java-reserved_word><strong>catch</strong></font>(ClassNotFoundException cf)<font class=java-bracket>{</font>
                        &nbsp;&nbsp;System.out.println(<font class=java-string>"can't find class"</font>+cf);
                        &nbsp;&nbsp;<font class=java-reserved_word><strong>return</strong></font> <font class=java-reserved_word><strong>null</strong></font>;
                        <font class=java-bracket>}</font><font class=java-reserved_word><strong>catch</strong></font>(SQLException sqle)<font class=java-bracket>{</font>
                        &nbsp;&nbsp;System.out.println(<font class=java-string>"can't connection db:"</font>+sqle);
                        &nbsp;&nbsp;<font class=java-reserved_word><strong>return</strong></font> <font class=java-reserved_word><strong>null</strong></font>;
                        <font class=java-bracket>}</font> <font class=java-reserved_word><strong>catch</strong></font> (Exception e) <font class=java-bracket>{</font>
                        System.out.println(<font class=java-string>"Failed to load JDBC/ODBC driver."</font>);
                        <font class=java-reserved_word><strong>return</strong></font> <font class=java-reserved_word><strong>null</strong></font>;
                        <font class=java-bracket>}</font>
                        <font class=java-bracket>}</font>
                        <font class=java-comment>/**
                        *&lt;br&gt;方法说明：获取结果集元数据信息
                        *&lt;br&gt;输入参数：Connection con 数据库连接
                        *&lt;br&gt;输入参数：String table 表名称
                        *&lt;br&gt;返回类型：
                        */</font>
                        <font class=java-reserved_word><strong>public</strong></font> <font class=java-reserved_word><strong>void</strong></font> getMeta(Connection con, String table)<font class=java-bracket>{</font>
                        <font class=java-reserved_word><strong>try</strong></font> <font class=java-bracket>{</font>
                        Statement Stm = con.createStatement();
                        String sql=<font class=java-string>"select * from "</font>+table;
                        ResultSet rs = Stm.executeQuery(sql);
                        ResultSetMetaData lineInfo = rs.getMetaData();
                        System.out.println(<font class=java-string>"*********************RESULT META Comment************************"</font>);
                        <font class=java-comment>//获取数据列数</font>
                        <font class=java-reserved_word><strong>int</strong></font> columnCount = lineInfo.getColumnCount();
                        System.out.println(<font class=java-string>"Column Count :"</font>+columnCount);
                        <font class=java-comment>//获取数据列类型</font>
                        <font class=java-reserved_word><strong>for</strong></font>(<font class=java-reserved_word><strong>int</strong></font> i=1;i&lt;columnCount+1;i++)<font class=java-bracket>{</font>
                        String columeName = lineInfo.getColumnName(i);
                        String columeType = lineInfo.getColumnTypeName(i);
                        <font class=java-comment>//boolean autocol = lineInfo.isAutoIncrement(i);</font>
                        System.out.println(columeName+<font class=java-string>" = "</font>+columeType); <font class=java-comment>//+"  :::  "+autocol);</font>
                        &nbsp;&nbsp;  <font class=java-bracket>}</font>
                        <font class=java-bracket>}</font><font class=java-reserved_word><strong>catch</strong></font> (SQLException se) <font class=java-bracket>{</font>
                        <font class=java-comment>// 输出数据库连接错误信息</font>
                        System.out.println(<font class=java-string>"SQL Exception: "</font> + se.getMessage());
                        se.printStackTrace(System.out);
                        <font class=java-bracket>}</font><font class=java-reserved_word><strong>catch</strong></font>(Exception e)<font class=java-bracket>{</font>
                        System.out.println(e);
                        <font class=java-bracket>}</font><font class=java-reserved_word><strong>finally</strong></font><font class=java-bracket>{</font>
                        <font class=java-reserved_word><strong>try</strong></font><font class=java-bracket>{</font>
                        con.close();
                        <font class=java-bracket>}</font><font class=java-reserved_word><strong>catch</strong></font>(SQLException se)<font class=java-bracket>{</font><font class=java-bracket>}</font>
                        <font class=java-bracket>}</font>
                        <font class=java-bracket>}</font>
                        &nbsp;
                        <font class=java-bracket>}</font>
                        </pre>
                        </td>
                    </tr>
                </tbody>
            </table>
            </span></td>
        </tr>
    </tbody>
</table>
</pre>
<img src ="http://www.blogjava.net/19851985lili/aggbug/113908.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/19851985lili/" target="_blank">☜♥☞MengChuChen</a> 2007-04-26 21:27 <a href="http://www.blogjava.net/19851985lili/articles/113908.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java的代碼規範 [精華] </title><link>http://www.blogjava.net/19851985lili/articles/113906.html</link><dc:creator>☜♥☞MengChuChen</dc:creator><author>☜♥☞MengChuChen</author><pubDate>Thu, 26 Apr 2007 13:17:00 GMT</pubDate><guid>http://www.blogjava.net/19851985lili/articles/113906.html</guid><wfw:comment>http://www.blogjava.net/19851985lili/comments/113906.html</wfw:comment><comments>http://www.blogjava.net/19851985lili/articles/113906.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/19851985lili/comments/commentRss/113906.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/19851985lili/services/trackbacks/113906.html</trackback:ping><description><![CDATA[<p>&nbsp;<br>定義這個規範的目的是讓專案中所有的文?都看起來像一個人寫的，增加可讀性，減少專案組中因爲換人而帶來的損失。（這些規範並不是一定要?對遵守，但是一定要讓程式有良好的可讀性） </p>
<p>Package 的命名 <br>Package 的名字應該都是由一個小寫單詞組成。 </p>
<p>Class 的命名 <br>Class 的名字必須由大寫字母開頭而其他字母都小寫的單詞組成 </p>
<p>Class 變數的命名 <br>變數的名字必須用一個小寫字母開頭。後面的單詞用大寫字母開頭。 </p>
<p>Static Final 變數的命名 <br>Static Final 變數的名字應該都大寫，並且指出完整含義。 </p>
<p>參數的命名 <br>參數的名字必須和變數的命名規範一致。 </p>
<p>陣列的命名 <br>陣列應該總是用下面的方式來命名： <br>byte[] buffer;&nbsp;&nbsp;&nbsp;&nbsp; <br>而不是： <br>byte buffer[]; <br>&nbsp;&nbsp;&nbsp;&nbsp; <br>方法的參數 <br>使用有意義的參數命名，如果可能的話，使用和要賦?的欄位一樣的名字： <br>1234<br>&nbsp;SetCounter(int size)<br>{&nbsp; <br>this.size = size;<br>}</p>
<p>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp; </p>
<p>Java 文件樣式 <br>所有的 Java(*.java) 文件都必須遵守如下的樣式規則 <br>版權資訊 <br>版權資訊必須在 java 文件的開頭，比如： </p>
<p>/** * Copyright R 2000 XXX Co. Ltd. * All right reserved. */&nbsp;&nbsp;&nbsp;&nbsp; <br>其他不需要出現在 javadoc 的資訊也可以包含在這?。 </p>
<p>Package/Imports <br>package 行要在 import 行之前，import 中標準的包名要在本地的包名之前，而且按照字母順序排列。如果 import 行中包含了同一個包中的不同子目?，則應該用 * 來處理。 <br>123<br>&nbsp;package hotlava.net.stats;<br>import java.io.*;<br>import java.util.Observable;import hotlava.util.Application;&nbsp; </p>
<p>&nbsp;<br>&nbsp;&nbsp; <br>這兒java.io.* 使用來代替InputStream and OutputStream 的。 <br>Class <br>接下來的是類的注釋，一般是用來解釋類的。 <br>1<br>&nbsp;/** * A class representing a set of packet and byte counters * It is observable to allow it to be watched, but only * reports changes when the current set is complete */&nbsp; </p>
<p>&nbsp;<br>&nbsp;&nbsp; <br>接下來是類定義，包含了在不同的行的 extends 和 implements <br>1<br>&nbsp;public class CounterSet&nbsp;&nbsp; extends Observable implements Cloneable&nbsp; </p>
<p>&nbsp;<br>&nbsp;&nbsp; <br>Class Fields </p>
<p>接下來是類的成員變數： <br>123<br>&nbsp; <br>/** * Packet counters */<br>protected int[] packets;</p>
<p>&nbsp;</p>
<p>public 的成員變數必須生成文?（JavaDoc）。proceted、private和 package 定義的成員變數如果名字含義明確的話，可以沒有注釋。 </p>
<p>存取方法 <br>接下來是類變數的存取的方法。它只是簡單的用來將類的變數賦?獲取?的話，可以簡單的寫在一行上。 <br>12345678910111213<br>&nbsp; <br>/** * Get the counters * @return an array containing the statistical data.&nbsp; This array has been * freshly allocated and can be modified by the caller. */public int[] getPackets() { <br>return copyArray(packets, offset); <br>}<br>public int[] getBytes() { <br>return copyArray(bytes, offset); <br>}<br>public int[] getPackets() {<br>&nbsp;return packets; <br>}<br>public void setPackets(int[] packets) { <br>this.packets = packets;<br>&nbsp;}</p>
<p>&nbsp;</p>
<p>其他的方法不要寫在一行上 </p>
<p>構造函數 <br>接下來是構造函數，它應該用遞增的方式寫（比如：參數多的寫在後面）。 <br>訪問類型 ("public", "private" 等.) 和 任何 "static", "final" 或 "synchronized" 應該在一行中，並且方法和參數?寫一行，這樣可以使方法和參數更易讀。 <br>1234<br>&nbsp;public CounterSet<br>(int size){&nbsp; <br>this.size = size;<br>}</p>
<p>&nbsp;</p>
<p>克隆方法 <br>如果這個類是可以被克隆的，那?下一?就是 clone 方法： <br>12345678910111213<br>&nbsp; <br>public Object clone() <br>{&nbsp; <br>try {&nbsp;&nbsp; <br>&nbsp;CounterSet obj = (CounterSet)super.clone();&nbsp;&nbsp; <br>&nbsp;obj.packets = (int[])packets.clone();&nbsp;&nbsp; <br>&nbsp;obj.size = size;&nbsp;&nbsp;&nbsp; <br>return obj;&nbsp; <br>}<br>catch(CloneNotSupportedException e) {&nbsp;&nbsp;&nbsp; <br>throw new InternalError("Unexpected CloneNotSUpportedException: " + e.getMessage());&nbsp; <br>}<br>}</p>
<p>&nbsp;</p>
<p>類方法 <br>下面開始寫類的方法： <br>12345678<br>&nbsp;/** * Set the packet counters * (such as when restoring from a database) */<br>protected finalvoid setArray(int[] r1, int[] r2, int[] r3, int[] r4)&nbsp; throws IllegalArgumentException<br>{&nbsp; <br>//&nbsp; // Ensure the arrays are of equal size&nbsp; // <br>&nbsp;if (r1.length != r2.length || r1.length != r3.length || r1.length != r4.length)<br>&nbsp; throw new IllegalArgumentException("Arrays must be of the same size");&nbsp; System.arraycopy(r1, 0, r3, 0, r1.length);&nbsp; <br>&nbsp;System.arraycopy(r2, 0, r4, 0, r1.length);<br>}</p>
<p>&nbsp;</p>
<p><br>toString 方法 <br>無論如何，?一個類都應該定義 toString 方法： <br>12345678910<br>&nbsp;public String toString() <br>{&nbsp; <br>String retval = "CounterSet: ";&nbsp;&nbsp; <br>&nbsp;for (int i = 0; i &lt; data.length(); i++) {&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp; retval += data.bytes.toString();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; retval += data.packets.toString(); <br>&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp; <br>return retval;&nbsp; <br>}<br>}</p>
<p>&nbsp;</p>
<p><br>main 方法 <br>如果main(String[]) 方法已經定義了, 那?它應該寫在類的底部. <br>代碼編寫格式 </p>
<p>代碼樣式 <br>代碼應該用 unix 的格式，而不是 windows 的（比如：回車變成回車+換行） </p>
<p>文?化 <br>必須用 javadoc 來爲類生成文?。不僅因爲它是標準，這也是被各種 java 編譯器都認可的方法。使用 @author 標記是不被推薦的，因爲代碼不應該是被個人擁有的。 </p>
<p>縮進 <br>縮進應該是?行2個空格. 不要在原始?案中保存Tab字元. 在使用不同的源代碼管理工具時Tab字元將因爲用?設置的不同而擴展爲不同的寬度. <br>如果?使用 UltrEdit 作爲?的 Java 源代碼編輯器的話，?可以通過如下操作來禁止保存Tab字元, 方法是通過 UltrEdit中先設定 Tab 使用的長度室2個空格，然後用 Format|Tabs to Spaces 功能表將 Tab 轉換爲空格。 </p>
<p>頁寬 <br>頁寬應該設置爲80字元. 源代碼一般不會超過這個寬度, 並導致無法完整顯示, 但這一設置也可以靈活調整. 在任何情況下, 超長的語句應該在一個逗號或者一個操作符後折行. 一條語句折行後, 應該比原來的語句再縮進2個字元. </p>
<p>{} 對 <br>{} 中的語句應該單獨作爲一行. 例如, 下面的第1行是錯誤的, 第2行是正確的: <br>12<br>&nbsp;if (i&gt;0) { i ++ }; <br>// 錯誤, { 和 } 在同一行</p>
<p>&nbsp;</p>
<p><br>1234<br>&nbsp; if (i&gt;0) {<br>&nbsp;i ++ <br>&nbsp;}; <br>&nbsp;// 正確, { 單獨作爲一行 } 語句永遠單獨作爲一行. </p>
<p>&nbsp;</p>
<p>如果 } 語句應該縮進到與其相對應的 { 那一行相對齊的位置。 </p>
<p>括弧 <br>左括弧和後一個字元之間不應該出現空格, 同樣, 右括弧和前一個字元之間也不應該出現空格. 下面的例子?明括弧和空格的錯誤及正確使用: <br>12<br>&nbsp;CallProc( AParameter ); // 錯誤 <br>CallProc(AParameter); // 正確 </p>
<p>&nbsp;</p>
<p>不要在語句中使用無意義的括弧. 括弧只應該爲達到某種目的而出現在源代碼中。下面的例子?明錯誤和正確的用法: <br>12<br>&nbsp;if ((I) = 42) { // 錯誤 - 括弧毫無意義 <br>if (I == 42) or (J == 42) then // 正確 - 的確需要括弧 </p>
<p>&nbsp;</p>
<p>程式編寫規範 <br>exit() <br>exit 除了在 main 中可以被調用外，其他的地方不應該調用。因爲這樣做不給任何代碼代碼機會來截獲退出。一個類似後臺服務地程式不應該因爲某一個庫模組決定了要退出就退出。 </p>
<p>異常 <br>申明的錯誤應該抛出一個RuntimeException或者派生的異常。 <br>頂層的main()函數應該截獲所有的異常，並且列印（或者記?在日誌中）在螢幕上。 </p>
<p>??收集 <br>JAVA使用成熟的後臺??收集技術來代替引用計數。但是這樣會導致一個問題：?必須在使用完物件的實例以後進行清場工作。比如一個prel的程式師可能這?寫： <br>1234<br>&nbsp;&nbsp; ...&nbsp; {<br>&nbsp;&nbsp;&nbsp; FileOutputStream fos = new FileOutputStream(projectFile);<br>&nbsp;&nbsp;&nbsp; project.save(fos, "IDE Project File");<br>&nbsp;&nbsp; }&nbsp; ...</p>
<p>&nbsp;</p>
<p>除非輸出流一出作用域就關閉，非引用計數的程式語言，比如JAVA，是不能自動完成變數的清場工作的。 <br>必須象下面一樣寫： <br>&nbsp; FileOutputStream fos = new FileOutputStream(projectFile); <br>&nbsp; project.save(fos, "IDE Project File"); <br>&nbsp; fos.close(); <br>Clone <br>下面是一種有用的方法： <br>1234567891011<br>&nbsp;&nbsp; implements Cloneable&nbsp; public&nbsp;&nbsp;&nbsp; Object clone()&nbsp;&nbsp;&nbsp; {&nbsp; <br>&nbsp;&nbsp;&nbsp; try { <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ThisClass obj = (ThisClass)super.clone();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; obj.field1 = (int[])field1.clone();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; obj.field2 = field2;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return obj; <br>&nbsp;&nbsp;&nbsp;&nbsp; } <br>catch(CloneNotSupportedException e) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw new InternalError("Unexpected CloneNotSUpportedException: " + e.getMessage());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <br>&nbsp;}</p>
<p>&nbsp;</p>
<p>final 類 <br>?對不要因爲性能的原因將類定義爲 final 的（除非程式的框架要求） <br>如果一個類還沒有準備好被繼承，最好在類文?中注明，而不要將?定義爲 final 的。這是因爲沒有人可以保證會不會由於什?原因需要繼承?。 </p>
<p>訪問類的成員變數 <br>大部分的類成員變數應該定義爲 protected 的來防止繼承類使用他們。 <br>注意，要用"int[] packets"，而不是"int packets[]"，後一種永遠也不要用。 <br>1234567<br>&nbsp; <br>public void setPackets(int[] packets) { <br>this.packets = packets; <br>}<br>&nbsp;CounterSet(int size){<br>this.size = size;<br>}</p>
<p>&nbsp;<strong> </strong>
<table cellSpacing=0 cellPadding=0 width=1298 border=0 x:str>
    <colgroup><strong>
    <col width=85>
    <col width=125>
    <col width=165>
    <col width=617>
    <col width=50>
    <col width=42>
    <col width=53>
    <col width=69>
    <col width=72>
    <col width=20></strong>
    <tbody>
        <tr height=18>
            <td width=85 height=36 rowSpan=2>文件构成</td>
            <td width=125 rowSpan=2>文件路径</td>
            <td width=165>模块位置</td>
            <td width=617>文件应当属于他所在的模块（serivce,dao&#8230;&#8230; ）目录。</td>
            <td width=50>●</td>
            <td width=42>　</td>
            <td width=53>　</td>
            <td width=69>　</td>
            <td width=72></td>
            <td width=20></td>
        </tr>
        <tr height=18>
            <td height=18>机能位置</td>
            <td width=617>文件属于他所对应的机能目录。</td>
            <td width=50>●</td>
            <td width=42>　</td>
            <td width=53>　</td>
            <td>　</td>
            <td></td>
            <td></td>
        </tr>
        <tr height=19>
            <td height=319 rowSpan=15>命名规则</td>
            <td>包名</td>
            <td>包名</td>
            <td width=617>首字母小写，名词方式或者编号方式命名</td>
            <td width=50>●</td>
            <td width=42>　</td>
            <td width=53>　</td>
            <td>　</td>
            <td></td>
            <td></td>
        </tr>
        <tr height=19>
            <td height=19>类名</td>
            <td>类名</td>
            <td width=617>首字母大写，单词第一个字母大写。</td>
            <td width=50>●</td>
            <td width=42>　</td>
            <td width=53>　</td>
            <td>　</td>
            <td></td>
            <td></td>
        </tr>
        <tr height=19>
            <td height=38 rowSpan=2>常量</td>
            <td>常量</td>
            <td width=617>定义为静态（static），定义为终结（final）</td>
            <td width=50>　</td>
            <td width=42>　</td>
            <td width=53>●</td>
            <td>　</td>
            <td></td>
            <td></td>
        </tr>
        <tr height=19>
            <td height=19>常量名</td>
            <td width=617>常量名全部使用大写，单词间使用（_）分割</td>
            <td width=50>　</td>
            <td width=42>　</td>
            <td width=53>●</td>
            <td>　</td>
            <td></td>
            <td></td>
        </tr>
        <tr height=19>
            <td height=57 rowSpan=3>方法名</td>
            <td>无返回值方法名</td>
            <td>首字母小写，机能方式命名。</td>
            <td width=50>　</td>
            <td width=42>　</td>
            <td width=53>●</td>
            <td>　</td>
            <td></td>
            <td></td>
        </tr>
        <tr height=19>
            <td height=19>其他类型方法名</td>
            <td>首字母小写</td>
            <td width=50>●</td>
            <td width=42>　</td>
            <td width=53>　</td>
            <td>　</td>
            <td></td>
            <td></td>
        </tr>
        <tr height=19>
            <td width=165 height=19>Boolean型方法名</td>
            <td width=617>is+形容词，can+动词，has+名词/动词过去式</td>
            <td width=50>　</td>
            <td width=42>　</td>
            <td width=53>●</td>
            <td>　</td>
            <td></td>
            <td></td>
        </tr>
        <tr height=19>
            <td height=38 rowSpan=2>变量名</td>
            <td>Boolean型变量名</td>
            <td width=617>is+形容词，can+动词，has+名词/动词过去式</td>
            <td>　</td>
            <td>　</td>
            <td width=53>●</td>
            <td>　</td>
            <td></td>
            <td></td>
        </tr>
        <tr height=19>
            <td height=19>其他类型变量名</td>
            <td width=617>首字母小写</td>
            <td width=50>●</td>
            <td width=42>　</td>
            <td width=53>　</td>
            <td>　</td>
            <td></td>
            <td></td>
        </tr>
        <tr height=19>
            <td width=125 height=19>英文</td>
            <td width=165>拼写正确</td>
            <td width=617>英语单词拼写正确</td>
            <td width=50>●</td>
            <td>　</td>
            <td>　</td>
            <td width=69>　</td>
            <td></td>
            <td></td>
        </tr>
        <tr height=19>
            <td width=125 height=19>对称性</td>
            <td width=165>命名单词对称</td>
            <td width=617 x:str="add/remove insert/delete insert/delete start/stop begin/end &#8230;&#8230; ">add/remove insert/delete insert/delete start/stop begin/end &#8230;&#8230;&nbsp;</td>
            <td>　</td>
            <td>　</td>
            <td width=53>●</td>
            <td width=69>　</td>
            <td></td>
            <td></td>
        </tr>
        <tr height=19>
            <td width=125 height=19>循环用变量</td>
            <td width=165>循环用变量命名</td>
            <td width=617>根据使用次序按照i j k l m n 依次使用</td>
            <td width=50>●</td>
            <td>　</td>
            <td>　</td>
            <td>　</td>
            <td></td>
            <td></td>
        </tr>
        <tr height=36>
            <td width=125 height=36>临时变量</td>
            <td width=165>临时变量命名</td>
            <td width=617>使用该变量类型每个单词的首字母小写命名，如（ServeletContext sc;）<br>使用该变量类型名，将该名称首字母小写，如（Array array; 或者 Array arr;）</td>
            <td width=50>●</td>
            <td>　</td>
            <td>　</td>
            <td>　</td>
            <td></td>
            <td></td>
        </tr>
        <tr height=19>
            <td width=125 height=19>方法参数</td>
            <td>方法参数命名</td>
            <td width=617>定义方式参照变量名定义。参数名能够表示该参数的含义。</td>
            <td width=50>●</td>
            <td width=42>　</td>
            <td width=53>　</td>
            <td>　</td>
            <td></td>
            <td></td>
        </tr>
        <tr height=36>
            <td width=125 height=36>内部变量</td>
            <td width=165>内部变量命名</td>
            <td width=617>用于保存公开变量（publci String getXXX()）的内部变量，使用XXX作为变量名命名（但首字母要小写）</td>
            <td width=50>　</td>
            <td width=42>　</td>
            <td width=53>　</td>
            <td>　</td>
            <td></td>
            <td></td>
        </tr>
        <tr height=19>
            <td width=85 height=247 rowSpan=13>编程样式</td>
            <td width=125>注释</td>
            <td width=165>注释方式</td>
            <td width=617>单行注释使用"//"+空格+注释内容。多行注释使用/*...*/。</td>
            <td width=50>●</td>
            <td width=42>　</td>
            <td width=53>　</td>
            <td>　</td>
            <td></td>
            <td></td>
        </tr>
        <tr height=19>
            <td width=125 height=19>缩进方式</td>
            <td width=165>缩进方式</td>
            <td width=617>使用1个tab进行缩进处理</td>
            <td width=50>●</td>
            <td width=42>　</td>
            <td width=53>　</td>
            <td>　</td>
            <td></td>
            <td></td>
        </tr>
        <tr height=19>
            <td width=125 height=57 rowSpan=3>括号方式</td>
            <td width=165>类</td>
            <td width=617>起始括号位于类定义行末尾，结束括号单独一行，与类定义对齐。</td>
            <td width=50>●</td>
            <td width=42>　</td>
            <td width=53>　</td>
            <td>　</td>
            <td></td>
            <td></td>
        </tr>
        <tr height=19>
            <td width=165 height=19>方法</td>
            <td width=617>起始括号位于方法定义行末尾，结束括号单独一行，与方法定义对齐。</td>
            <td width=50>●</td>
            <td width=42>　</td>
            <td width=53>　</td>
            <td>　</td>
            <td></td>
            <td></td>
        </tr>
        <tr height=19>
            <td width=165 height=19>程序分支</td>
            <td width=617>起始括号位于分支定义行末尾，结束括号单独一行，与分支定义对齐。</td>
            <td width=50>●</td>
            <td>　</td>
            <td>　</td>
            <td>　</td>
            <td></td>
            <td></td>
        </tr>
        <tr height=19>
            <td width=125 height=19>行的长度</td>
            <td width=165>行的长度</td>
            <td width=617>每行程序的长度不得超过80个字符。</td>
            <td width=50>●</td>
            <td width=42>　</td>
            <td width=53>　</td>
            <td>　</td>
            <td></td>
            <td></td>
        </tr>
        <tr height=19>
            <td width=125 height=19>private</td>
            <td width=165>使用范围</td>
            <td width=617>除去公开方法或者属性外，应当全部定义为private。</td>
            <td width=50>●</td>
            <td width=42>　</td>
            <td width=53>　</td>
            <td>　</td>
            <td></td>
            <td></td>
        </tr>
        <tr height=19>
            <td width=125 height=19>protected</td>
            <td width=165>使用范围</td>
            <td width=617>共通类/方法以外，没有特殊要求，不得使用protected定义。</td>
            <td width=50>●</td>
            <td width=42>　</td>
            <td width=53>　</td>
            <td>　</td>
            <td></td>
            <td></td>
        </tr>
        <tr height=19>
            <td width=125 height=19>public</td>
            <td width=165>使用范围</td>
            <td width=617>允许外部访问和修改的方法/变量。</td>
            <td width=50>●</td>
            <td width=42>　</td>
            <td width=53>　</td>
            <td>　</td>
            <td></td>
            <td></td>
        </tr>
        <tr height=19>
            <td width=125 height=38 rowSpan=2>if/while</td>
            <td width=165>"="符号的使用</td>
            <td width=617>在if/while语句的判断式内，不能使用"="符号。</td>
            <td width=50>●</td>
            <td>　</td>
            <td>　</td>
            <td>　</td>
            <td></td>
            <td></td>
        </tr>
        <tr height=19>
            <td width=165 height=19>"&lt; &gt; &lt;= &gt;="的使用</td>
            <td width=617>在同一个判断式中的多个部分内，不允许同时出现"&lt;"和"&gt;"（判断方向必须一致）</td>
            <td width=50>●</td>
            <td width=42>　</td>
            <td width=53>　</td>
            <td>　</td>
            <td></td>
            <td></td>
        </tr>
        <tr height=19>
            <td width=125 height=19>循环处理</td>
            <td width=165>循环处理嵌套</td>
            <td width=617>循环处理不允许嵌套3层以上。</td>
            <td width=50>●</td>
            <td>　</td>
            <td>　</td>
            <td>　</td>
            <td></td>
            <td></td>
        </tr>
        <tr height=19>
            <td width=125 height=19>循环变量</td>
            <td width=165>循环变量</td>
            <td width=617>不允许多个循环代码使用同一个变量作为循环参数。</td>
            <td width=50>●</td>
            <td>　</td>
            <td>　</td>
            <td>　</td>
            <td></td>
            <td></td>
        </tr>
        <tr height=19>
            <td width=85 height=171 rowSpan=9>　</td>
            <td width=125 rowSpan=2>文件注释</td>
            <td width=165>注释方式</td>
            <td width=617>使用多行注释</td>
            <td width=50>●</td>
            <td>　</td>
            <td>　</td>
            <td>　</td>
            <td></td>
            <td></td>
        </tr>
        <tr height=19>
            <td width=165 height=19>改版履历</td>
            <td width=617>式样变更的改版履历，内容有（时间，式样版本，对应者）</td>
            <td width=50>　</td>
            <td width=42>　</td>
            <td width=53>●</td>
            <td>　</td>
            <td></td>
            <td></td>
        </tr>
        <tr height=19>
            <td width=125 height=57 rowSpan=3>类注释</td>
            <td width=165>注释方式</td>
            <td width=617>使用多行注释</td>
            <td width=50>●</td>
            <td>　</td>
            <td>　</td>
            <td>　</td>
            <td></td>
            <td></td>
        </tr>
        <tr height=19>
            <td width=165 height=19>机能说明</td>
            <td width=617>对机能进行简单说明。</td>
            <td width=50>●</td>
            <td>　</td>
            <td>　</td>
            <td>　</td>
            <td></td>
            <td></td>
        </tr>
        <tr height=19>
            <td width=165 height=19>创建者</td>
            <td width=617>记录创建者（@author）</td>
            <td width=50>●</td>
            <td>　</td>
            <td>　</td>
            <td>　</td>
            <td></td>
            <td></td>
        </tr>
        <tr height=19>
            <td width=125 height=57 rowSpan=3>方法注释</td>
            <td width=165>注释方式</td>
            <td width=617>使用多行注释</td>
            <td width=50>●</td>
            <td>　</td>
            <td>　</td>
            <td>　</td>
            <td></td>
            <td></td>
        </tr>
        <tr height=19>
            <td width=165 height=19>机能说明</td>
            <td width=617>对机能进行简单说明。</td>
            <td width=50>　</td>
            <td width=42>●</td>
            <td width=53>　</td>
            <td>　</td>
            <td></td>
            <td></td>
        </tr>
        <tr height=19>
            <td width=165 height=19>参数说明</td>
            <td width=617>对参数和返回值进行简单说明。</td>
            <td width=50>　</td>
            <td width=42>●</td>
            <td width=53>　</td>
            <td>　</td>
            <td></td>
            <td></td>
        </tr>
        <tr height=19>
            <td width=125 height=19>变量注释</td>
            <td width=165>注释方式</td>
            <td width=617>使用单行注释</td>
            <td width=50>●</td>
            <td width=42>　</td>
            <td width=53>　</td>
            <td>　</td>
            <td></td>
            <td></td>
        </tr>
        <tr height=19>
            <td width=85 height=19>其他</td>
            <td width=125>判断式</td>
            <td width=165>判断式</td>
            <td width=617>使用"&lt; &gt; = &amp;&amp; ||"等判断式组成多次组合判断时，使用括号标明判断式执行次序。</td>
            <td width=50>●</td>
            <td width=42>　</td>
            <td width=53>　</td>
            <td>　</td>
            <td></td>
            <td></td>
        </tr>
    </tbody>
</table>
</p>
<p>&nbsp;</p>
<img src ="http://www.blogjava.net/19851985lili/aggbug/113906.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/19851985lili/" target="_blank">☜♥☞MengChuChen</a> 2007-04-26 21:17 <a href="http://www.blogjava.net/19851985lili/articles/113906.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>多线程（总结）</title><link>http://www.blogjava.net/19851985lili/articles/113597.html</link><dc:creator>☜♥☞MengChuChen</dc:creator><author>☜♥☞MengChuChen</author><pubDate>Wed, 25 Apr 2007 11:08:00 GMT</pubDate><guid>http://www.blogjava.net/19851985lili/articles/113597.html</guid><wfw:comment>http://www.blogjava.net/19851985lili/comments/113597.html</wfw:comment><comments>http://www.blogjava.net/19851985lili/articles/113597.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/19851985lili/comments/commentRss/113597.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/19851985lili/services/trackbacks/113597.html</trackback:ping><description><![CDATA[<p><font size=2>public interface Runnable<br>public class Thread extends Object implements Runnable<br>Runnable 接口应该由那些打算通过某一线程执行其实例的类来实现。类必须定义一个称为 run 的无参数方法.<br>Runnable 为非 Thread 子类的类提供了一种激活方式。通过实例化某个 Thread 实例并将自身作为运行目标，就可以运行实现 Runnable 的类而无需创建 Thread 的子类。大多数情况下，如果只想重写 run() 方法，而不重写其他 Thread 方法，那么应使用 Runnable 接口。这很重要，因为除非程序员打算修改或增强类的基本行为，否则不应为该类创建子类。<br>如何提供给 Java 我们要线程执行的代码呢？让我们来看一看 Thread 类。Thread 类最重要的方法是 run() ，它为Thread 类的方法 start() 所调用，提供我们的线程所要执行的代码。为了指定我们自己的代码，只需要覆盖它！<br>方法一：继承 Thread 类，覆盖方法 run()<br>我们在创建的 Thread 类的子类中重写 run() ,加入线程所要执行的代码即可。<br>下面是一个例子：<br>public class MyThread extends Thread {<br>int count= 1, number;<br>public MyThread(int num) {<br>number = num;<br>System.out.println("创建线程 " + number);<br>}<br>public void run() {<br>while(true) {<br>System.out.println("线程 " + number + ":计数 " + count);<br>if(++count== 6) return;<br>}<br>}<br>public static void main(String args[]) {<br>for(int i = 0; i &lt; 5; i++) new MyThread(i+1).start();<br>}<br>}<br>这种方法简单明了，符合大家的习惯，但是，它也有一个很大的缺点，那就是如果我们的类已经从一个类继承（如小程序必须继承自 Applet 类），则无法再继承 Thread 类，这时如果我们又不想建立一个新的类，应该怎么办呢？<br>我们不妨来探索一种新的方法：我们不创建 Thread 类的子类，而是直接使用它，那么我们只能将我们的方法作为参数传递给 Thread 类的实例，有点类似回调函数。但是 Java 没有指针，我们只能传递一个包含这个方法的类的实例。那么如何限制这个类必须包含这一方法呢？当然是使用接口！（虽然抽象类也可满足，但是需要继承，而我们之所以要采用这种新方法，不就是为了避免继承带来的限制吗？）<br>Java 提供了接口 java.lang.Runnable 来支持这种方法。<br>方法二：实现 Runnable 接口<br>Runnable 接口只有一个方法 run()，我们声明自己的类实现 Runnable 接口并提供这一方法，将我们的线程代码写入其中，就完成了这一部分的任务。<br>但是 Runnable 接口并没有任何对线程的支持，我们还必须创建 Thread 类的实例，这一点通过 Thread 类的构造函数<br>public Thread(Runnable target);来实现。<br>下面是一个例子：<br>public class MyThread implements Runnable {<br>int count= 1, number;<br>public MyThread(int num) {<br>number = num;<br>System.out.println("创建线程 " + number);<br>}<br>public void run() {<br>while(true) {<br>System.out.println("线程 " + number + ":计数 " + count);<br>if(++count== 6) return;<br>} <br>}<br>public static void main(String args[]) {<br>for(int i = 0; i &lt; 5; i++) new Thread(new MyThread(i+1)).start();<br>}<br>}<br>严格地说，创建 Thread 子类的实例也是可行的，但是必须注意的是，该子类必须没有覆盖 Thread 类的 run 方法，否则该线程执行的将是子类的 run 方法，而不是我<br>们用以实现Runnable 接口的类的 run 方法，对此大家不妨试验一下。<br>使用 Runnable 接口来实现多线程使得我们能够在一个类中包容所有的代码，有利于封装，它的缺点在于，我们只能使用一套代码，若想创建多个线程并使各个线程执行不同的代码，则仍必须额外创建类，如果这样的话，在大多数情况下也许还不如直接用多个类分别继承 Thread 来得紧凑。<br>综上所述，两种方法各有千秋，大家可以灵活运用。<br>下面让我们一起来研究一下多线程使用中的一些问题。</font></p>
<p><font size=2>三：线程的四种状态<br>1. 新状态：线程已被创建但尚未执行（start() 尚未被调用）。<br>2. 可执行状态：线程可以执行，虽然不一定正在执行。CPU 时间随时可能被分配给该线程，从而使得它执行。<br>3. 死亡状态：正常情况下 run() 返回使得线程死亡。调用 stop()或 destroy() 亦有同样效果，但是不被推荐，前者会产生异常，后者是强制终止，不会释放锁。<br>4. 阻塞状态：线程不会被分配 CPU 时间，无法执行。</font></p>
<p><font size=2>四：线程的优先级 <br>线程的优先级代表该线程的重要程度，当有多个线程同时处于可执行状态并等待获得 CPU 时间时，线程调度系统根据各个线程的优先级来决定给谁分配 CPU 时间，优先级高的线程有更大的机会获得 CPU 时间，优先级低的线程也不是没有机会，只是机会要小一些罢了。<br>你可以调用 Thread 类的方法 getPriority() 和 setPriority()来存取线程的优先级，线程的优先级界于1(MIN_PRIORITY)和10(MAX_PRIORITY)之间，缺省是5(NORM_PRIORITY)。</font></p>
<p><br><font size=2>五：线程的同步<br>由于同一进程的多个线程共享同一片存储空间，在带来方便的同时，也带来了访问冲突这个严重的问题。Java语言提供了专门机制以解决这种冲突，有效避免了同一个数据对象被多个线程同时访问<br>由于我们可以通过 private 关键字来保证数据对象只能被方法访问，所以我们只需针对方法提出一套机制，这套机制就是 synchronized 关键字，它包括两种用法：synchronized 方法和 synchronized 块。<br>1. synchronized 方法：通过在方法声明中加入 synchronized关键字来声明 synchronized 方法。如<br>public synchronized void accessVal(int newVal);<br>synchronized 方法控制对类成员变量的访问：每个类实例对应一把锁，每个 synchronized 方法都必须获得调用该方法的类实例的锁方能执行，否则所属线程阻塞，方<br>法一旦执行，就独占该锁，直到从该方法返回时才将锁释放，此后被阻塞的线程方能获得该锁，重新进入可执行状态。这种机制确保了同一时刻对于每一个类实例，其所有声明为 synchronized 的成员函数中至多只有一个处于可执行状态（因为至多只有一个能够获得该类实例对应的锁），从而有效避免了类成员变量的访问冲突（只要所有可能访问类成员变量的方法均被声明为 synchronized）。<br>在 Java 中，不光是类实例，每一个类也对应一把锁，这样我们也可将类的静态成员函数声明为 synchronized ，以控制其对类的静态成员变量的访问。<br>synchronized 方法的缺陷：若将一个大的方法声明为synchronized 将会大大影响效率，典型地，若将线程类的方法 run() 声明为 synchronized ，由于在线程的整个生命期内它一直在运行，因此将导致它对本类任何 synchronized 方法的调用都永远不会成功。当然我们可以通过将访问类成员变量的代码放到专门的方法中，将其声明为 synchronized ，并在主方法中调用来解决这一问题，但是 Java 为我们提供了更好的解决办法，那就是 synchronized 块。<br>2. synchronized 块：通过 synchronized关键字来声明synchronized 块。语法如下： <br>synchronized(syncObject) {<br>//允许访问控制的代码<br>}<br>synchronized 块是这样一个代码块，其中的代码必须获得对象 syncObject （如前所述，可以是类实例或类）的锁方能执行，具体机制同前所述。由于可以针对任意代码块，且可任意指定上锁的对象，故灵活性较高。<br>六：线程的阻塞<br>为了解决对共享存储区的访问冲突，Java 引入了同步机制，现在让我们来考察多个线程对共享资源的访问，显然同步机制已经不够了，因为在任意时刻所要求的资源不一定已经准备好了被访问，反过来，同一时刻准备好了的资源也可能不止一个。为了解决这种情况下的访问控制问题，Java 引入了对阻塞机制的支持。<br>阻塞指的是暂停一个线程的执行以等待某个条件发生（如某资源就绪），学过操作系统的同学对它一定已经很熟悉了。Java 提供了大量方法来支持阻塞，下面让我们逐一分析。<br>1. sleep() 方法：sleep() 允许 指定以毫秒为单位的一段时间作为参数，它使得线程在指定的时间内进入阻塞状态，不能得到CPU 时间，指定的时间一过，线程重新进入可执行状态。<br>典型地，sleep() 被用在等待某个资源就绪的情形：测试发现条件不满足后，让线程阻塞一段时间后重新测试，直到条件满足为止。<br>2. suspend() 和 resume() 方法：两个方法配套使用，suspend()使得线程进入阻塞状态，并且不会自动恢复，必须其对应的resume() 被调用，才能使得线程重新进入可执行状态。典型地，suspend() 和 resume() 被用在等待另一个线程产生的结果的情形：测试发现结果还没有产生后，让线程阻塞，另一个线程产生了结果后，调用 resume() 使其恢复。<br>3. yield() 方法：yield() 使得线程放弃当前分得的 CPU 时间，但是不使线程阻塞，即线程仍处于可执行状态，随时可能再次分得 CPU 时间。调用 yield() 的效果等价于调度程序认为该线程已执行了足够的时间从而转到另一个线程。<br>4. wait() 和 notify() 方法：两个方法配套使用，wait() 使得线程进入阻塞状态，它有两种形式，一种允许 指定以毫秒为单位的一段时间作为参数，另一种没有参数，前者当对应的 notify() 被调用或者超出指定时间时线程重新进入可执行状态，后者则必须对应的 notify() 被调用。<br>初看起来它们与 suspend() 和 resume() 方法对没有什么分别，但是事实上它们是截然不同的。区别的核心在于，前面叙述的所有方法，阻塞时都不会释放占用的锁（如果占用了的话），而这一对方法则相反。<br>上述的核心区别导致了一系列的细节上的区别。<br>首先，前面叙述的所有方法都隶属于 Thread 类，但是这一对却直接隶属于 Object 类，也就是说，所有对象都拥有这一对方法。初看起来这十分不可思议，但是实际上却是很自然的，因为这一对方法阻塞时要释放占用的锁，而锁是任何对象都具有的，调用任意对象的 wait() 方法导致线程阻塞，并且该对象上的锁被释放。而调用 任意对象的notify()方法则导致因调用该对象的 wait() 方法而阻塞的线程中随机选择的一个解除阻塞（但要等到获得锁后才真正可执行）。<br>其次，前面叙述的所有方法都可在任何位置调用，但是这一对方法却必须在 synchronized 方法或块中调用，理由也很简单，只有在synchronized 方法或块中当前线程才占有锁，才有锁可以释放。同样的道理，调用这一对方法的对象上的锁必须为当前线程所拥有，这样才有锁可以释放。因此，这一对方法调用必须放置在这样的 synchronized 方法或块中，该方法或块的上锁对象就是调用这一对方法的对象。若不满足这一条件，则程序虽然仍能编译，但在运行时会出现IllegalMonitorStateException 异常。<br>wait() 和 notify() 方法的上述特性决定了它们经常和synchronized 方法或块一起使用，将它们和操作系统的进程间通信机制作一个比较就会发现它们的相似性：synchronized方法或块提供了类似于操作系统原语的功能，它们的执行不会受到多线程机制的干扰，而这一对方法则相当于 block 和wakeup 原语（这一对方法均声明为 synchronized）。它们的结合使得我们可以实现操作系统上一系列精妙的进程间通信的算法（如信号量算法），并用于解决各种复杂的线程间通信问题。<br>关于 wait() 和 notify() 方法最后再说明两点：<br>第一：调用 notify() 方法导致解除阻塞的线程是从因调用该对象的 wait() 方法而阻塞的线程中随机选取的，我们无法预料哪一个线程将会被选择，所以编程时要特别小心，避免因这种不确定性而产生问题。<br>第二：除了 notify()，还有一个方法 notifyAll() 也可起到类似作用，唯一的区别在于，调用 notifyAll() 方法将把因调用该对象的 wait() 方法而阻塞的所有线程一次性全部解除阻塞。当然，只有获得锁的那一个线程才能进入可执行状态。<br>谈到阻塞，就不能不谈一谈死锁，略一分析就能发现，suspend() 方法和不指定超时期限的 wait() 方法的调用都可能产生死锁。遗憾的是，Java 并不在语言级别上支持死锁的避免，我们在编程中必须小心地避免死锁。<br>以上我们对 Java 中实现线程阻塞的各种方法作了一番分析，我们重点分析了 wait() 和 notify() 方法，因为它们的功能最强大，使用也最灵活，但是这也导致了它们的效率较低，较容易出错。实际使用中我们应该灵活使用各种方法，以便更好地达到我们的目的。</font></p>
<p><font size=2>七：守护线程<br>守护线程是一类特殊的线程，它和普通线程的区别在于它并不是应用程序的核心部分，当一个应用程序的所有非守护线程终止运行时，即使仍然有守护线程在运行，应用程序也将终止，反之，只要有一个非守护线程在运行，应用程序就不会终止。守护线程一般被用于在后台为其它线程提供服务。<br>可以通过调用方法 isDaemon() 来判断一个线程是否是守护线程，也可以调用方法 setDaemon() 来将一个线程设为守护线程。</font></p>
<p><font size=2>八：线程组<br>线程组是一个 Java 特有的概念，在 Java 中，线程组是类ThreadGroup 的对象，每个线程都隶属于唯一一个线程组，这个线程组在线程创建时指定并在线程的整个生命期内都不能更改。你可以通过调用包含 ThreadGroup 类型参数的 Thread 类构造函数来指定线程属的线程组，若没有指定，则线程缺省地隶属于名为 system 的系统线程组。<br>在 Java 中，除了预建的系统线程组外，所有线程组都必须显式创建。<br>在 Java 中，除系统线程组外的每个线程组又隶属于另一个线程组，你可以在创建线程组时指定其所隶属的线程组，若没有指定，则缺省地隶属于系统线程组。这样，所有线程组组成了一棵以系统线程组为根的树。<br>Java 允许我们对一个线程组中的所有线程同时进行操作，比如我们可以通过调用线程组的相应方法来设置其中所有线程的优先级，也可以启动或阻塞其中的所有线程。<br>Java 的线程组机制的另一个重要作用是线程安全。线程组机制允许我们通过分组来区分有不同安全特性的线程，对不同组的线程进行不同的处理，还可以通过线程组的分层结构来支持不对等安全措施的采用。Java 的 ThreadGroup 类提供了大量的方法来方便我们对线程组树中的每一个线程组以及线程组中的每一个线程进行操作。</font></p>
<p><font size=2>九：总结<br>在这一讲中，我们一起学习了 Java 多线程编程的方方面面，包括创建线程，以及对多个线程进行调度、管理。我们深刻认识到了多线程编程的复杂性，以及线程切换开销带来的多线程程序的低效性，这也促使我们认真地思考一个问题：我们是否需要多线程？何时需要多线程？<br>多线程的核心在于多个代码块并发执行，本质特点在于各代码块之间的代码是乱序执行的。我们的程序是否需要多线程，就是要看这是否也是它的内在特点。<br>假如我们的程序根本不要求多个代码块并发执行，那自然不需要使用多线程；假如我们的程序虽然要求多个代码块并发执行，但是却不要求乱序，则我们完全可以用一个循环来简单高效地实现，也不需要使用多线程；只有当它完全符合多线程的特点时，多线程机制对线程间通信和线程管理的强大支持才能有用武之地，这时使用多线程才是值得的</font></p>
<img src ="http://www.blogjava.net/19851985lili/aggbug/113597.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/19851985lili/" target="_blank">☜♥☞MengChuChen</a> 2007-04-25 19:08 <a href="http://www.blogjava.net/19851985lili/articles/113597.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java 字符集编码</title><link>http://www.blogjava.net/19851985lili/articles/110341.html</link><dc:creator>☜♥☞MengChuChen</dc:creator><author>☜♥☞MengChuChen</author><pubDate>Fri, 13 Apr 2007 01:04:00 GMT</pubDate><guid>http://www.blogjava.net/19851985lili/articles/110341.html</guid><wfw:comment>http://www.blogjava.net/19851985lili/comments/110341.html</wfw:comment><comments>http://www.blogjava.net/19851985lili/articles/110341.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/19851985lili/comments/commentRss/110341.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/19851985lili/services/trackbacks/110341.html</trackback:ping><description><![CDATA[首先看清楚几种常用的字符集编码(java语言是采用unicode字符集编码来表示字符与字符串的)：<br><br>　　<strong>ASCII</strong>(American Standard Code for Information Interchange，美国信息互换标准代码)，是基于常用的英文字符的一套电脑编码系统。我们知道英文中经常使用的字符、数字符号被计算机处理时都是以二进制码的形式出现的。这种二进制码的集合就是所谓的ASCII码。每一个ASCII码与一个8位（bit）二进制数对应。其最高位是0，相应的十进制数是0-127。如，数字&#8220;0&#8221;的编码用十进制数表示就是48。另有128个扩展的ASCII码，最高位都是1，由一些制表符和其它符号组成。ASCII是现今最通用的单字节编码系统。
<p>　　<strong>GB2312</strong>：GB2312码是中华人民共和国国家汉字信息交换用编码，全称《信息交换用汉字编码字符集－基本集》。主要用于给每一个中文字符指定相应的数字，也就是进行编码。一个中文字符用两个字节的数字来表示，为了和ASCII码有所区别，将中文字符每一个字节的最高位置都用1来表示。<br><br>　　<strong>GBK</strong>：为了对更多的字符进行编码，国家又发布了新的编码系统GBK(GBK的K是&#8220;扩展&#8221;的汉语拼音第一个字母)。在新的编码系统里，除了完全兼容GB2312 外，还对繁体中文、一些不常用的汉字和许多符号进行了编码。</p>
<p>　　<strong>ISO-8859-1</strong>：是西方国家所使用的字符编码集，是一种单字节的字符集 ，而英文实际上只用了其中数字小于128的部分。</p>
<p>　　<strong>Unicode</strong>：这是一种通用的字符集，对所有语言的文字进行了统一编码，对每一个字符都用2个字节来表示，对于英文字符采取前面加&#8220;0&#8221;字节的策略实现等长兼容。如 &#8220;a&#8221; 的ASCII码为0x61，UNICODE就为0x00，0x61。</p>
<p>　　<strong>UTF-8</strong>：Eight-bit UCS Transformation Format，(UCS，Universal Character Set，通用字符集，UCS 是所有其他字符集标准的一个超集)。一个7位的ASCII码值，对应的UTF码是一个字节。如果字符是0x0000，或在0x0080与0x007f之间，对应的UTF码是两个字节，如果字符在0x0800与0xffff之间，对应的UTF码是三个字节。</p>
<p>　　我们运行java程序时，JVM有自己所支持的编码种类，用以下代码可以看到：</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"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top> <span style="COLOR: #000000">Map m</span> <span style="COLOR: #000000">=</span> <span style="COLOR: #000000">Charset.availableCharsets();<br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp; Set names</span> <span style="COLOR: #000000">=</span> <span style="COLOR: #000000">m.keySet();<br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp; Iterator it</span> <span style="COLOR: #000000">=</span> <span style="COLOR: #000000">names.iterator();<br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">while</span> <span style="COLOR: #000000">(it.hasNext())<br><img src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img style="DISPLAY: none" src="http://www.blogjava.net/Images/OutliningIndicators/ContractedBlock.gif" align=top>&nbsp;&nbsp;</span> <span 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"> </span><span><span style="COLOR: #000000">{<br><img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp; System.out.println(it.next());<br><img src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>&nbsp;&nbsp; }</span> </span></div>
<p><br>　　 然后可以通过以下代码看到我们目前JVM所使用的编码：<br></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"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top> <span style="COLOR: #000000">Properties pps</span> <span style="COLOR: #000000">=</span> <span style="COLOR: #000000">System.getProperties();<br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp; pps.list(System.out);</span> </div>
<p>　　具体来说什么是编码，什么是解码？<br>　　在InputStreamReader JDK有这样描述：It reads bytes and decodes them into characters using a specified charset.(用指定的字符集将字节数组解码成字符串)。<br>　　相反OutputStreamWriter 描述：Characters written to it are encoded into bytes using a specified charset.(用指定的字符集将字符串编码成字节数组)。<br><br>　　理解这个以后一切好办了啦！<br><br>　　我们的OS一般是GBK编码的（凡是从磁盘上读取文件可以看成是用OS的字符集编码方式来对操作对象进行解码处理--从标准输入设备读取数据的时候是依赖OS的字符集）。而我们将从磁盘上文件经过处理得到我们想要的字符串等其它对象的时候，这一过程是用JVM的默认的字符集编码方式来处理的！由于不同的字符集编码方式有着不同的原理(前面所述)，这样当编码与解码不一致的时候，自然而然就出现了可爱的乱码。<br><br>　　比如如下，将我们JVM字符集改成iso-8859-1这样在就与我们的OS不同：<br>　　当输入中文时自然就输出的是乱码了。</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"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top> <span style="COLOR: #000000">pps.put(</span> <span style="COLOR: #000000">"</span> <span style="COLOR: #000000">file.encoding</span> <span style="COLOR: #000000">"</span> <span style="COLOR: #000000">,</span> <span style="COLOR: #000000">"</span> <span style="COLOR: #000000">ISO-8859-1</span> <span style="COLOR: #000000">"</span> <span style="COLOR: #000000">);<br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">int</span> <span style="COLOR: #000000">data;<br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">byte</span> <span style="COLOR: #000000">[] buf</span> <span style="COLOR: #000000">=</span> <span style="COLOR: #0000ff">new</span> <span style="COLOR: #000000"></span><span style="COLOR: #0000ff">byte</span> <span style="COLOR: #000000">[</span> <span style="COLOR: #000000">100</span> <span style="COLOR: #000000">];<br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">int</span> <span style="COLOR: #000000">i</span> <span style="COLOR: #000000">=</span> <span style="COLOR: #000000">0</span> <span style="COLOR: #000000">;<br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">while</span> <span style="COLOR: #000000">((data</span> <span style="COLOR: #000000">=</span> <span style="COLOR: #000000">System.in.read())</span> <span style="COLOR: #000000">!=</span> <span style="COLOR: #000000">'</span> <span style="COLOR: #000000">q</span> <span style="COLOR: #000000">'</span> <span style="COLOR: #000000">)<br><img src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img style="DISPLAY: none" src="http://www.blogjava.net/Images/OutliningIndicators/ContractedBlock.gif" align=top>&nbsp;&nbsp;</span> <span 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"> </span><span><span style="COLOR: #000000">{<br><img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp; buf[i]</span> <span style="COLOR: #000000">=</span> <span style="COLOR: #000000">(</span> <span style="COLOR: #0000ff">byte</span> <span style="COLOR: #000000">)data;<br><img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp; i</span> <span style="COLOR: #000000">++</span> <span style="COLOR: #000000">;<br><img src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>&nbsp;&nbsp; }</span> </span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp; String str</span> <span style="COLOR: #000000">=</span> <span style="COLOR: #0000ff">new</span> <span style="COLOR: #000000">String(buf,</span> <span style="COLOR: #000000">0</span> <span style="COLOR: #000000">,i);<br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp; System.out.println(str);</span> </div>
<p>　<br>　　这时我们可以用string的一个构造方法：<br>　　<span style="COLOR: #000000">String(</span><span style="COLOR: #0000ff">byt</span><span style="COLOR: #000000">[] bytes, String charsetName) <br>　　Constructs a </span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000"> String by decoding the specified array of bytes using the specified </span>charset.(用指定的字符集对字节数组进行解码)。<br>　　其中用到了string 的getBytes方法：<br>　　getBytes(String charsetName) <br>　　Encodes this String into a sequence of bytes using the named charset, storing the result into a new byte array.(用指定的字符集进行编码，将结果存放到一字节数组里面)重新构造一个string：</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"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top> <span style="COLOR: #000000">String strGBK</span> <span style="COLOR: #000000">=</span> <span style="COLOR: #0000ff">new</span> <span style="COLOR: #000000">String(str.getBytes(</span> <span style="COLOR: #000000">"</span> <span style="COLOR: #000000">ISO-8859-1</span> <span style="COLOR: #000000">"</span> <span style="COLOR: #000000">),</span> <span style="COLOR: #000000">"</span> <span style="COLOR: #000000">GBK</span> <span style="COLOR: #000000">"</span> <span style="COLOR: #000000">);</span> </div>
<p>　　这样又可以重新得到我们想要的汉字了。<br><br>　　我们这例子中是GBK(OS)来编码的，然后采用iso-8859-1(JVM)来解码得到一个新string(此string是乱码)，然后将此string用iso-8859-1重新编码，并且用指定的GBK来解码。得到一个新string(也就是strGBK)，这个string就不再是乱码了。<br><br>　　但如果我们一开始就采用GBK解码得到的字符串，然后用ISO-8859-1编码，能否再解码回去得到我们的中文字符呢？显示不可以啦，因为用ISO-8859-1的编码的时候采用是一种单字节的字符集来对其编码，这样就丢失了一个字节(对中文来说)！所以这样是得不到中文字符的！</p>
<br>
<img src ="http://www.blogjava.net/19851985lili/aggbug/110341.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/19851985lili/" target="_blank">☜♥☞MengChuChen</a> 2007-04-13 09:04 <a href="http://www.blogjava.net/19851985lili/articles/110341.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java企业应用系统框架的比较与选择</title><link>http://www.blogjava.net/19851985lili/articles/110322.html</link><dc:creator>☜♥☞MengChuChen</dc:creator><author>☜♥☞MengChuChen</author><pubDate>Fri, 13 Apr 2007 00:24:00 GMT</pubDate><guid>http://www.blogjava.net/19851985lili/articles/110322.html</guid><wfw:comment>http://www.blogjava.net/19851985lili/comments/110322.html</wfw:comment><comments>http://www.blogjava.net/19851985lili/articles/110322.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/19851985lili/comments/commentRss/110322.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/19851985lili/services/trackbacks/110322.html</trackback:ping><description><![CDATA[　摘 要 目前流行的Java企业应用系统框架种类繁多，为了使开发人员正确选择系统架构从而提高Java企业应用的开发效率，首先针对基于EJB和基于POJOs的较为流行的几种框架分别进行了概述，然后对这些框架从表现层、业务逻辑层和持久层的实现细节进行了对比，总结了Java企业应用系统框架选择需要侧重考虑因素，得到了基于EJB的框架和基于POJOs的框架分别适用的范围。 <br><br><strong>　　关键词</strong> Java企业应用系统框架；EJB3.0；Spring；Hibernate <br><br>　　<strong>引言</strong> <br><br>　　EJB的体系结构是J2EE的基础和核心，J2EE定义了整个标准的应用开发体系结构和一个部署环境，基于EJB的框架一度成为人们开发Java企业应用的首选。随着Java开源项目阵营的发展壮大， 一些基于POJOs(Plan Old Java Objects)的开源框架被越来越广泛地引入到Java企业应用的开发中来。根据复杂程度人们习惯把前者称为重量级框架，把后者称为轻量级框架。Java企业应用框架一般被划分为三个层次：表现层、业务逻辑组件层和持久层。本文主要对目前企业应用对应于这三个层次的两种类型的流行框架进行了细节比较，最后针对Java企业应用的系统框架选择提出作者的观点。<br><br>　　<strong>两种类型框架概述</strong> <br><br>　　1、基于EJB的重量级框架 <br><br>　　由于 EJB容器能够很好的处理系统性能、事务机制、安全访问权限以及分布式运算等问题，基于EJB框架进行开发能保证企业应用平滑发展，而不是发展到一种规模就重新更换一套软件系统，且可以保证开发人员将大部份精力集中在业务逻辑的开发上。采用EJB框架开发的企业应用具有必须继承或依赖EJB容器的特点。EJB充分考虑到了顶级大型项目的需求，使用它几乎能解决企业级应用涉及到的所有问题，相应的基于EJB框架也是一个功能复杂的重量级框架。<br><br>　　J2EE1.4标准规定的EJB 2.1框架缺少设计且实现起来有些过于复杂。当前J2EE5.0的新规范提出的EJB 3.0的目标就是简化开发[1]，借鉴了一些基于POJO的思想，它相对于EJB2.1中两个重要的变化分别是：一是使用了Java5中的程序注释工具，注释取代了过多的XML配置文件并且消除了严格组件模型需求；二是采用了基于Hibernate和TopLink思想的O/R Mapping模型。<br><br>　　J2EE5.0的新规范中定义企业应用三个层次的标准实现为：表现层采用JSF（Java Server Face），JSF的开发流程的核心是事件驱动，组件和标签的封装程度非常高，很多典型应用已经不需要开发者去处理http。整个过程是通过IoC(依赖注入)[2]来实现的；业务组件层采用EJB3.0的Session Bean。EJB3.0允许开发者使用藕合松散的组件来开发应用。这些组件通过自己发布的商业接口来耦合，不必像EJB 2.1规范定义的那样一个Bean必须遵守的严格的组件模型，每一个EJB类必须从某一种抽象类中继承，并为容器提供了回调的钩子；持久层采用EJB3.0实体Bean持久化模型，吸收了Hibernate的一些思想采用O/R Mapping模式， EJBQL也有许多重要的改变。<br><br>　　2、基于POJOs的轻量级框架<br><br>　　在基于POJOs轻量级框架上开发的应用程序无需依赖于EJB容器可独立运行，对应于Java企业应用三个层次的轻量级框架技术分别都得到了一定的发展，这三个层次流行的框架如下：<br><br>　　目前比较流行的开源表现层框架主要有Struts和Tapestry。Tapestry与Struts应用框架不同的是，它是基于组件，而不是面向脚本语言（比如JSP和Velocity）的，组件是由一个定义文件(以XML的格式)、一个HTML模板、一个JAVA类构成的；业务组件层轻量级解决方案也不少，包括Spring、Hivemind等。但是目前使用最为广泛的还是Spring框架，Spring框架是一个基于IoC和AOP（面向方面编程）[3]的构架。采用IoC使得它可以很容易的实现bean的装配，提供了简洁的AOP并据此实现事务管理等，但是它不具备处理应用分布式的能力。Spring的核心要点是：支持不绑定到特定J2EE服务的可重用业务和数据访问对象。这样的对象可以在不同J2EE环境（Web或EJB）、独立应用程序、测试环境之间重用；持久层框主要有Hibernate和各种JDO产品，以及iBATIS。Hibernate是一个开源的O/R Mapping框架，它对JDBC进行了非常轻量级的对象封装，可以应用在任何使用JDBC的场合，可以在应用EJB的J2EE框架中取代CMP，完成数据持久化的重任。iBATIS是一个简易的SQL Map工具，它是将手工编写的在xml配置文件中的SQL语句映射成Java对象。<br>　　<strong>对应于三个层次的框架比较</strong> <br><br>　　1、表现层框架比较 <br><br>　　MVC设计模式不再是某一种表现层框架的特点而是这几种框架的共性。Struts框架由于出现时间早，所以使用相对广泛，它的社区非常活跃，很容易找到很多现成的开源功能标签以供使用以及样例程序可供参考。但是它的组件在页面中显示的粗粒度，以及框架类的限制在很多情况下会表现得过于死板，给表示层的开发会带来一些额外的代码开销。JSF在很大程度上类似Struts，只是JSF的组件概念没有象Struts那样必须继承ActionForm的限制，JSF在事件粒度上要比Struts细腻。JSF有的另外一个优势就是其身后有Sun公司和其他的一些大公司的支持。Tapestry是一个完全组件的框架，Tapestry的组件可以被套嵌并包裹其它组件，因此可以组合形成一个更大的组件或逻辑页面。组件的行为模式为Web页面编程提供了很大的方便，事件处理也方便很多。所以，如果做一个对页面要求灵活度相当高的系统就可以考虑选用Tapestry。<br><br>　　表1 三种框架的表现层功能技术细节比较<br><br>
<table cellSpacing=0 cellPadding=0 border=1>
    <tbody>
        <tr>
            <td width=96><br>框架<br></td>
            <td width=228><br>Struts<br></td>
            <td width=168><br>Tapestry3.0<br></td>
            <td width=156><br>JSF<br></td>
        </tr>
        <tr>
            <td width=96><br>View组件实现模式<br></td>
            <td width=228><br>标签库+组件，组件必须继承ActionForm<br></td>
            <td width=168><br>完全组件，分显式调用和隐式调用，组件必须继承BaseComponent<br></td>
            <td width=156><br>标签库+组件，普通POJO无需继承<br></td>
        </tr>
        <tr>
            <td width=96><br>组件在View显示粒度<br></td>
            <td width=228><br>View页面只能显示与表单对应的ActionForm，配置中Action与 ActionForm与 页面一般只能1:1:1关系。<br></td>
            <td width=168><br>可将组件嵌入页面任何一行，对使用组件数量无限制。<br></td>
            <td width=156><br>同Tapestry<br></td>
        </tr>
        <tr>
            <td width=96><br>页面跳转<br></td>
            <td width=228><br>使用标签库html:link中写明目标URL，URL名称需要对照struts_config.xml配置文件中的path命名，与组件Action耦合。<br></td>
            <td width=168><br>URL名称是目标的组件名称，不涉及URL和路径等操作，方便稳固。<br></td>
            <td width=156><br>类似Struts，也需要在配置文件中查找，与组件分离。<br></td>
        </tr>
        <tr>
            <td width=96><br>事件触发<br></td>
            <td width=228><br>通过表单提交submit激活，不能细化到表单里字段。<br></td>
            <td width=168><br>能够给于表单每个字段赋一个事件，事件组件必须实现PageListener接口<br></td>
            <td width=156><br>同Tapestry，事件组件必须实现ActionListener <br></td>
        </tr>
    </tbody>
</table>
<br>　　2、业务组件层框架比较 <br><br>　　EJB 2.1框架有些过于复杂了，有如下缺点：① EJB模型需要建立许多组件接口和实现许多不必要的回滚方法；②EJB的部署描述复杂而容易出错；③开发人员不能脱离EJB容器测试。对于以上缺点JCP (Java Community Process)制订的EJB3.0标准框架做了相应的改进，该框架为所有主要的J2EE厂商支持。EJB3.0和Spring两个框架结构都有一个共同核心设计理念：将中间件服务传递给耦合松散的POJOs。<br><br>　　EJB3.0框架与应用<a class=bluekey href="http://server.chinabyte.com/" target=_blank><u><font color=#0000ff>服务器</font></u></a>高度整合，服务整合代码也包装在一个标准接口后面。EJB框架一方面有成熟的EJB容器支持，基于EJB框架的企业应用性能优良；另一方面EJB容器设计因为考虑了多方面的功能，所以在其内核上总是会显得臃肿，这也是一种重量表现。不需要的东西存在肯定会影响效率，EJB不能根据项目需求对EJB整体包括EJB容器进行可配置式的切割。<br><br>　　Spring框架处于应用服务器和服务库的上方，服务整合的代码属于框架，并暴露于应用开发者。它与应用服务器整合的能力相对EJB3.0要弱。但是Spring框架模块的可分离配置体现了它优于EJB3.0的灵活性。<br><br>　　表2 EJB和Spring框架的具体细节比较<br>
<table cellSpacing=0 cellPadding=0 border=1>
    <tbody>
        <tr>
            <td width=96><br>框架<br></td>
            <td width=258><br>EJB2/EJB3<br></td>
            <td width=294><br>Spring Framework 1.x<br></td>
        </tr>
        <tr>
            <td width=96><br>灵活性(松耦合)<br></td>
            <td width=258><br>EJB3比EJB2更具灵活性，EJB3支持应用系统POJO<br></td>
            <td width=294><br>支持应用系统POJO，框架本身可分离配置<br></td>
        </tr>
        <tr>
            <td width=96><br>功能完整性<br></td>
            <td width=258><br>全面，支持异步JMS 分布式事务<br></td>
            <td width=294><br>较为全面。有自己的表现层和持久层模板，可支持异步<br></td>
        </tr>
        <tr>
            <td width=96><br>领域范围<br></td>
            <td width=258><br>支持业务逻辑Session<br></td>
            <td width=294><br>不支持，需要开发者额外基于ThreadLocal编制代码<br></td>
        </tr>
        <tr>
            <td width=96><br>IoC/AOP支持<br></td>
            <td width=258><br>EJB3支持IoC， JBoss等EJB3服务器支持AOP；基于业务组件的较粗粒度<br></td>
            <td width=294><br>基于JavaBeans类的细粒度支持AOP<br></td>
        </tr>
        <tr>
            <td width=96><br>单台性能<br></td>
            <td width=258><br>一般，批量查询等大数据量业务处理须小心，存在本地不透明缺陷。<br></td>
            <td width=294><br>一般，应用程序可配置cache/Pool以提高性能<br></td>
        </tr>
        <tr>
            <td width=96><br>可伸缩性<br></td>
            <td width=258><br>可支持多台服务器分布式计算。<br></td>
            <td width=294><br>不支持，可依靠EJB实现<br></td>
        </tr>
        <tr>
            <td width=96><br>开发效率<br></td>
            <td vAlign=top width=258><br>学习曲线长，导致熟练掌握难。借助商业开发工具可加快熟练者的开发速度。<br></td>
            <td vAlign=top width=294><br>可挑选只适合自己的功能实现。相对EJB稍简单。<br></td>
        </tr>
        <tr>
            <td width=96><br>系统规模<br></td>
            <td width=258><br>EJB2适合大型系统;EJB3适合中大型系统<br></td>
            <td width=294><br>适合中小型系统，可借助EJB支持中大型系统<br></td>
        </tr>
    </tbody>
</table>
<br>　　3、持久层框架比较 <br><br>　　容器管理持久性（CMP）是对EJB中Entity Bean进行持久性管理的方式。EJB2.1 持久性模型过于复杂并且存在基础缺陷[3]。EJB3.0持久层针对EJB2.1的缺陷做了相应改进，采用与Hibernate类似的机制。<br><br>　　Hibernate相对而言其基本优势如下：①Hibernate 使用 Java 反射机制而不是字节码增强程序来实现透明性；②Hibernate的使用简单；③映射的灵活性很出色，它支持各种关系数据库，从一对一到多对多的各种复杂关系。Hibernate 也有一些缺点，它限制所使用的对象模型 (例如，一个持久性类不能映射到多个表)。 <br>　　　　　　　　　　　　　　　　　　　　　　　<br>　　使用iBATIS提供的O/R Mapping机制，对业务逻辑实现人员而言，面对的是纯粹的Java对象，这一层与通过Hibernate 实现O/R Mapping 而言基本一致，而对于具体的数据操作，Hibernate 会自动生成SQL 语句，而iBATIS则要求开发者编写具体的SQL 语句。相对Hibernate等 &#8220;全自动&#8221;O/R Mapping机制而言，iBATIS以SQL开发的工作量和数据库移植性上的让步，为系统设计提供了更大的自由空间。作为&#8220;全自动&#8221;ORM 实现的一种有益补充，iBATIS的出现显得别具意义。<br><br>　　<strong>企业应用系统框架选择</strong> <br><br>　　设计和性能是实际框架选择的两个基本点，善于平衡才是框架选择的主要宗旨。轻量级框架和重量级框架解决问题的侧重点是不同的。<br><br>　　轻量级框架侧重于减小开发的复杂度，相应的它的处理能力便有所减弱（如事务功能弱、不具备分布式处理能力），比较适用于开发中小型企业应用。采用轻量框架一方面因为尽可能的采用基于POJOs的方法进行开发，使应用不依赖于任何容器，这可以提高开发调试效率；另一方面轻量级框架多数是开源项目，开源社区提供了良好的设计和许多快速构建工具以及大量现成可供参考的开源代码，这有利于项目的快速开发。例如目前Tomcat+Spring+Hibernate已经成为许多开发者开发J2EE中小型企业应用偏爱的一种架构选择。随着可供选择的框架层出不穷，开发者可以根据需要对应于企业应用三个层次的轻量级框架选择，本文第2节的内容可供选择参考。<br><br>　　而作为重量级框架EJB框架则强调高可伸缩性，适合与开发大型企业应用。在EJB体系结构中，一切与基础结构服务相关的问题和底层分配问题都由应用程序容器或服务器来处理，且EJB容器通过减少数据库访问次数以及分布式处理等方式提供了专门的系统性能解决方案，能够充分解决系统性能问题。<br><br>　　轻量级框架的产生并非是对重量级框架的否定，甚至在某种程度上可以说二者是互补的。轻量级框架在努力发展以开发具有更强大，功能更完备的企业应用；而新的EJB规范EJB3.0则在努力简化J2EE的使用以使得EJB不仅仅是擅长处理大型企业系统，也利用开发中小型系统，这也是EJB轻量化的一种努力。对于大型企业应用以及将来可能涉及到能力扩展的中小型应用采用结合使用轻量级框架和重量级框架也不失为一种较好的解决方案。<br><br>　　<strong>总结</strong> 　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　<br>　　目前适用Java企业应用的系统框架可谓百花齐放，各种框架都有长短，选择应用系统框架时不可盲目的追求流行，首先需要明确所要实现的应用系统的系统处理能力需求，然后在熟悉比较各种框架细节的基础上从设计以及开发效率方面进行考虑。本文旨在为系统框架选择提供一个参考，限于篇幅本文只对其中的几种框架做了比较，开发者可以根据需要对更多其他框架细节进行比较。(转载文章请保留出处：<a href="http://www.javajia.com/"><u><font color=#0000ff>Java家(www.javajia.com)</font></u></a>) 
<img src ="http://www.blogjava.net/19851985lili/aggbug/110322.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/19851985lili/" target="_blank">☜♥☞MengChuChen</a> 2007-04-13 08:24 <a href="http://www.blogjava.net/19851985lili/articles/110322.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>调试</title><link>http://www.blogjava.net/19851985lili/articles/110321.html</link><dc:creator>☜♥☞MengChuChen</dc:creator><author>☜♥☞MengChuChen</author><pubDate>Fri, 13 Apr 2007 00:20:00 GMT</pubDate><guid>http://www.blogjava.net/19851985lili/articles/110321.html</guid><wfw:comment>http://www.blogjava.net/19851985lili/comments/110321.html</wfw:comment><comments>http://www.blogjava.net/19851985lili/articles/110321.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/19851985lili/comments/commentRss/110321.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/19851985lili/services/trackbacks/110321.html</trackback:ping><description><![CDATA[<p align=justify>弗雷德里克&#183;布鲁克斯（Frederick P. Brooks）博士在他那篇著名的《没有银弹——<a name=baidusnap0></a><strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">软件工程中的根本和次要问题</strong>》一文中，将软件项目比作可怕的人狼（werewolves），并大胆地预言十年内不会找到特别有效的银弹。该论文发表的时间是1986年，如今整整20年过去了，尽管不时有人惊呼找到了神奇的银弹，但是冷静的人们很快发现那只是美好的愿望。<br><br>如果说软件工业中与人狼的战斗还在持续，那么在这些战役中一定会有程序员的身影，笔者也是其中的一个。我的编程生涯是从使用汇编语言编写DOS下的TSR程序开始的。今天DOS操作系统已经成为历史，在那个年代最值得炫耀的TSR技术也早已经过时了。十几年中，OWL、VFW、VDX、ISAPI、Active Movie等技术也被时间淘汰&#8230;&#8230;然而，在这漫长的时间当中，我最看重的是软件调试技术。它是十几年中我学到的最有用、一直受用、而且日久弥新的一项技术。&nbsp; <span>其实就是</span><span>:</span><span> "</span><span>软</span><span>件工程</span><span>"</span><span>与</span><span>"</span><span>软</span><span>件工</span><span>艺</span><span>"</span><span>之</span><span>间门</span><span>派之争的</span><span>问题</span><span><br></span><br>从软件工程的角度来讲，软件调试是软件工程的一个重要部分，软件调试过程出现在软件工程的各个阶段。从最初的可行性分析、原型验证、到开发和测试阶段、再到发布后的维护与支持，都有软件调试过程的参与。通常认为，一个完整的软件调试过程由以下几个步骤组成：<br>● 重现故障，通常是在用于调试的系统上重复导致故障的步骤，使要解决的问题出现在被调试的系统中。<br>● 定位根源，即综合利用各种调试工具，使用各种调试手段寻找导致软件故障的根源（root cause）。通常测试人员报告和描述的是软件界面或工作行为中所表现出的异常，或者是与软件需求和功能规约不符的地方，泛指软件缺欠（defect）或者故障（failure）。而这些表面的缺欠总是由于一或多个内在因素所导致的。这些内因要么是代码的行为错误，要么是不行为错误（该作而未作）。<br>● 探索和实现解决方案，即根据寻找到的故障根源、和资源情况、紧迫程度等要求设计和实现解决方案。<br>● 验证方案，在目标环境中测试方案的有效性，又称为回归（regress）测试。如果问题已经解决，那么就可以关闭问题。如果没有解决则回到第3步调整和修改解决方案。<br>这些步骤中，定位根源常常是最困难也是最关键的步骤，它是软件调试过程的核心和灵魂。如果没有找到故障根源，那么解决方案便很是隔靴搔痒，或者头痛医脚，白白浪费了时间。<br>对软件调试的另一种更通俗的解释是指使用调试工具求解各种软件问题的过程,例如跟踪软件的执行过程,探索软件本身或者与其配套的其它软件或者硬件系统的工作原理等,这些过程的目的有可能是为了去除软件缺欠,也可能不是。<br><br>在了解了软件调试技术的基本概念以后，下面我们来看一下支撑软件调试技术的几种基本机制。<br>● 断点:即当被调试程序执行到某一空间或时间点时将其中断到调试器中。根据中断条件分为如下几种:<br>○&nbsp;&nbsp; 代码断点:当程序执行到指定内存地址的代码时中断到调试器。<br>○&nbsp;&nbsp; 数据断点:当程序访问指定内存地址的数据时中断到调试器。<br>○&nbsp;&nbsp; I/O断点:当程序访问指定I/O地址的端口时中断到调试器。<br>根据断点的设置方法,断点又分为软件断点和硬件断点。软件断点通常是通过向指定的代码位置插入专用的断点指令来实现的,比如IA32 CPU的INT 3指令（机器码为0xCC）就是断点指令。硬件断点通常是通过设置CPU的调试寄存器来设置的。IA32 CPU定义了8个调试寄存器,DR0~DR7,可以最多同时设置4个硬件断点(对于一个调试会话)。通过调试寄存器可以设置以上三种断点中的任一种,但是通过断点指令只可以设置代码断点。<br><br>● 单步跟踪:即让应用程序按照某单位一步步执行。根据单位，又分几种:<br>○&nbsp;&nbsp; 每次执行一条汇编指令，称为汇编语言一级的单步跟踪。设置IA32 CPU标志寄存器的TF（Trap Flag，即陷阱标志位）位，便可以让CPU每执行完一条指令便产生一个调试异常（INT 1），中断到调试器。<br>○&nbsp;&nbsp; 每次执行源代码（比汇编语言更高级的程序语言,如C/C++）的一条语句，又称为源代码级的单步跟踪。通常高级语言的单步跟踪是通过反复设置CPU的陷阱标志位来实现的,如果当前源代码行还没有执行完,那么调试器重新设置陷阱标志并让程序继续执行,直到该语句结束（EIP指向另一语句）才中断给用户。<br>○&nbsp;&nbsp; 每次执行一个程序分支，又称为分支到分支单步跟踪。设置IA32 CPU的DbgCtl MSR寄存器的BTF(Branch Trap Flag)标志后，便可以启用分支到分支单步跟踪。<br>○&nbsp;&nbsp; 每次执行一个任务（线程），即当一个任务（线程）被调度执行时中断到调试器。IA32架构所定义的任务状态段（TSS）中的T标志为实现这一功能提供了硬件一级的支持，但是很多调试器还有提供这项功能。<br><br>● 栈回溯（stack backtrace）:即通过记录在栈中的函数返回地址显示（追溯）函数调用过程。在将返回地址翻译成函数名时需要有调试符号（debug symbol）的支持。大多数编译器都支持在编译时生成调试符号。微软的调试符号服务器（http://msdl.microsoft.com/download/symbols）提供了大多数Windows系统文件的调试符号，是调试和学习Windows操作系统的宝贵资源。<br>● 调试信息输出（debug output/print）:即将程序运行的位置、变量状态等信息输出到调试器、窗口、文件或者其它可以观察到的地方。这种方法的优点是简单方便、不依赖于调试器，但也有明显的缺点，如效率低，安全性差，通常不可以动态开启，且难以管理等。在Windows操作系统中，驱动程序可以使用DbgPrint/DbgPrintEx来输出调试信息，应用程序可以调用OutputDebugString API。<br>● 日志（log）:将程序运行的状态信息写入到特定的文件或者数据库中。Windows操作系统提供了记录、观察和管理（删除和备份）日志的功能。Windows Vista新引入了名为Common Log File System（CLFS.SYS）的内核模块，用于进一步加强日志功能。<br>● 事件追踪（event trace）:通常用来监视频繁的复杂的软件过程，满足普通日志机制难以胜任的需求。比如监视大信息量的文件操作、网络通信等。ETW（Event Trace for Windows）是Windows操作系统内建的事件追踪机制，Windows内核本身和很多Windows下的软件工具（如Bootvis，TCP/IP View）都使用了该机制。<br><br>在以上机制中，断点和单步跟踪通常必须在有调试器参与的情况下才能使用。调试器（software debugger）是综合提供各种调试功能的软件工具。除了处理断点、单步跟踪、模块映射等调试事件外，调试器通常还提供如下功能:<br>● 观察和编辑被调试程序的内存和数据，如全局变量、局部变量、以及程序的栈和堆等重要数据结构。<br>● 观察和反汇编被调试程序的代码。<br>● 显示线程栈中的函数调用信息。<br>● 管理调试符号。<br>● 控制进程和线程，例如将被调试程序中断到调试器中，和恢复其执行等。<br>根据调试器所调试目标程序的工作模式，可以把调试器分为用户态调试器和内核态调试器，前者用于调试用户态下的各种程序（应用程序、系统服务、或者用户态的DLL模块），后者用于调试工作在内核模式的程序，如驱动程序和操作系统的内核部分。WinDbg是微软开发的一个免费调试器，它既可以用作用户态调试器，也可以用作内核态调试器，是调试Windows操作系统下的各种软件的一个强有力工具。我几乎每天都使用WinDbg，它是我的计算机中使用频率最高的软件之一。<br><br>最后，简要地描述一下软件调试技术的几个特征。<br>系统性——很多看似简单的调试机制都是依靠系统内的多个部件协同工作而完成的。以软件断点为例，CPU提供了指令支持和硬件级的异常机制，操作系统将异常以调试事件的形式分发给调试器，调试器响应调试事件并与用户交互。如果在做源代码级的调试，那么调试器又需要编译器所产生的调试符号来帮忙。<br>全局性——对于一个软件项目，应该在项目的设计和架构阶段就制定出全局的调试支持机制，并贯彻实施。比如，所有模块都应该使用统一的方法来输出调试信息、记录日志、报告错误，并公开统一的接口用做单元测试和故障诊断。这样不仅可以避免重复工作，而且增加了软件的可调适性（debuggability），有利于保证产品的质量和进度。<br>困难性——《C语言编程》一书的作者Brian Kernighan曾经说过，&#8220;调试天生就比编写代码难上一倍，如果你写出了最聪明的代码，那么你的智商就不足以调试这个代码。&#8221;因为，要调试一个程序，就必须深刻理解它的工作原理，不仅要知道how和表层的东西，还要知道why和深层次的内幕。另外，调试需要锲而不舍的探索精神和坚韧的耐力，这也让很多人望而却步。<br>综上所述，软件调试技术是与软件开发密不可分的一门技术，其初衷是为了定位和去除软件故障，但因为调试技术所具有的对软件的强大控制力和观察力，其应用早已延伸到了很多其它领域，比如逆向工程、计算机安全等等。<br>&nbsp; </p>
<p><strong><span>1 </span></strong><strong><span>大前提：</span></strong><strong><span>软</span></strong><strong><span>件活</span></strong><strong><span>动</span></strong><strong><span>包含根本任</span></strong><strong><span>务</span></strong><strong><span>和次要任</span></strong><strong><span>务</span></strong><strong></strong></p>
<p><span>布</span><span>鲁</span><span>克斯指出：所有</span><span>软</span><span>件活</span><span>动</span><span>包括：</span></p>
<p><span>根本任</span><span>务</span><span>——</span><span>打造构成抽象</span><span>软</span><span>件</span><span>实</span><span>体的</span><span>复杂</span><span>概念</span><span>结</span><span>构；</span></p>
<p><span>次要任</span><span>务</span><span>——</span><span>使用</span><span>编</span><span>程</span><span>语</span><span>言表达</span><span>这</span><span>些抽象</span><span>实</span><span>体，并在</span><span>时间</span><span>和空</span><span>间</span><span>内将它</span><span>们</span><span>映射成机器</span><span>语</span><span>言</span><span>。</span></p>
<p><strong><span>2 </span></strong><strong><span>小前提：</span></strong><strong><span>现</span></strong><strong><span>有解决方案致力于解决次要任</span></strong><strong><span>务</span></strong><strong></strong></p>
<p><span>考察和</span><span>评</span><span>估几乎</span><span>现</span><span>有所有的</span><span>软</span><span>件工程解决方案，布</span><span>鲁</span><span>克斯指出：</span><span>现</span><span>有所有方案全都在致力于解决</span><span>软</span><span>件工程中的次要</span><span>问题</span><span>。</span></p>
<p><strong><span>3 </span></strong><strong><span>结论</span></strong><strong><span>：没有</span></strong><strong><span>银弹</span></strong><strong></strong></p>
<p><span>无</span><span>论这</span><span>些方案多</span><span>么</span><span>完善，都不可能在根本上解决</span><span>问题</span><span>，即使将全部次要任</span><span>务</span><span>的</span><span>时间缩</span><span>减到零，也不会</span><span>带</span><span>来生</span><span>产</span><span>率数量</span><span>级</span><span>上的提高</span><span>。</span><span> </span></p>
<p><strong><span>应</span></strong><strong><span>用孤</span></strong><strong><span>岛问题</span></strong><span>：管理</span><span>软</span><span>件如何</span><span>实</span><span>施、</span><span>应</span><span>用的</span><span>问题</span></p>
<p><span>由于基</span><span>础</span><span>架构的先天不足，</span><span>现</span><span>有的信息系</span><span>统</span><span>，无</span><span>论</span><span>是独立的工具</span><span>软</span><span>件</span><span>还</span><span>是集成的解决方案，大多是孤</span><span>岛</span><span>型的</span><span>应</span><span>用，或者是</span><span>业务</span><span>功能模</span><span>块</span><span>的</span><span>简单</span><span>累加。</span><span>这</span><span>些孤</span><span>岛</span><span>系</span><span>统</span><span>，相互之</span><span>间</span><span>是孤立封</span><span>闭</span><span>的</span></p>
<p><strong><span>IT</span></strong><strong><span>黑洞</span></strong><strong><span>问题</span></strong><span>：</span><span>管理</span><span>软</span><span>件如何</span><span>设计</span><span>、</span><span>开发</span><span>和</span><span>维护</span><span>的</span><span>问题</span></p>
<p><span>现</span><span>有信息系</span><span>统</span><span>的建</span><span>设</span><span>，是在底</span><span>层</span><span>的技</span><span>术</span><span>平台上直接构建</span><span>业务</span><span>系</span><span>统</span><span>，并且也只能采用面向技</span><span>术</span><span>的、</span><span>业务</span><span>无</span><span>关</span><span>的</span><span>&#8220;</span><span>原始</span><span>&#8221;</span><span>编</span><span>程工具来</span><span>开发</span><span>管理系</span><span>统</span><span> </span><span>。</span><span>这种</span><span>低</span><span>层</span><span>次的</span><span>软</span><span>件</span><span>开发</span><span>模式，使信息系</span><span>统</span><span>的</span><span>开发</span><span>、</span><span>维护</span><span>和</span><span>扩</span><span>展困</span><span>难</span><span>重重，</span><span>导</span><span>致</span><span>IT</span><span>黑洞</span><span>现</span><span>象的普遍</span><span>发</span><span>生</span></p>
<img src ="http://www.blogjava.net/19851985lili/aggbug/110321.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/19851985lili/" target="_blank">☜♥☞MengChuChen</a> 2007-04-13 08:20 <a href="http://www.blogjava.net/19851985lili/articles/110321.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>计算机编码大全</title><link>http://www.blogjava.net/19851985lili/articles/108100.html</link><dc:creator>☜♥☞MengChuChen</dc:creator><author>☜♥☞MengChuChen</author><pubDate>Tue, 03 Apr 2007 00:33:00 GMT</pubDate><guid>http://www.blogjava.net/19851985lili/articles/108100.html</guid><wfw:comment>http://www.blogjava.net/19851985lili/comments/108100.html</wfw:comment><comments>http://www.blogjava.net/19851985lili/articles/108100.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/19851985lili/comments/commentRss/108100.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/19851985lili/services/trackbacks/108100.html</trackback:ping><description><![CDATA[<font size=2>基础的开始<br>最小的单元是位（bit），接着是字节（Byte），一个字节＝8位，英语表示是1 byte=8 bits 。机器语言的单位Byte。接着是KB，1 KB=1024 Byte; 接着是MB，1 MB=1024 KB; 接着是GB，1 GB=1024 MB ;接着是TB, 1TB=1024 GB。<br>接着是进制：二进制0和1，8进制0-7， 十进制不用说，10进制0-9后面是A,B,C,D,E,F 他们关系如下：<br>Binary &nbsp; Octal Decimal Hex<br>0 &nbsp; &nbsp; &nbsp; 0 &nbsp; &nbsp; 0 &nbsp; &nbsp; 0<br>1 &nbsp; &nbsp; &nbsp; 1 &nbsp; &nbsp; 1 &nbsp; &nbsp; 1<br>10 &nbsp; &nbsp; &nbsp; 2 &nbsp; &nbsp; 2 &nbsp; &nbsp; 2<br>11 &nbsp; &nbsp; &nbsp; 3 &nbsp; &nbsp; 3 &nbsp; &nbsp; 3<br>100 &nbsp; &nbsp; 4 &nbsp; &nbsp; 4 &nbsp; &nbsp; 4<br>101 &nbsp; &nbsp; 5 &nbsp; &nbsp; 5 &nbsp; &nbsp; 5<br>110 &nbsp; &nbsp; 6 &nbsp; &nbsp; 6 &nbsp; &nbsp; 6<br>111 &nbsp; &nbsp; 7 &nbsp; &nbsp; 7 &nbsp; &nbsp; 7<br>1000 &nbsp; &nbsp; 10 &nbsp; 8 &nbsp; &nbsp; 8<br>1001 &nbsp; &nbsp; 11 &nbsp; 9 &nbsp; &nbsp; 9<br>1010 &nbsp; &nbsp; 12 &nbsp; 10 &nbsp; &nbsp; A<br>1011 &nbsp; &nbsp; 13 &nbsp; 11 &nbsp; &nbsp; B<br>1100 &nbsp; &nbsp; 14 &nbsp; 12 &nbsp; &nbsp; C<br>1101 &nbsp; &nbsp; 15 &nbsp; 13 &nbsp; &nbsp; D<br>1110 &nbsp; &nbsp; 16 &nbsp; 14 &nbsp; &nbsp; E<br>1111 &nbsp; &nbsp; 17 &nbsp; 15 &nbsp; &nbsp; F<br><br>接着是上层建筑字符：<br><br>字符是各种文字和符号的总称，包括各国家文字、标点符号、图形符号、数字等。字符集是多个字符的集合，字符集种类较多，每个字符集包含的字符个数不同，常见字符集名称：ASCII字符集、GB2312字符集、BIG5字符集、 GB 18030字符集、Unicode字符集等。计算机要准确的处理各种字符集文字，需要进行字符编码，以便计算机能够识别和存储各种文字。<br><br>ASCII 字符集<br>ASCII（American Standard Code for Information Interchange，美国信息互换标准代码）是基于罗马字母表的一套电脑编码系统，它主要用于显示现代英语和其他西欧语言。它是现今最通用的单字节编码系统，并等同于国际标准ISO 646。<br><br>包含内容：<br><br>控制字符：回车键、退格、换行键等。<br><br>可显示字符：英文大小写字符、阿拉伯数字和西文符号<br><br>ASCII扩展字符集扩展：表格符号、计算符号、希腊字母和特殊的拉丁符号。 <br><br>　　第0～32号及第127号(共34个)是控制字符或通讯专用字符，如控制符：LF（换行）、CR（回车）、FF（换页）、DEL（删除）、BEL（振铃）等；通讯专用字符：SOH（文头）、EOT（文尾）、ACK（确认）等； <br><br>　　第33～126号(共94个)是字符，其中第48～57号为0～9十个阿拉伯数字；65～90号为26个大写英文字母，97～122号为26个小写英文字母，其余为一些标点符号、运算符号等。 <br><br>　　注意：在计算机的存储单元中，一个ASCII码值占一个字节(8个二进制位)，其最高位(b7)用作奇偶校验位。所谓奇偶校验，是指在代码传送过程中用来检验是否出现错误的一种方法，一般分奇校验和偶校验两种。奇校验规定：正确的代码一个字节中1的个数必须是奇数，若非奇数，则在最高位b7添1；偶校验规定：正确的代码一个字节中1的个数必须是偶数，若非偶数，则在最高位b7添1。<br><br>DEC &nbsp; HEX CHAR CODE C 程序（转义） <br>0 &nbsp; 00 　 NUL （&#8217;\0&#8217;） <br>1 &nbsp; 01 　 SOH 　 <br>2 &nbsp; 02 　 STX 　 <br>3 &nbsp; 03 　 ETX 　 <br>4 &nbsp; 04 　 EOT 　 <br>5 &nbsp; 05 　 ENQ 　 <br>6 &nbsp; 06 　 ACK 　 <br>7 &nbsp; 07 　 BEL （&#8217;\a&#8217;） <br>8 &nbsp; 08 　 BS （&#8217;\b&#8217;） <br>9 &nbsp; 09 　 HT （&#8217;\t&#8217;） <br>10 &nbsp; 0A 　 LF （&#8217;\n&#8217;） <br>11 &nbsp; 0B 　 VT （&#8217;\v&#8217;） <br>12 &nbsp; 0C 　 FF （&#8217;\f&#8217;） <br>13 &nbsp; 0D 　 CR （&#8217;\r&#8217;） <br>14 &nbsp; 0E 　 SO 　 <br>15 &nbsp; 0F 　 SI 　 <br>16 &nbsp; 10 　 DLE 　 <br>17 &nbsp; 11 　 DC1 　 <br>18 &nbsp; 12 　 DC2 　 <br>19 &nbsp; 13 　 DC1 　 <br>20 &nbsp; 14 　 DC4 　 <br>21 &nbsp; 15 　 NAK 　 <br>22 &nbsp; 16 　 SYN 　 <br>23 &nbsp; 17 　 ETB 　 <br>24 &nbsp; 18 　 CAN 　 <br>25 &nbsp; 19 　 EM 　 <br>26 &nbsp; 1A 　 SUB 　 <br>27 &nbsp; 1B 　 ESC 　 <br>28 &nbsp; 1C 　 FS 　 <br>29 &nbsp; 1D 　 GS 　 <br>30 &nbsp; 1E 　 RS 　 <br>31 &nbsp; 1F 　 US 　 <br>32 &nbsp; 20 (space，空格) 　 　 <br>33 &nbsp; 21 &nbsp; ! 　 　 <br>34 &nbsp; 22 &nbsp; " 　 　 <br>35 &nbsp; 23 &nbsp; # 　 　 <br>36 &nbsp; 24 &nbsp; $ 　 　 <br>37 &nbsp; 25 &nbsp; % 　 　 <br>38 &nbsp; 26 &nbsp; &amp; 　 　 <br>39 &nbsp; 27 &nbsp; &#8217; 　 　 <br>40 &nbsp; 28 &nbsp; ( 　 　 <br>41 &nbsp; 29 &nbsp; ) 　 　 <br>42 &nbsp; 2A &nbsp; * 　 　 <br>43 &nbsp; 2B &nbsp; + 　 　 <br>44 &nbsp; 2C &nbsp; , 　 　 <br>45 &nbsp; 2D &nbsp; - 　 　 <br>46 &nbsp; 2E &nbsp; . 　 　 <br>47 &nbsp; 2F &nbsp; / 　 　 <br>48 &nbsp; 30 &nbsp; 0 　 　 <br>49 &nbsp; 31 &nbsp; 1 　 　 <br>50 &nbsp; 32 &nbsp; 2 　 　 <br>51 &nbsp; 33 &nbsp; 3 　 　 <br>52 &nbsp; 34 &nbsp; 4 　 　 <br>53 &nbsp; 35 &nbsp; 5 　 　 <br>54 &nbsp; 36 &nbsp; 6 　 　 <br>55 &nbsp; 37 &nbsp; 7 　 　 <br>56 &nbsp; 38 &nbsp; 8 　 　 <br>57 &nbsp; 39 &nbsp; 9 　 　 <br>58 &nbsp; 3A &nbsp; : 　 　 <br>59 &nbsp; 3B &nbsp; ; 　 　 <br>60 &nbsp; 3C &nbsp; &lt; 　 　 <br>61 &nbsp; 3D &nbsp; = 　 　 <br>62 &nbsp; 3E &nbsp; &gt; 　 　 <br>63 &nbsp; 3F &nbsp; ? 　 　 <br>64 &nbsp; 40 &nbsp; @ 　 　 <br>65 &nbsp; 41 &nbsp; A 　 　 <br>66 &nbsp; 42 &nbsp; B 　 　 <br>67 &nbsp; 43 &nbsp; C 　 　 <br>68 &nbsp; 44 &nbsp; D 　 　 <br>69 &nbsp; 45 &nbsp; E 　 　 <br>70 &nbsp; 46 &nbsp; F 　 　 <br>71 &nbsp; 47 &nbsp; G 　 　 <br>72 &nbsp; 48 &nbsp; H 　 　 <br>73 &nbsp; 49 &nbsp; I 　 　 <br>74 &nbsp; 4A &nbsp; J 　 　 <br>75 &nbsp; 4B &nbsp; K 　 　 <br>76 &nbsp; 4C &nbsp; L 　 　 <br>77 &nbsp; 4D &nbsp; M 　 　 <br>78 &nbsp; 4E &nbsp; N 　 　 <br>79 &nbsp; 4F &nbsp; O 　 　 <br>80 &nbsp; 50 &nbsp; P 　 　 <br>81 &nbsp; 51 &nbsp; Q 　 　 <br>82 &nbsp; 52 &nbsp; R 　 　 <br>83 &nbsp; 53 &nbsp; S 　 　 <br>84 &nbsp; 54 &nbsp; T 　 　 <br>85 &nbsp; 55 &nbsp; U 　 　 <br>86 &nbsp; 56 &nbsp; V 　 　 <br>87 &nbsp; 57 &nbsp; W 　 　 <br>88 &nbsp; 58 &nbsp; X 　 　 <br>89 &nbsp; 59 &nbsp; Y 　 　 <br>90 &nbsp; 5A &nbsp; Z 　 　 <br>91 &nbsp; 5B &nbsp; [ 　 　 <br>92 &nbsp; 5C &nbsp; \ 　 （&#8217;\\&#8217;） <br>93 &nbsp; 5D &nbsp; ] 　 　 <br>94 &nbsp; 5E &nbsp; ^ 　 　 <br>95 &nbsp; 5F &nbsp; _ 　 　 <br>96 &nbsp; 60 &nbsp; ` 　 　 <br>97 &nbsp; 61 &nbsp; a 　 　 <br>98 &nbsp; 62 &nbsp; b 　 　 <br>99 &nbsp; 63 &nbsp; c 　 　 <br>100 &nbsp; 64 &nbsp; d 　 　 <br>101 &nbsp; 65 &nbsp; e 　 　 <br>102 &nbsp; 66 &nbsp; f 　 　 <br>103 &nbsp; 67 &nbsp; g 　 　 <br>104 &nbsp; 68 &nbsp; h 　 　 <br>105 &nbsp; 69 &nbsp; i 　 　 <br>106 &nbsp; 6A &nbsp; j 　 　 <br>107 &nbsp; 6B &nbsp; k 　 　 <br>108 &nbsp; 6C &nbsp; l 　 　 <br>109 &nbsp; 6D &nbsp; m 　 　 <br>110 &nbsp; 6E &nbsp; n 　 　 <br>111 &nbsp; 6F &nbsp; o 　 　 <br>112 &nbsp; 70 &nbsp; p 　 　 <br>113 &nbsp; 71 &nbsp; q 　 　 <br>114 &nbsp; 72 &nbsp; r 　 　 <br>115 &nbsp; 73 &nbsp; s 　 　 <br>116 &nbsp; 74 &nbsp; t 　 　 <br>117 &nbsp; 75 &nbsp; u 　 　 <br>118 &nbsp; 76 &nbsp; v 　 　 <br>119 &nbsp; 77 &nbsp; w 　 　 <br>120 &nbsp; 78 &nbsp; x 　 　 <br>121 &nbsp; 79 &nbsp; y 　 　 <br>122 &nbsp; 7A &nbsp; z 　 　 <br>123 &nbsp; 7B &nbsp; { 　 　 <br>124 &nbsp; 7C &nbsp; | 　 　 <br>125 &nbsp; 7D &nbsp; } 　 　 <br>126 &nbsp; 7E &nbsp; ~ 　 　 <br>127 &nbsp; 7F &nbsp; 　 DEL <br><br><br>GB2312 字符集<br><br>GB2312又称为GB2312-80字符集，全称为《信息交换用汉字编码字符集&#183;基本集》，由原中国国家标准总局发布，1981年5月1日实施，是中国国家标准的简体中文字符集。它所收录的汉字已经覆盖99.75%的使用频率，基本满足了汉字的计算机处理需要。在中国大陆和新加坡获广泛使用。<br><br>GB2312收录简化汉字及一般符号、序号、数字、拉丁字母、日文假名、希腊字母、俄文字母、汉语拼音符号、汉语注音字母，共 7445 个图形字符。其中包括6763个汉字，其中一级汉字3755个，二级汉字3008个；包括拉丁字母、希腊字母、日文平假名及片假名字母、俄语西里尔字母在内的682个全角字符。 <br><br>GB2312中对所收汉字进行了&#8220;分区&#8221;处理，每区含有94个汉字/符号。这种表示方式也称为区位码。<br><br>它是用双字节表示的，两个字节中前面的字节为第一字节，后面的字节为第二字节。习惯上称第一字节为&#8220;高字节&#8221; ，而称第二字节为&#8220;低字节&#8221;。&#8220;高位字节&#8221;使用了0xA1-0xF7(把01-87区的区号加上0xA0)，&#8220;低位字节&#8221;使用了0xA1-0xFE(把01-94加上0xA0)。<br><br>以GB2312字符集的第一个汉字&#8220;啊&#8221;字为例，它的区号16，位号01，则区位码是1601，在大多数计算机程序中，高字节和低字节分别加0xA0得到程序的汉字处理编码0xB0A1。计算公式是：0xB0=0xA0+16, 0xA1=0xA0+1。<br><br>GBK字符集<br>GBK字符集是GB2312的扩展(K)，GBK1.0收录了21886个符号，它分为汉字区和图形符号区，汉字区包括21003个字符。GBK字符集主要扩展了繁体中文字的支持。<br><br><br>BIG5 字符集<br><br>BIG5又称大五码或五大码，1984年由台湾财团法人信息工业策进会和五间软件公司宏碁 (Acer)、神通 (MiTAC)、佳佳、零壹 (Zero One)、大众 (FIC)创立，故称大五码。Big5码的产生，是因为当时台湾不同厂商各自推出不同的编码，如倚天码、IBM PS55、王安码等，彼此不能兼容；另一方面，台湾政府当时尚未推出官方的汉字编码，而中国大陆的GB2312编码亦未有收录繁体中文字。<br><br>Big5字符集共收录13,053个中文字，该字符集在中国台湾使用。耐人寻味的是该字符集重复地收录了两个相同的字：&#8220;兀&#8221;(0xA461及0xC94A)、&#8220;嗀&#8221;(0xDCD1及0xDDFC)。<br><br>Big5码使用了双字节储存方法，以两个字节来编码一个字。第一个字节称为&#8220;高位字节&#8221;，第二个字节称为&#8220;低位字节&#8221;。高位字节的编码范围0xA1-0xF9，低位字节的编码范围0x40-0x7E及0xA1-0xFE。<br><br>尽管Big5码内包含一万多个字符，但是没有考虑社会上流通的人名、地名用字、方言用字、化学及生物科等用字，没有包含日文平假名及片假字母。<br><br>例如台湾视&#8220;着&#8221;为&#8220;著&#8221;的异体字，故没有收录&#8220;着&#8221;字。康熙字典中的一些部首用字(如&#8220;亠&#8221;、&#8220;疒&#8221;、&#8220;辵&#8221;、&#8220;癶&#8221;等)、常见的人名用字(如&#8220;堃&#8221;、&#8220;煊&#8221;、&#8220;栢&#8221;、&#8220;喆&#8221;等) 也没有收录到Big5之中。<br><br><br>GB18030 字符集<br><br>GB18030的全称是GB18030-2000《信息交换用汉字编码字符集基本集的扩充》，是我国政府于2000年3月17日发布的新的汉字编码国家标准，2001年8月31日后在中国市场上发布的软件必须符合本标准。GB 18030字符集标准的出台经过广泛参与和论证，来自国内外知名信息技术行业的公司，信息产业部和原国家质量技术监督局联合实施。<br><br>GB 18030字符集标准解决汉字、日文假名、朝鲜语和中国少数民族文字组成的大字符集计算机编码问题。该标准的字符总编码空间超过150万个编码位，收录了27484个汉字，覆盖中文、日文、朝鲜语和中国少数民族文字。满足中国大陆、香港、台湾、日本和韩国等东亚地区信息交换多文种、大字量、多用途、统一编码格式的要求。并且与Unicode 3.0版本兼容，填补Unicode扩展字符字汇&#8220;统一汉字扩展A&#8221;的内容。并且与以前的国家字符编码标准（GB2312，GB13000.1）兼容。<br><br>编码方法：<br>GB 18030标准采用单字节、双字节和四字节三种方式对字符编码。单字节部分使用0&#215;00至0&#215;7F码(对应于ASCII码的相应码)。双字节部分，首字节码从0&#215;81至0&#215;FE，尾字节码位分别是0&#215;40至0&#215;7E和0&#215;80至0&#215;FE。四字节部分采用GB/T 11383未采用的0&#215;30到0&#215;39作为对双字节编码扩充的后缀，这样扩充的四字节编码，其范围为0&#215;81308130到0&#215;FE39FE39。其中第一、三个字节编码码位均为0&#215;81至0&#215;FE，第二、四个字节编码码位均为0&#215;30至0&#215;39。<br><br>按照程序员的称呼，GB2312、GBK到GB18030都属于双字节字符集 (DBCS)。<br><br>接着是国际通用的unicode字符集<br><br>Unicode字符集（简称为UCS）<br><br>1．名称的由来<br><br>Unicode字符集编码是（Universal Multiple-Octet Coded Character Set） 通用多八位编码字符集的简称，支持世界上超过650种语言的国际字符集。Unicode允许在同一服务器上混合使用不同语言组的不同语言。它是由一个名为 Unicode 学术学会(Unicode Consortium)的机构制订的字符编码系统，支持现今世界各种不同语言的书面文本的交换、处理及显示。该编码于1990年开始研发，1994年正式公布，最新版本是2005年3月31日的Unicode 4.1.0。Unicode是一种在计算机上使用的字符编码。它为每种语言中的每个字符设定了统一并且唯一的二进制编码，以满足跨语言、跨平台进行文本转换、处理的要求。<br><br>2．编码方法<br><br>Unicode 标准始终使用十六进制数字，而且在书写时在前面加上前缀&#8220;U+&#8221;，例如字母&#8220;A&#8221;的编码为 004116 。所以&#8220;A&#8221;的编码书写为&#8220;U+0041&#8221;。<br><br>3．UTF-8 编码<br>UTF-8是Unicode的其中一个使用方式。 UTF是 Unicode Translation Format，即把Unicode转做某种格式的意思。<br><br>UTF-8便于不同的计算机之间使用网络传输不同语言和编码的文字，使得双字节的Unicode能够在现存的处理单字节的系统上正确传输。<br><br>UTF-8使用可变长度字节来储存 Unicode字符，例如ASCII字母继续使用1字节储存，重音文字、希腊字母或西里尔字母等使用2字节来储存，而常用的汉字就要使用3字节。辅助平面字符则使用4字节。<br><br>4．UTF-16 和 UTF-32 编码<br>UTF-32、UTF-16 和 UTF-8 是 Unicode 标准的编码字符集的字符编码方案，UTF-16 使用一个或两个未分配的 16 位代码单元的序列对 Unicode 代码点进行编码；UTF-32 即将每一个 Unicode 代码点表示为相同值的 32 位整数<br><br>通过一个问题了解unicode编码<br><br>问题：使用Windows记事本的&#8220;另存为&#8221;，可以在ANSI、GBK、Unicode、Unicode big endian和UTF-8这几种编码方式间相互转换。同样是txt文件，Windows怎样识别编码方式的呢？<br>我很早前就发现Unicode、Unicode big endian和UTF-8编码的txt文件的开头会多出几个字节，分别是FF、FE（Unicode）,FE、FF（Unicode big endian）,EF、BB、BF（UTF-8）。但这些标记是基于什么标准呢？<br><br>答案：<br><br>ANSI字符集定义：ASCII字符集，以及由此派生并兼容的字符集，如：GB2312，正式的名称为MBCS(Multi-Byte Chactacter System，多字节字符系统)，通常也称为ANSI字符集。 <br><br>UNICODE 与 UTF8、UTF16 <br><br>由于每种语言都制定了自己的字符集，导致最后存在的各种字符集实在太多，在国际交流中要经常转换字符集非常不便。因此，产生了Unicode字符集，它固定使用16 bits(两个字节)来表示一个字符，共可以表示65536个字符 <br>标准的 Unicode 称为UTF-16(UTF:UCS Transformation Format )。后来为了双字节的Unicode能够在现存的处理单字节的系统上正确传输，出现了UTF-8，使用类似MBCS的方式对Unicode进行编码。(Unicode字符集有多种编码形式) <br>例如"连通"两个字的Unicode标准编码UTF-16 (big endian)为：DE 8F 1A 90 <br>而其UTF-8编码为：E8 BF 9E E9 80 9A <br><br>当一个软件打开一个文本时，它要做的第一件事是决定这个文本究竟是使用哪种字符集的哪种编码保存的。软件一般采用三种方式来决定文本的字符集和编码： <br>检测文件头标识，提示用户选择，根据一定的规则猜测 <br>最标准的途径是检测文本最开头的几个字节，开头字节 Charset/encoding,如下表： <br>EF BB BF &nbsp; &nbsp; UTF-8 <br>FE FF &nbsp; &nbsp; &nbsp; UTF-16/UCS-2, little endian <br>FF FE &nbsp; &nbsp; &nbsp; UTF-16/UCS-2, big endian <br>FF FE 00 00 UTF-32/UCS-4, little endian. <br>00 00 FE FF UTF-32/UCS-4, big-endian. <br><br><br>1、big endian和little endian<br>big endian和little endian是CPU处理多字节数的不同方式。例如&#8220;汉&#8221;字的Unicode编码是6C49。那么写到文件里时，究竟是将6C写在前面，还是将49写在前面？如果将6C写在前面，就是big endian。还是将49写在前面，就是little endian。<br>&#8220;endian&#8221;这个词出自《格列佛游记》。小人国的内战就源于吃鸡蛋时是究竟从大头(Big-Endian)敲开还是从小头(Little-Endian)敲开，由此曾发生过六次叛乱，其中一个皇帝送了命，另一个丢了王位。<br>我们一般将endian翻译成&#8220;字节序&#8221;，将big endian和little endian称作&#8220;大尾&#8221;和&#8220;小尾&#8221;。<br><br>2、字符编码、内码，顺带介绍汉字编码<br>字符必须编码后才能被计算机处理。计算机使用的缺省编码方式就是计算机的内码。早期的计算机使用7位的ASCII编码，为了处理汉字，程序员设计了用于简体中文的GB2312和用于繁体中文的big5。<br>GB2312(1980年)一共收录了7445个字符，包括6763个汉字和682个其它符号。汉字区的内码范围高字节从B0-F7，低字节从A1-FE，占用的码位是72*94=6768。其中有5个空位是D7FA-D7FE。<br>GB2312支持的汉字太少。1995年的汉字扩展规范GBK1.0收录了21886个符号，它分为汉字区和图形符号区。汉字区包括21003个字符。2000年的GB18030是取代GBK1.0的正式国家标准。该标准收录了27484个汉字，同时还收录了藏文、蒙文、维吾尔文等主要的少数民族文字。现在的PC平台必须支持GB18030，对嵌入式产品暂不作要求。所以手机、MP3一般只支持GB2312。<br>从ASCII、GB2312、GBK到GB18030，这些编码方法是向下兼容的，即同一个字符在这些方案中总是有相同的编码，后面的标准支持更多的字符。在这些编码中，英文和中文可以统一地处理。区分中文编码的方法是高字节的最高位不为0。按照程序员的称呼，GB2312、GBK到GB18030都属于双字节字符集 (DBCS)。<br>有的中文Windows的缺省内码还是GBK，可以通过GB18030升级包升级到GB18030。不过GB18030相对GBK增加的字符，普通人是很难用到的，通常我们还是用GBK指代中文Windows内码。<br>这里还有一些细节：<br>GB2312的原文还是区位码，从区位码到内码，需要在高字节和低字节上分别加上A0。<br>在DBCS中，GB内码的存储格式始终是big endian，即高位在前。<br>GB2312的两个字节的最高位都是1。但符合这个条件的码位只有128*128=16384个。所以GBK和GB18030的低字节最高位都可能不是1。不过这不影响DBCS字符流的解析：在读取DBCS字符流时，只要遇到高位为1的字节，就可以将下两个字节作为一个双字节编码，而不用管低字节的高位是什么。<br><br>3、Unicode、UCS和UTF(UCS Transformation Format)<br>前面提到从ASCII、GB2312、GBK到GB18030的编码方法是向下兼容的。而Unicode只与ASCII兼容（更准确地说，是与ISO-8859-1兼容），与GB码不兼容。例如&#8220;汉&#8221;字的Unicode编码是6C49，而GB码是BABA。<br><br>UCS规定了怎么用多个字节表示各种文字。而怎样传输这些编码，是由UTF(UCS Transformation Format)规范规定的！常见的UTF规范包括UTF-8、UTF-7、UTF-16。<br><br>4、UTF的字节序和BOM<br>UTF-8以字节为编码单元，没有字节序的问题。UTF-16以两个字节为编码单元，在解释一个UTF-16文本前，首先要弄清楚每个编码单元的字节序。例如收到一个&#8220;奎&#8221;的Unicode编码是594E，&#8220;乙&#8221;的Unicode编码是4E59。如果我们收到UTF-16字节流&#8220;594E&#8221;，那么这是&#8220;奎&#8221;还是&#8220;乙&#8221;？<br>Unicode规范中推荐的标记字节顺序的方法是BOM。BOM不是&#8220;Bill Of Material&#8221;的BOM表，而是Byte Order Mark。BOM是一个有点小聪明的想法：<br>在UCS编码中有一个叫做"ZERO WIDTH NO-BREAK SPACE"的字符，它的编码是FEFF。而FFFE在UCS中是不存在的字符，所以不应该出现在实际传输中。UCS规范建议我们在传输字节流前，先传输字符"ZERO WIDTH NO-BREAK SPACE"。<br>这样如果接收者收到FEFF，就表明这个字节流是Big-Endian的；如果收到FFFE，就表明这个字节流是Little-Endian的。因此字符"ZERO WIDTH NO-BREAK SPACE"又被称作BOM。<br>UTF-8不需要BOM来表明字节顺序，但可以用BOM来表明编码方式。字符"ZERO WIDTH NO-BREAK SPACE"的UTF-8编码是EF BB BF（读者可以用我们前面介绍的编码方法验证一下）。所以如果接收者收到以EF BB BF开头的字节流，就知道这是UTF-8编码了。<br>Windows就是使用BOM来标记文本文件的编码方式的。<br><br><br>写到这里对编码有了大致的了解了，就可以理解网上一些文章的话了，比如有一篇很流行的文章《URL编码与SQL注射》里面有一段是这么说的：<br><br>其实url编码就是一个字符ascii码的十六进制。不过稍微有些变动，需要在前面加上&#8220;%&#8221;。比如&#8220;\&#8221;，它的ascii码是92，92的十六进制是5c，所以&#8220;\&#8221;的url编码就是%5c。那么汉字的url编码呢？很简单，看例子：&#8220;胡&#8221;的ascii码是-17670，十六进制是BAFA，url编码是&#8220;%BA%FA&#8221;。呵呵，知道怎么转换的了吧。<br><br><br>&nbsp; 这得从ASCII说起，扩展的ASCII字符集采用8bit255个字符显然不够用，于是各个国家纷纷制定了自己的文字编码规范，其中中文的文字编码规范叫做&#8220;GB2312-80&#8221;（就是GB2312)，它是和ASCII兼容的一种编码规范，其实就是用扩展ASCII没有真正标准化这一点，把一个中文字符用两个扩展ASCII字符来表示。文中说的的中文ASCII码实际上就是简体中文的编码2312GB！它把ASCII又扩充了一个字节，由于高位的第一位是0，所以会出现负数的形式，url编码就是将汉字的这个GB2312编码转化成UTF-8的编码并且每8位即一个字节前面加上%符号表示。<br><br>那为何UTF-8是进行网络的规范传输编码呢？<br><br>在Unicode里，所有的字符被一视同仁。汉字不再使用&#8220;两个扩展ASCII&#8221;，而是使用&#8220;1个Unicode&#8221;，注意，现在的汉字是&#8220;一个字符&#8221;了，于是，拆字、统计字数这些问题也就自然而然的解决了。但是，这个世界不是理想的，不可能在一夜之间所有的系统都使用Unicode来处理字符，所以Unicode在诞生之日，就必须考虑一个严峻的问题：和ASCII字符集之间的不兼容问题。 <br><br>我们知道，ASCII字符是单个字节的，比如&#8220;A&#8221;的ASCII是65。而Unicode是双字节的，比如&#8220;A&#8221;的Unicode是0065，这就造成了一个非常大的问题：以前处理ASCII的那套机制不能被用来处理Unicode了 <br><br>另一个更加严重的问题是，C语言使用'\0'作为字符串结尾，而Unicode里恰恰有很多字符都有一个字节为0，这样一来，C语言的字符串函数将无法正常处理Unicode，除非把世界上所有用C写的程序以及他们所用的函数库全部换掉 <br><br>于是，比Unicode更伟大的东东诞生了，之所以说它更伟大是因为它让Unicode不再存在于纸上，而是真实的存在于我们大家的电脑中。那就是：UTF <br><br>UTF= UCS Transformation Format UCS转换格式，它是将Unicode编码规则和计算机的实际编码对应起来的一个规则。现在流行的UTF有2种：UTF-8和UTF-16 <br><br>其中UTF-16和上面提到的Unicode本身的编码规范是一致的，这里不多说了。而UTF-8不同，它定义了一种&#8220;区间规则&#8221;，这种规则可以和ASCII编码保持最大程度的兼容，这样做的好处是压缩了字符在西欧一些国家的内存消耗，减少了不必要的资源浪费，这在实际应用中是非常有必要的。 <br><br>UTF-8有点类似于Haffman编码，它将Unicode编码为：<br>00000000-0000007F的字符，用单个字节来表示； <br><br>00000080-000007FF的字符用两个字节表示 （中文的编码范围）<br><br>00000800-0000FFFF的字符用3字节表示 <br><br>因为目前为止Unicode-16规范没有指定FFFF以上的字符，所以UTF-8最多是使用3个字节来表示一个字符。但理论上来说，UTF-8最多需要用6字节表示一个字符。 <br><br>在UTF-8里，英文字符仍然跟ASCII编码一样，因此原先的函数库可以继续使用。而中文的编码范围是在0080-07FF之间，因此是2个字节表示（但这两个字节和GB编码的两个字节是不同的）。<br><br><br>看看编码之多：ANSI,AscII,GB2312,GBK,BIG5,GB18030,Unicode,UCS（就是unicode）Utf-8,utf-16,utf-32 整整10种编码～，算是够复杂了<br>可是这还仅仅是个开始，应用方面变化无穷，不过现在看到这些东西起码再不会头大了！呼呼～<br><br><br>哦，漏了一个加密的base64编码。<br><br>什么是Base64？ <br><br>按照RFC2045的定义，Base64被定义为：Base64内容传送编码被设计用来把任意序列的8位字节描述为一种不易被人直接识别的形式。（The Base64 Content-Transfer-Encoding is designed to represent arbitrary sequences of octets in a form that need not be humanly readable.） <br><br>为什么要使用Base64？<br><br>在设计这个编码的时候，我想设计人员最主要考虑了3个问题： <br>1.是否加密？ <br>2.加密算法复杂程度和效率 <br>3.如何处理传输？ <br><br>&nbsp; 加密是肯定的，但是加密的目的不是让用户发送非常安全的Email。这种加密方式主要就是&#8220;防君子不防小人&#8221;。即达到一眼望去完全看不出内容即可。 <br>基于这个目的加密算法的复杂程度和效率也就不能太大和太低。和上一个理由类似，MIME协议等用于发送Email的协议解决的是如何收发Email，而并不是如何安全的收发Email。因此算法的复杂程度要小，效率要高，否则因为发送Email而大量占用资源，路就有点走歪了。 <br><br>&nbsp; 但是，如果是基于以上两点，那么我们使用最简单的恺撒法即可，为什么Base64看起来要比恺撒法复杂呢？这是因为在Email的传送过程中，由于历史原因，Email只被允许传送ASCII字符，即一个8位字节的低7位。因此，如果您发送了一封带有非ASCII字符（即字节的最高位是1）的Email通过有&#8220;历史问题&#8221;的网关时就可能会出现问题。网关可能会把最高位置为0！很明显，问题就这样产生了！因此，为了能够正常的传送Email，这个问题就必须考虑！所以，单单靠改变字母的位置的恺撒之类的方案也就不行了。关于这一点可以参考RFC2046。 <br>基于以上的一些主要原因产生了Base64编码。</font><br><strong></strong>
<img src ="http://www.blogjava.net/19851985lili/aggbug/108100.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/19851985lili/" target="_blank">☜♥☞MengChuChen</a> 2007-04-03 08:33 <a href="http://www.blogjava.net/19851985lili/articles/108100.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JDK5.0的11个主要新特征 </title><link>http://www.blogjava.net/19851985lili/articles/97640.html</link><dc:creator>☜♥☞MengChuChen</dc:creator><author>☜♥☞MengChuChen</author><pubDate>Fri, 02 Feb 2007 12:29:00 GMT</pubDate><guid>http://www.blogjava.net/19851985lili/articles/97640.html</guid><wfw:comment>http://www.blogjava.net/19851985lili/comments/97640.html</wfw:comment><comments>http://www.blogjava.net/19851985lili/articles/97640.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/19851985lili/comments/commentRss/97640.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/19851985lili/services/trackbacks/97640.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: JDK 5.0的11个主要新特征 1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 泛型 (Generic)1.1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 说明 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 增强了 java 的类...&nbsp;&nbsp;<a href='http://www.blogjava.net/19851985lili/articles/97640.html'>阅读全文</a><img src ="http://www.blogjava.net/19851985lili/aggbug/97640.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/19851985lili/" target="_blank">☜♥☞MengChuChen</a> 2007-02-02 20:29 <a href="http://www.blogjava.net/19851985lili/articles/97640.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JPCAP——JAVA中的数据链路层控制</title><link>http://www.blogjava.net/19851985lili/articles/97623.html</link><dc:creator>☜♥☞MengChuChen</dc:creator><author>☜♥☞MengChuChen</author><pubDate>Fri, 02 Feb 2007 11:46:00 GMT</pubDate><guid>http://www.blogjava.net/19851985lili/articles/97623.html</guid><wfw:comment>http://www.blogjava.net/19851985lili/comments/97623.html</wfw:comment><comments>http://www.blogjava.net/19851985lili/articles/97623.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/19851985lili/comments/commentRss/97623.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/19851985lili/services/trackbacks/97623.html</trackback:ping><description><![CDATA[
		<div>
				<strong>一．</strong>
				<strong>JPCAP</strong>
				<strong>简介</strong>
		</div>
		<div>众所周知，JAVA语言虽然在TCP/UDP传输方面给予了良好的定义，但对于网络层以下的控制，却是无能为力的。JPCAP扩展包弥补了这一点。</div>
		<div>JPCAP实际上并非一个真正去实现对数据链路层的控制，而是一个中间件，JPCAP调用wincap/libpcap，而给JAVA语言提供一个公共的接口，从而实现了平台无关性。在官方网站上声明，JPCAP支持FreeBSD 3.x, Linux RedHat 6.1, Fedora Core 4, Solaris, and Microsoft Windows 2000/XP等系统。</div>
		<div>
				<strong>二．</strong>
				<strong>JPCAP</strong>
				<strong>机制</strong>
		</div>
		<div>
				<span>       JPCAP</span>的整个结构大体上跟wincap/libpcap是很相像的，例如NetworkInterface类对应wincap<span>的</span><span>typedef struct _ADAPTER  ADAPTER</span><span>，</span><span>getDeviceList()</span><span>对应</span>pcap_findalldevs()等等。<span> JPCAP有16个类，下面就其中最重要的4个类做说明。</span></div>
		<div>
				<strong>
				</strong> </div>
		<div>
				<strong>
						<span>1．</span>
				</strong>
				<strong>NetworkInterface</strong>
		</div>
		<div>该类的每一个实例代表一个网络设备，一般就是网卡。这个类只有一些数据成员，除了继承自java.lang.Object的基本方法以外，没有定义其它方法。</div>
		<div>
				<strong>
				</strong> </div>
		<table style="WIDTH: 100%" cellspacing="0" cellpadding="0" width="100%" border="1">
				<tbody>
						<tr>
								<td style="BORDER-RIGHT: #aca899 1pt inset; PADDING-RIGHT: 2.25pt; BORDER-TOP: 1pt inset; PADDING-LEFT: 2.25pt; BACKGROUND: white; PADDING-BOTTOM: 2.25pt; BORDER-LEFT: 1pt inset; WIDTH: 100%; PADDING-TOP: 2.25pt; BORDER-BOTTOM: 1pt inset" width="100%" colspan="2">
										<div>
												<strong>
														<span>数据成员</span>
												</strong>
										</div>
								</td>
						</tr>
						<tr>
								<td style="PADDING-RIGHT: 2.25pt; PADDING-LEFT: 2.25pt; BACKGROUND: white; PADDING-BOTTOM: 2.25pt; WIDTH: 28.12%; PADDING-TOP: 2.25pt" valign="top" width="28%">
										<div align="right">
												<span>NetworkInterfaceAddress[]</span>
										</div>
								</td>
								<td style="PADDING-RIGHT: 2.25pt; PADDING-LEFT: 2.25pt; BACKGROUND: white; PADDING-BOTTOM: 2.25pt; WIDTH: 71.88%; PADDING-TOP: 2.25pt" width="71%">
										<div align="left">
												<strong>
														<span>addresses</span>
												</strong>
										</div>
										<div align="left">
												<span>    </span>
												<span>这个接口的网络地址。设定为数组应该是考虑到有些设备同时连接多条线路，例如路由器。但我们的PC机的网卡一般只有一条线路，所以我们一般取addresses[0]就够了。</span>
										</div>
								</td>
						</tr>
						<tr>
								<td style="PADDING-RIGHT: 2.25pt; PADDING-LEFT: 2.25pt; BACKGROUND: white; PADDING-BOTTOM: 2.25pt; WIDTH: 28.12%; PADDING-TOP: 2.25pt" valign="top" width="28%">
										<div align="right">
												<span> java.lang.String</span>
										</div>
								</td>
								<td style="PADDING-RIGHT: 2.25pt; PADDING-LEFT: 2.25pt; BACKGROUND: white; PADDING-BOTTOM: 2.25pt; WIDTH: 71.88%; PADDING-TOP: 2.25pt" width="71%">
										<div align="left">
												<strong>
														<span>datalink_description</span>
												</strong>
												<span>.</span>
										</div>
										<div align="left">
												<span>    </span>
												<span>数据链路层的描述。描述所在的局域网是什么网。例如，以太网（Ethernet）、无线LAN网（wireless LAN）、令牌环网(token ring)等等。</span>
										</div>
								</td>
						</tr>
						<tr>
								<td style="PADDING-RIGHT: 2.25pt; PADDING-LEFT: 2.25pt; BACKGROUND: white; PADDING-BOTTOM: 2.25pt; WIDTH: 28.12%; PADDING-TOP: 2.25pt" valign="top" width="28%">
										<div align="right">
												<span> java.lang.String</span>
										</div>
								</td>
								<td style="PADDING-RIGHT: 2.25pt; PADDING-LEFT: 2.25pt; BACKGROUND: white; PADDING-BOTTOM: 2.25pt; WIDTH: 71.88%; PADDING-TOP: 2.25pt" width="71%">
										<div align="left">
												<strong>
														<span>datalink_name </span>
												</strong>
										</div>
										<div align="left">
												<span>   </span>
												<span>该网络设备所对应数据链路层的名称。具体来说，例如Ethernet10M、<span>100M、1000M等等。</span></span>
										</div>
								</td>
						</tr>
						<tr>
								<td style="PADDING-RIGHT: 2.25pt; PADDING-LEFT: 2.25pt; BACKGROUND: white; PADDING-BOTTOM: 2.25pt; WIDTH: 28.12%; PADDING-TOP: 2.25pt" valign="top" width="28%">
										<div align="right">
												<span> java.lang.String</span>
										</div>
								</td>
								<td style="PADDING-RIGHT: 2.25pt; PADDING-LEFT: 2.25pt; BACKGROUND: white; PADDING-BOTTOM: 2.25pt; WIDTH: 71.88%; PADDING-TOP: 2.25pt" width="71%">
										<div align="left">
												<strong>
														<span>description</span>
												</strong>
										</div>
										<div align="left">
												<span>   </span>
												<span>网卡是XXXX牌子XXXX型号之类的描述。例如我的网卡描述：Realtek RTL8169/8110 Family Gigabit Ethernet NIC </span>
										</div>
								</td>
						</tr>
						<tr>
								<td style="PADDING-RIGHT: 2.25pt; PADDING-LEFT: 2.25pt; BACKGROUND: white; PADDING-BOTTOM: 2.25pt; WIDTH: 28.12%; PADDING-TOP: 2.25pt" valign="top" width="28%">
										<div align="right">
												<span> boolean</span>
										</div>
								</td>
								<td style="PADDING-RIGHT: 2.25pt; PADDING-LEFT: 2.25pt; BACKGROUND: white; PADDING-BOTTOM: 2.25pt; WIDTH: 71.88%; PADDING-TOP: 2.25pt" width="71%">
										<div align="left">
												<strong>
														<span>Loopback</span>
												</strong>
										</div>
										<div align="left">
												<span>    </span>
												<span>标志这个设备是否loopback设备。</span>
										</div>
								</td>
						</tr>
						<tr>
								<td style="PADDING-RIGHT: 2.25pt; PADDING-LEFT: 2.25pt; BACKGROUND: white; PADDING-BOTTOM: 2.25pt; WIDTH: 28.12%; PADDING-TOP: 2.25pt" valign="top" width="28%">
										<div align="right">
												<span> byte[]</span>
										</div>
								</td>
								<td style="PADDING-RIGHT: 2.25pt; PADDING-LEFT: 2.25pt; BACKGROUND: white; PADDING-BOTTOM: 2.25pt; WIDTH: 71.88%; PADDING-TOP: 2.25pt" width="71%">
										<div align="left">
												<strong>
														<span>mac_address</span>
												</strong>
										</div>
										<div align="left">
												<span>   </span>
												<span>网卡的MAC地址，6个字节。</span>
										</div>
								</td>
						</tr>
						<tr>
								<td style="PADDING-RIGHT: 2.25pt; PADDING-LEFT: 2.25pt; BACKGROUND: white; PADDING-BOTTOM: 2.25pt; WIDTH: 28.12%; PADDING-TOP: 2.25pt" valign="top" width="28%">
										<div align="right">
												<span> java.lang.String</span>
										</div>
								</td>
								<td style="PADDING-RIGHT: 2.25pt; PADDING-LEFT: 2.25pt; BACKGROUND: white; PADDING-BOTTOM: 2.25pt; WIDTH: 71.88%; PADDING-TOP: 2.25pt" width="71%">
										<div align="left">
												<strong>
														<span>Name</span>
												</strong>
										</div>
										<div align="left">
												<span>    </span>
												<span>这个设备的名称。例如我的网卡名称：\Device\NPF_{3CE5FDA5-E15D-4F87-B217-255BCB351CD5}</span>
										</div>
								</td>
						</tr>
				</tbody>
		</table>
		<div>
				<strong>
				</strong> </div>
		<div>
				<strong>
						<span>2．</span>
				</strong>
				<strong>JpcapCaptor</strong>
		</div>
		<div>该类提供了一系列静态方法实现一些基本的功能。该类一个实例代表建立了一个与指定设备的链接，可以通过该类的实例来控制设备，例如设定网卡模式、设定过滤关键字等等。</div>
		<div> </div>
		<table style="WIDTH: 100%" cellspacing="0" cellpadding="0" width="100%" border="1">
				<tbody>
						<tr>
								<td style="BORDER-RIGHT: #aca899 1pt inset; PADDING-RIGHT: 2.25pt; BORDER-TOP: 1pt inset; PADDING-LEFT: 2.25pt; BACKGROUND: white; PADDING-BOTTOM: 2.25pt; BORDER-LEFT: 1pt inset; WIDTH: 100%; PADDING-TOP: 2.25pt; BORDER-BOTTOM: 1pt inset" valign="top" width="100%" colspan="2">
										<div>
												<code>
														<strong>
																<span>数据成员</span>
														</strong>
												</code>
										</div>
								</td>
						</tr>
						<tr>
								<td style="PADDING-RIGHT: 2.25pt; PADDING-LEFT: 2.25pt; BACKGROUND: white; PADDING-BOTTOM: 2.25pt; WIDTH: 28.48%; PADDING-TOP: 2.25pt" valign="top" width="28%">
										<div align="right">
												<code>
														<span> int</span>
												</code>
										</div>
								</td>
								<td style="PADDING-RIGHT: 2.25pt; PADDING-LEFT: 2.25pt; BACKGROUND: white; PADDING-BOTTOM: 2.25pt; WIDTH: 71.52%; PADDING-TOP: 2.25pt" width="71%">
										<div>
												<code>
														<strong>
																<span>dropped_packets </span>
														</strong>
												</code>
										</div>
										<div>
												<span style="FONT-SIZE: 9pt">抛弃的包的数目。</span>
										</div>
								</td>
						</tr>
						<tr>
								<td style="PADDING-RIGHT: 2.25pt; PADDING-LEFT: 2.25pt; BACKGROUND: white; PADDING-BOTTOM: 2.25pt; WIDTH: 28.48%; PADDING-TOP: 2.25pt" valign="top" width="28%">
										<div align="right">
												<code>
														<span>protected  int</span>
												</code>
										</div>
								</td>
								<td style="PADDING-RIGHT: 2.25pt; PADDING-LEFT: 2.25pt; BACKGROUND: white; PADDING-BOTTOM: 2.25pt; WIDTH: 71.52%; PADDING-TOP: 2.25pt" width="71%">
										<div>
												<code>
														<strong>
																<span>ID</span>
														</strong>
												</code>
										</div>
										<div>
												<code>
														<strong>
																<span>    </span>
														</strong>
												</code>
												<span>这个数据成员在官方文档中并没有做任何说明，查看</span>
												<span>JPCAP</span>
												<span>源代码可以发现这个</span>
												<span>ID</span>
												<span>实际上在其</span>
												<span>JNI</span>
												<span>的</span>
												<span>C</span>
												<span>代码部分传进来的，这类本身并没有做出定义，所以是供其内部使用的。实际上在对</span>
												<span>JpcapCator</span>
												<span>实例的使用中也没有办法调用此数据成员。</span>
										</div>
								</td>
						</tr>
						<tr>
								<td style="PADDING-RIGHT: 2.25pt; PADDING-LEFT: 2.25pt; BACKGROUND: white; PADDING-BOTTOM: 2.25pt; WIDTH: 28.48%; PADDING-TOP: 2.25pt" valign="top" width="28%">
										<div align="right">
												<code>
														<span>protected static boolean[]</span>
												</code>
										</div>
								</td>
								<td style="PADDING-RIGHT: 2.25pt; PADDING-LEFT: 2.25pt; BACKGROUND: white; PADDING-BOTTOM: 2.25pt; WIDTH: 71.52%; PADDING-TOP: 2.25pt" width="71%">
										<div>
												<code>
														<strong>
																<span>instanciatedFlag</span>
														</strong>
												</code>
										</div>
										<div>
												<span>   </span>
												<span>同样在官方文档中没有做任何说明，估计其为供内部使用。</span>
										</div>
								</td>
						</tr>
						<tr>
								<td style="PADDING-RIGHT: 2.25pt; PADDING-LEFT: 2.25pt; BACKGROUND: white; PADDING-BOTTOM: 2.25pt; WIDTH: 28.48%; PADDING-TOP: 2.25pt" valign="top" width="28%">
										<div align="right">
												<code>
														<span>protected static int</span>
												</code>
										</div>
								</td>
								<td style="PADDING-RIGHT: 2.25pt; PADDING-LEFT: 2.25pt; BACKGROUND: white; PADDING-BOTTOM: 2.25pt; WIDTH: 71.52%; PADDING-TOP: 2.25pt" width="71%">
										<div>
												<code>
														<strong>
																<span>MAX_NUMBER_OF_INSTANCE</span>
														</strong>
												</code>
										</div>
										<div>
												<span style="FONT-SIZE: 9pt">同样在官方文档中没有做任何说明，估计其为供内部使用。</span>
										</div>
								</td>
						</tr>
						<tr>
								<td style="PADDING-RIGHT: 2.25pt; PADDING-LEFT: 2.25pt; BACKGROUND: white; PADDING-BOTTOM: 2.25pt; WIDTH: 28.48%; PADDING-TOP: 2.25pt" valign="top" width="28%">
										<div align="right">
												<code>
														<span>int</span>
												</code>
										</div>
								</td>
								<td style="PADDING-RIGHT: 2.25pt; PADDING-LEFT: 2.25pt; BACKGROUND: white; PADDING-BOTTOM: 2.25pt; WIDTH: 71.52%; PADDING-TOP: 2.25pt" width="71%">
										<div>
												<code>
														<strong>
																<span>received_packets</span>
														</strong>
												</code>
												<span>
														<br />        </span>
												<span>收到的包的数目</span>
										</div>
								</td>
						</tr>
						<tr>
								<td style="BORDER-RIGHT: #aca899 1pt inset; PADDING-RIGHT: 2.25pt; BORDER-TOP: 1pt inset; PADDING-LEFT: 2.25pt; BACKGROUND: white; PADDING-BOTTOM: 2.25pt; BORDER-LEFT: 1pt inset; WIDTH: 100%; PADDING-TOP: 2.25pt; BORDER-BOTTOM: 1pt inset" valign="top" width="100%" colspan="2">
										<div>
												<code>
														<strong>
																<span>方法成员</span>
														</strong>
												</code>
										</div>
								</td>
						</tr>
						<tr>
								<td style="PADDING-RIGHT: 2.25pt; PADDING-LEFT: 2.25pt; BACKGROUND: white; PADDING-BOTTOM: 2.25pt; WIDTH: 28.48%; PADDING-TOP: 2.25pt" valign="top" width="28%">
										<div align="right">
												<code>
														<span>static NetworkInterface[]</span>
												</code>
										</div>
								</td>
								<td style="PADDING-RIGHT: 2.25pt; PADDING-LEFT: 2.25pt; BACKGROUND: white; PADDING-BOTTOM: 2.25pt; WIDTH: 71.52%; PADDING-TOP: 2.25pt" width="71%">
										<div>
												<code>
														<strong>
																<span>getDeviceList</span>
														</strong>
												</code>
												<code>
														<span>()</span>
												</code>
												<span>
														<br />          </span>
												<span>返回一个网络设备列表。</span>
										</div>
								</td>
						</tr>
						<tr>
								<td style="PADDING-RIGHT: 2.25pt; PADDING-LEFT: 2.25pt; BACKGROUND: white; PADDING-BOTTOM: 2.25pt; WIDTH: 28.48%; PADDING-TOP: 2.25pt" valign="top" width="28%">
										<div align="right">
												<code>
														<span>static JpcapCaptor</span>
												</code>
										</div>
								</td>
								<td style="PADDING-RIGHT: 2.25pt; PADDING-LEFT: 2.25pt; BACKGROUND: white; PADDING-BOTTOM: 2.25pt; WIDTH: 71.52%; PADDING-TOP: 2.25pt" width="71%">
										<div>
												<code>
														<strong>
																<span>openDevice</span>
														</strong>
												</code>
												<code>
														<span>(NetworkInterface interface, int snaplen, boolean promisc, int to_ms)</span>
												</code>
												<span>
														<br />         </span>
												<span>创建一个与指定设备的连接并返回该连接。注意，以上两个方法都是静态方法。</span>
										</div>
										<div>
												<span>      Interface</span>
												<span>：要打开连接的设备的实例；</span>
										</div>
										<div>
												<span>      Snaplen</span>
												<span>：这个是比较容易搞混的一个参数。其实这个参数不是限制只能捕捉多少数据包，而是限制每一次收到一个数据包，只提取该数据包中前多少字节；</span>
										</div>
										<div>
												<span>      Promisc</span>
												<span>：设置是否混杂模式。处于混杂模式将接收所有数据包，若之后又调用了包过滤函数</span>
												<span>setFilter()</span>
												<span>将不起任何作用；</span>
										</div>
										<div>
												<span>      To_ms</span>
												<span>：这个参数主要用于</span>
												<span>processPacket()</span>
												<span>方法，指定超时的时间；</span>
										</div>
								</td>
						</tr>
						<tr>
								<td style="PADDING-RIGHT: 2.25pt; PADDING-LEFT: 2.25pt; BACKGROUND: white; PADDING-BOTTOM: 2.25pt; WIDTH: 28.48%; PADDING-TOP: 2.25pt" valign="top" width="28%">
										<div align="right">
												<code>
														<span> void</span>
												</code>
										</div>
								</td>
								<td style="PADDING-RIGHT: 2.25pt; PADDING-LEFT: 2.25pt; BACKGROUND: white; PADDING-BOTTOM: 2.25pt; WIDTH: 71.52%; PADDING-TOP: 2.25pt" width="71%">
										<div>
												<code>
														<strong>
																<span>Close</span>
														</strong>
												</code>()<span><br />          </span><span>关闭调用该方法的设备的连接，相对于</span><span>openDivece()</span><span>打开连接。</span></div>
								</td>
						</tr>
						<tr>
								<td style="PADDING-RIGHT: 2.25pt; PADDING-LEFT: 2.25pt; BACKGROUND: white; PADDING-BOTTOM: 2.25pt; WIDTH: 28.48%; PADDING-TOP: 2.25pt" valign="top" width="28%">
										<div align="right">
												<code>
														<span> JpcapSender</span>
												</code>
										</div>
								</td>
								<td style="PADDING-RIGHT: 2.25pt; PADDING-LEFT: 2.25pt; BACKGROUND: white; PADDING-BOTTOM: 2.25pt; WIDTH: 71.52%; PADDING-TOP: 2.25pt" width="71%">
										<div>
												<code>
														<strong>
																<span>getJpcapSenderInstance</span>
														</strong>
												</code>
												<code>
														<span>()</span>
												</code>
												<span>
														<br />          </span>
												<span>该返回一个</span>
												<span>JpcapSender</span>
												<span>实例，</span>
												<span>JpcapSender</span>
												<span>类是专门用于控制设备的发送数据包的功能的类。</span>
										</div>
								</td>
						</tr>
						<tr>
								<td style="PADDING-RIGHT: 2.25pt; PADDING-LEFT: 2.25pt; BACKGROUND: white; PADDING-BOTTOM: 2.25pt; WIDTH: 28.48%; PADDING-TOP: 2.25pt" valign="top" width="28%">
										<div align="right">
												<code>
														<span> Packet</span>
												</code>
										</div>
								</td>
								<td style="PADDING-RIGHT: 2.25pt; PADDING-LEFT: 2.25pt; BACKGROUND: white; PADDING-BOTTOM: 2.25pt; WIDTH: 71.52%; PADDING-TOP: 2.25pt" width="71%">
										<div>
												<code>
														<strong>
																<span>getPacket</span>
														</strong>
												</code>
												<code>
														<span>()</span>
												</code>
												<span>
														<br />          </span>
												<span>捕捉并返回一个数据包。这是</span>
												<span>JpcapCaptor</span>
												<span>实例中四种捕捉包的方法之一。</span>
										</div>
								</td>
						</tr>
						<tr>
								<td style="PADDING-RIGHT: 2.25pt; PADDING-LEFT: 2.25pt; BACKGROUND: white; PADDING-BOTTOM: 2.25pt; WIDTH: 28.48%; PADDING-TOP: 2.25pt" valign="top" width="28%">
										<div align="right">
												<code>
														<span> int</span>
												</code>
										</div>
								</td>
								<td style="PADDING-RIGHT: 2.25pt; PADDING-LEFT: 2.25pt; BACKGROUND: white; PADDING-BOTTOM: 2.25pt; WIDTH: 71.52%; PADDING-TOP: 2.25pt" width="71%">
										<div>
												<code>
														<strong>
																<span>loopPacket</span>
														</strong>
												</code>
												<code>
														<span>(int count, PacketReceiver handler)</span>
												</code>
												<span>
														<br />          </span>
												<span>捕捉指定数目的数据包，并交由实现了</span>
												<span>PacketReceiver</span>
												<span>接口的类的实例处理，并返回捕捉到的数据包数目。如果</span>
												<span>count</span>
												<span>参数设为－</span>
												<span>1</span>
												<span>，那么无限循环地捕捉数据。</span>
										</div>
										<div>
												<span>      </span>
												<span>这个方法不受超时的影响。还记得</span>
												<span>openDivice()</span>
												<span>中的</span>
												<span>to_ms</span>
												<span>参数么？那个参数对这个方法没有影响，如果没有捕捉到指定数目数据包，那么这个方法将一直阻塞等待。</span>
										</div>
										<div>
												<span style="FONT-SIZE: 9pt">PacketReceiver</span>
												<span>中只有一个抽象方法</span>
												<span>void receive(Packet p)</span>
												<span>。</span>
										</div>
								</td>
						</tr>
						<tr>
								<td style="PADDING-RIGHT: 2.25pt; PADDING-LEFT: 2.25pt; BACKGROUND: white; PADDING-BOTTOM: 2.25pt; WIDTH: 28.48%; PADDING-TOP: 2.25pt" valign="top" width="28%">
										<div align="right">
												<code>
														<span> int</span>
												</code>
										</div>
								</td>
								<td style="PADDING-RIGHT: 2.25pt; PADDING-LEFT: 2.25pt; BACKGROUND: white; PADDING-BOTTOM: 2.25pt; WIDTH: 71.52%; PADDING-TOP: 2.25pt" width="71%">
										<div>
												<code>
														<strong>
																<span>processPacket</span>
														</strong>
												</code>
												<code>
														<span>(int count, PacketReceiver handler)</span>
												</code>
												<span>
														<br />           </span>
												<span>跟</span>
												<code>
														<strong>
																<span>loopPacket</span>
														</strong>
												</code>
												<code>
														<span>()</span>
												</code>
												<code>
														<span>功能一样，唯一的区别是这个方法受超时的影响，超过指定时间自动返回捕捉到数据包的数目。</span>
												</code>
										</div>
								</td>
						</tr>
						<tr>
								<td style="PADDING-RIGHT: 2.25pt; PADDING-LEFT: 2.25pt; BACKGROUND: white; PADDING-BOTTOM: 2.25pt; WIDTH: 28.48%; PADDING-TOP: 2.25pt" valign="top" width="28%">
										<div align="right">
												<code>
														<span> int</span>
												</code>
										</div>
								</td>
								<td style="PADDING-RIGHT: 2.25pt; PADDING-LEFT: 2.25pt; BACKGROUND: white; PADDING-BOTTOM: 2.25pt; WIDTH: 71.52%; PADDING-TOP: 2.25pt" width="71%">
										<div>
												<code>
														<strong>
																<span>dispatchPacket</span>
														</strong>
												</code>
												<code>
														<span>(int count, PacketReceiver handler)</span>
												</code>
												<span>
														<br />        </span>
												<span>跟</span>
												<code>
														<strong>
																<span>processPacket</span>
														</strong>
												</code>
												<code>
														<span>()</span>
												</code>
												<code>
														<span>功能一样，区别是这个方法可以处于“non-blocking”模式工作，在这种模式下dispatchPacket()可能立即返回，即使没有捕捉到任何数据包。</span>
												</code>
										</div>
								</td>
						</tr>
						<tr>
								<td style="PADDING-RIGHT: 2.25pt; PADDING-LEFT: 2.25pt; BACKGROUND: white; PADDING-BOTTOM: 2.25pt; WIDTH: 28.48%; PADDING-TOP: 2.25pt" valign="top" width="28%">
										<div align="right">
												<code>
														<span> void</span>
												</code>
										</div>
								</td>
								<td style="PADDING-RIGHT: 2.25pt; PADDING-LEFT: 2.25pt; BACKGROUND: white; PADDING-BOTTOM: 2.25pt; WIDTH: 71.52%; PADDING-TOP: 2.25pt" width="71%">
										<div>
												<code>
														<strong>
																<span>setFilter</span>
														</strong>
												</code>
												<code>
														<span>(java.lang.String condition, boolean optimize)</span>
												</code>
												<span>
														<br />          .</span>
												<code>
														<span>condition</span>
												</code>
												<code>
														<span>：</span>
												</code>
												<span>设定要提取的包的关键字。</span>
										</div>
										<div>
												<span>       </span>
												<code>
														<span>Optimize</span>
												</code>
												<code>
														<span>：这个参数在说明文档以及源代码中都没有说明，只是说这个参数如果为真，那么过滤器将处于优化模式。</span>
												</code>
										</div>
								</td>
						</tr>
						<tr>
								<td style="PADDING-RIGHT: 2.25pt; PADDING-LEFT: 2.25pt; BACKGROUND: white; PADDING-BOTTOM: 2.25pt; WIDTH: 28.48%; PADDING-TOP: 2.25pt" valign="top" width="28%">
										<div align="right">
												<code>
														<span> void</span>
												</code>
										</div>
								</td>
								<td style="PADDING-RIGHT: 2.25pt; PADDING-LEFT: 2.25pt; BACKGROUND: white; PADDING-BOTTOM: 2.25pt; WIDTH: 71.52%; PADDING-TOP: 2.25pt" width="71%">
										<div>
												<code>
														<strong>
																<span>setNonBlockingMode</span>
														</strong>
												</code>
												<code>
														<span>(boolean nonblocking)</span>
												</code>
										</div>
										<div>
												<span>     </span>
												<span>如果值为“</span>
												<span>true</span>
												<span>”，那么设定为“</span>
												<span>non-blocking</span>
												<span>”模式。</span>
										</div>
								</td>
						</tr>
						<tr>
								<td style="PADDING-RIGHT: 2.25pt; PADDING-LEFT: 2.25pt; BACKGROUND: white; PADDING-BOTTOM: 2.25pt; WIDTH: 28.48%; PADDING-TOP: 2.25pt" valign="top" width="28%">
										<div align="right">
												<code>
														<span> void</span>
												</code>
										</div>
								</td>
								<td style="PADDING-RIGHT: 2.25pt; PADDING-LEFT: 2.25pt; BACKGROUND: white; PADDING-BOTTOM: 2.25pt; WIDTH: 71.52%; PADDING-TOP: 2.25pt" width="71%">
										<div>
												<code>
														<strong>
																<span>breakLoop</span>
														</strong>
												</code>()</div>
										<div>
												<span>     </span>
												<span>当调用</span>
												<span>processPacket()</span>
												<span>和</span>
												<span>loopPacket()</span>
												<span>后，再调用这个方法可以强制让</span>
												<span>processPacket()</span>
												<span>和</span>
												<span>loopPacket()</span>
												<span>停止。</span>
										</div>
								</td>
						</tr>
				</tbody>
		</table>
		<div>
				<strong>
				</strong> </div>
		<div>
				<strong>
						<span>3．</span>
				</strong>
				<strong>JpcapSender</strong>
		</div>
		<div>该类专门用于控制数据包的发送。</div>
		<div> </div>
		<table style="WIDTH: 100%" cellspacing="0" cellpadding="0" width="100%" border="1">
				<tbody>
						<tr>
								<td style="BORDER-RIGHT: #aca899 1pt inset; PADDING-RIGHT: 2.25pt; BORDER-TOP: 1pt inset; PADDING-LEFT: 2.25pt; BACKGROUND: white; PADDING-BOTTOM: 2.25pt; BORDER-LEFT: 1pt inset; WIDTH: 100%; PADDING-TOP: 2.25pt; BORDER-BOTTOM: 1pt inset" valign="top" width="100%" colspan="2">
										<div>
												<code>
														<strong>
																<span>方法成员</span>
														</strong>
												</code>
										</div>
								</td>
						</tr>
						<tr>
								<td style="PADDING-RIGHT: 2.25pt; PADDING-LEFT: 2.25pt; BACKGROUND: white; PADDING-BOTTOM: 2.25pt; WIDTH: 19.7%; PADDING-TOP: 2.25pt" valign="top" width="19%">
										<div align="right">
												<code>
														<span> void</span>
												</code>
										</div>
								</td>
								<td style="PADDING-RIGHT: 2.25pt; PADDING-LEFT: 2.25pt; BACKGROUND: white; PADDING-BOTTOM: 2.25pt; PADDING-TOP: 2.25pt">
										<div>
												<code>
														<strong>
																<span>close</span>
														</strong>
												</code>
												<code>
														<span>()</span>
												</code>
												<span>
														<br />          </span>
												<span>强制关闭这个连接。</span>
										</div>
								</td>
						</tr>
						<tr>
								<td style="PADDING-RIGHT: 2.25pt; PADDING-LEFT: 2.25pt; BACKGROUND: white; PADDING-BOTTOM: 2.25pt; WIDTH: 19.7%; PADDING-TOP: 2.25pt" valign="top" width="19%">
										<div align="right">
												<code>
														<span>static JpcapSender</span>
												</code>
										</div>
								</td>
								<td style="PADDING-RIGHT: 2.25pt; PADDING-LEFT: 2.25pt; BACKGROUND: white; PADDING-BOTTOM: 2.25pt; PADDING-TOP: 2.25pt">
										<div>
												<code>
														<strong>
																<span>openRawSocket</span>
														</strong>
												</code>
												<code>
														<span>()</span>
												</code>
										</div>
										<div>
												<span>     </span>
												<span>这个方法返回的</span>
												<span>JpcapSender</span>
												<span>实例发送数据包时将自动填写数据链路层头部分。</span>
										</div>
								</td>
						</tr>
						<tr>
								<td style="PADDING-RIGHT: 2.25pt; PADDING-LEFT: 2.25pt; BACKGROUND: white; PADDING-BOTTOM: 2.25pt; WIDTH: 19.7%; PADDING-TOP: 2.25pt" valign="top" width="19%">
										<div align="right">
												<code>
														<span> void</span>
												</code>
										</div>
								</td>
								<td style="PADDING-RIGHT: 2.25pt; PADDING-LEFT: 2.25pt; BACKGROUND: white; PADDING-BOTTOM: 2.25pt; PADDING-TOP: 2.25pt">
										<div>
												<code>
														<strong>
																<span>sendPacket</span>
														</strong>
												</code>
												<code>
														<span>(Packet packet)</span>
												</code>
												<span>
														<br />          JpcapSender</span>
												<span>最重要的功能，发送数据包。需要注意的是，如果调用这个方法的实例是由</span>
												<strong>
														<span>JpcapCaptor</span>
												</strong>
												<span>的</span>
												<code>
														<strong>
																<span>getJpcapSenderInstance</span>
														</strong>
												</code>
												<code>
														<span>()</span>
												</code>
												<code>
														<span>得到的话，需要自己设定数据链路层的头，而如果是由上面的<strong>openRawSocket</strong>()</span>
												</code>
												<span>得到的话，那么无需也不能设置，数据链路层的头部将由系统自动生成。</span>
										</div>
								</td>
						</tr>
				</tbody>
		</table>
		<div>
				<strong>
				</strong> </div>
		<div>
				<strong>
						<span>4．</span>
				</strong>
				<strong>Packet</strong>
		</div>
		<div>这个是所有其它数据包类的父类。Jpcap所支持的数据包有：<br /><span>ARPPacket</span><span>、</span><span>DatalinkPacket</span><span>、</span><span>EthernetPacket</span><span>、</span><span>ICMPPacket</span><span>、</span><span>IPPacket</span><span>、</span><span>TCPPacket</span><span>、</span><span>UDPPacket</span></div>
		<div> </div>
		<div>
				<strong>三．使用JPCAP</strong>
				<strong>实现监听</strong>
		</div>
		<div>
				<span>       <strong>1</strong></span>
				<strong>．监听原理</strong>
		</div>
		<div>
				<span>       </span>在详细说用JPCAP实现网络监听实现前，先简单介绍下监听的原理。</div>
		<div>
				<span>       </span>局域网监听利用的是所谓的“ARP欺骗”技术。在以前曾经一段阶段，局域网的布局是使用总线式（或集线式）结构，要到达监听只需要将网卡设定为混杂模式即可，但现在的局域网络普遍采用的是交换式网络，所以单纯靠混杂模式来达到监听的方法已经不可行了。所以为了达到监听的目的，我们需要“欺骗”路由器、“欺骗”交换机，即“ARP欺骗”技术。</div>
		<div>
				<span>       </span>假设本机为A，监听目标为B。</div>
		<div>首先，伪造一个ARP REPLY包，数据链路层头及ARP内容部分的源MAC地址填入A的MAC地址，而源IP部分填入网关IP，目的地址填入B的MAC、IP，然后将这个包发送给B，而B接收到这个伪造的ARP REPLY包后，由于源IP为网关IP，于是在它的ARP缓存表里刷新了一项，将（网关IP，网关MAC）刷新成（网关IP，A的MAC）。而B要访问外部的网都需要经过网关，这时候这些要经过网关的包就通通流到A的机器上来了。</div>
		<div>接着，再伪造一个ARP REPLY包，数据链路层头及ARP内容部分的源MAC地址填入A的MAC地址，而源IP部分填入B的IP，目的地址填入网关MAC、IP，然后将这个包发给网关，网关接收到这个伪造的ARP REPLY包后，由于源IP为B的IP，于是在它的ARP缓存表里刷新了一项，将（B的IP，B的MAC）刷新成（B的IP，A的MAC）。这时候外部传给B的数据包经过网关时，就通通转发给A。</div>
		<div>这样还只是拦截了B的数据包而已，B并不能上网——解决方法是将接收到的包，除了目的地址部分稍做修改，其它原封不动的再转发出去，这样就达到了监听的目的——在B不知不觉中浏览了B所有的对外数据包。</div>
		<div> </div>
		<div align="center">
				<span>ARP</span>
				<span>数据包解析</span>
		</div>
		<div>
				<span>单元：</span>
				<span>Byte</span>
		</div>
		<table style="BORDER-RIGHT: medium none; BORDER-TOP: medium none; BORDER-LEFT: medium none; BORDER-BOTTOM: medium none; BORDER-COLLAPSE: collapse" cellspacing="0" cellpadding="0" border="1">
				<tbody>
						<tr style="HEIGHT: 22.1pt">
								<td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: windowtext 1pt solid; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 22.1pt" valign="top" colspan="3">
										<div>
												<span>Ethernet</span>
												<span>头部</span>
										</div>
								</td>
								<td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: medium none; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 22.1pt" valign="top" colspan="8">
										<div>
												<span>ARP</span>
												<span>数据部分</span>
										</div>
								</td>
						</tr>
						<tr style="HEIGHT: 22.1pt">
								<td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: windowtext 1pt solid; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 22.1pt" valign="top">
										<div>
												<span>６</span>
										</div>
								</td>
								<td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: medium none; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 22.1pt" valign="top">
										<div>
												<span>６</span>
										</div>
								</td>
								<td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: medium none; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 22.1pt" valign="top">
										<div>
												<span>２</span>
										</div>
								</td>
								<td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: medium none; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 22.1pt" valign="top">
										<div>
												<span>2</span>
										</div>
								</td>
								<td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: medium none; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 22.1pt" valign="top">
										<div>
												<span>2</span>
										</div>
								</td>
								<td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: medium none; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 22.1pt" valign="top">
										<div>
												<span>2</span>
										</div>
								</td>
								<td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: medium none; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 22.1pt" valign="top">
										<div>
												<span>2</span>
										</div>
								</td>
								<td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: medium none; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 22.1pt" valign="top">
										<div>
												<span>４</span>
										</div>
								</td>
								<td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: medium none; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 22.1pt" valign="top">
										<div>
												<span>６</span>
										</div>
								</td>
								<td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: medium none; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 22.1pt" valign="top">
										<div>
												<span>４</span>
										</div>
								</td>
								<td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: medium none; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 22.1pt" valign="top">
										<div>
												<span>６</span>
										</div>
								</td>
						</tr>
						<tr style="HEIGHT: 62.45pt">
								<td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: windowtext 1pt solid; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 62.45pt" valign="top">
										<div>
												<span>目标</span>
												<span>MAC</span>
												<span>地址</span>
										</div>
								</td>
								<td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: medium none; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 62.45pt" valign="top">
										<div>
												<span>源地</span>
												<span>MAC</span>
												<span>地址</span>
										</div>
								</td>
								<td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: medium none; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 62.45pt" valign="top">
										<div>
												<span>类型号</span>
												<span>0x0800:ip</span>
										</div>
										<div>
												<span>0x0806:ARP</span>
										</div>
								</td>
								<td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: medium none; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 62.45pt" valign="top">
										<div>
												<span>局域网类型</span>
										</div>
										<div>
												<span>以太网</span>
												<span>0x0001</span>
										</div>
								</td>
								<td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: medium none; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 62.45pt" valign="top">
										<div>
												<span>网络协议类型</span>
										</div>
										<div>
												<span>IP</span>
												<span>网络</span>
												<span>0x0800</span>
										</div>
								</td>
								<td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: medium none; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 62.45pt" valign="top">
										<div>
												<span>MAC/IP</span>
												<span>地址长度，恒为</span>
												<span>0x06/04</span>
										</div>
								</td>
								<td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: medium none; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 62.45pt" valign="top">
										<div>
												<span>ARP</span>
												<span>包类型</span>
										</div>
										<div>
												<span>REPLY</span>
										</div>
										<div>
												<span>0x0002</span>
										</div>
								</td>
								<td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: medium none; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 62.45pt" valign="top">
										<div>
												<span>ARP</span>
												<span>目标</span>
												<span>IP</span>
												<span>地址</span>
										</div>
								</td>
								<td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: medium none; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 62.45pt" valign="top">
										<div>
												<span>ARP</span>
												<span>目标</span>
												<span>MAC </span>
												<span>地址</span>
										</div>
								</td>
								<td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: medium none; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 62.45pt" valign="top">
										<div>
												<span>ARP</span>
												<span>源</span>
												<span>IP</span>
												<span>地址</span>
										</div>
								</td>
								<td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: medium none; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 62.45pt" valign="top">
										<div>
												<span>ARP</span>
												<span>源</span>
												<span>MAC</span>
												<span>地址</span>
										</div>
								</td>
						</tr>
				</tbody>
		</table>
		<div> </div>
		<div>
				<strong>2</strong>
				<strong>．用JPCAP</strong>
				<strong>实现监听</strong>
		</div>
		<div>
				<span>       </span>就如上面说的，为了实现监听，我们必须做四件事：</div>
		<div>
				<span>A．</span>发送ARP包修改B的ARP缓存表；</div>
		<div>
				<span>B．</span>发送ARP包修改路由ARP缓存表；</div>
		<div>
				<span>C．</span>转发B发过来的数据包；</div>
		<div>
				<span>D．</span>转发路由发过来的数据包；</div>
		<div> </div>
		<div>下面我们给个小小的例子说明怎样实现。</div>
		<div>我们假定运行这个程序的机器A只有一个网卡，只接一个网络，所在局域网为Ethernet，并且假定已经通过某种方式获得B和网关的MAC地址（例如ARP解析获得）。我们修改了B和网关的ARP表，并对他们的包进行了转发。</div>
		<div>
				<span style="FONT-SIZE: 9pt">public class changeARP{</span>
		</div>
		<div>
				<span style="FONT-SIZE: 9pt">         private NetworkInterface[] devices;                           //</span>
				<span>设备列表</span>
		</div>
		<div>
				<span style="FONT-SIZE: 9pt">         private NetworkInterface device;                               //</span>
				<span>要使用的设备</span>
		</div>
		<div>
				<span style="FONT-SIZE: 9pt">         private JpcapCaptor jpcap;                                        //</span>
				<span>与设备的连接</span>
		</div>
		<div>
				<span style="FONT-SIZE: 9pt">         private JpcapSender sender;                                       //</span>
				<span>用于发送的实例</span>
		</div>
		<div>
				<span style="FONT-SIZE: 9pt">         private byte[] targetMAC, gateMAC;                       //B</span>
				<span>的</span>
				<span>MAC</span>
				<span>地址，网关的</span>
				<span>MAC</span>
				<span>地址</span>
		</div>
		<div>
				<span style="FONT-SIZE: 9pt">         private byte[] String targetIp, String gateIp;              //B</span>
				<span>的</span>
				<span>IP</span>
				<span>地址，网关的</span>
				<span>IP</span>
				<span>地址</span>
		</div>
		<div>
				<span style="FONT-SIZE: 9pt">         /**</span>
		</div>
		<div>
				<span style="FONT-SIZE: 9pt">         *</span>
				<span>初始化设备</span>
		</div>
		<div>
				<span style="FONT-SIZE: 9pt">         * JpcapCaptor.getDeviceList()</span>
				<span>得到设备可能会有两个，其中一个必定是“</span>
				<span>Generic </span>
		</div>
		<div>
				<span style="FONT-SIZE: 9pt; COLOR: blue">*<span>dialup adapter</span></span>
				<span>”，</span>
				<span>这是</span>
				<span>windows</span>
				<span>系统的虚拟网卡，并非真正的硬件设备。</span>
		</div>
		<div>
				<span style="FONT-SIZE: 9pt">*</span>
				<span>注意：在这里有一个小小的</span>
				<span>BUG</span>
				<span>，如果</span>
				<span>JpcapCaptor.getDeviceList()</span>
				<span>之前有类似</span>
				<span>JFrame jf=new</span>
		</div>
		<div>
				<span style="FONT-SIZE: 9pt">*JFame</span>
				<span>（）这类的语句会影响得到设备个数，只会得到真正的硬件设备，而不会出现虚拟网卡。</span>
		</div>
		<div>
				<span style="FONT-SIZE: 9pt">*</span>
				<span>虚拟网卡只有</span>
				<span>MAC</span>
				<span>地址而没有</span>
				<span>IP</span>
				<span>地址，而且如果出现虚拟网卡，那么实际网卡的</span>
				<span>MAC</span>
				<span>将分</span>
		</div>
		<div>
				<span style="FONT-SIZE: 9pt">*</span>
				<span>配给虚拟网卡，也就是说在程序中调用</span>
				<span>device.</span>
				<span>mac_address</span>
				<span>时得到的是</span>
				<span>00 00 00 00 00 00</span>
				<span>。</span>
		</div>
		<div>
				<span style="FONT-SIZE: 9pt">         */</span>
		</div>
		<div>
				<span style="FONT-SIZE: 9pt">         private NetworkInterface getDevice() throws IOException {</span>
		</div>
		<div>
				<span style="FONT-SIZE: 9pt">                  devices = JpcapCaptor.getDeviceList();                                                 //</span>
				<span>获得设备列表</span>
		</div>
		<div>
				<span style="FONT-SIZE: 9pt">                   device = devices[0];                                                                                //</span>
				<span>只有一个设备</span>
		</div>
		<div>
				<span style="FONT-SIZE: 9pt">                   jpcap = JpcapCaptor.openDevice(device, 2000, false, 10000);             //</span>
				<span>打开与设备的连接</span>
		</div>
		<div>
				<span style="FONT-SIZE: 9pt">                   jpcap.setFilter(“ip”,true);                                                                       //</span>
				<span>只监听</span>
				<span>B</span>
				<span>的</span>
				<span>IP</span>
				<span>数据包</span>
		</div>
		<div>
				<span style="FONT-SIZE: 9pt">                   sender = captor.getJpcapSenderInstance();</span>
		</div>
		<div>
				<span style="FONT-SIZE: 9pt">         }</span>
		</div>
		<div>
				<span style="FONT-SIZE: 9pt">         /**</span>
		</div>
		<div>
				<span style="FONT-SIZE: 9pt">         *</span>
				<span>修改</span>
				<span>B</span>
				<span>和网关的</span>
				<span>ARP</span>
				<span>表。因为网关会定时发数据包刷新自己和</span>
				<span>B</span>
				<span>的缓存表，所以必须每隔一</span>
		</div>
		<div>
				<span style="FONT-SIZE: 9pt">         *</span>
				<span>段时间就发一次包重新更改</span>
				<span>B</span>
				<span>和网关的</span>
				<span>ARP</span>
				<span>表。</span>
		</div>
		<div>
				<span style="FONT-SIZE: 9pt">         *@</span>
				<span>参数</span>
				<span> targetMAC           B</span>
				<span>的</span>
				<span>MAC</span>
				<span>地址，可通过</span>
				<span>ARP</span>
				<span>解析得到；</span>
		</div>
		<div>
				<span style="FONT-SIZE: 9pt">         *@</span>
				<span>参数</span>
				<span> targetIp                 B</span>
				<span>的</span>
				<span>IP</span>
				<span>地址；</span>
		</div>
		<div>
				<span style="FONT-SIZE: 9pt">         *@</span>
				<span>参数</span>
				<span> gateMAC              </span>
				<span>网关的</span>
				<span>MAC</span>
				<span>地址；</span>
		</div>
		<div>
				<span style="FONT-SIZE: 9pt">         *@</span>
				<span>参数</span>
				<span> gateIp                     </span>
				<span>网关的</span>
				<span>IP;</span>
		</div>
		<div>
				<span style="FONT-SIZE: 9pt">         */</span>
		</div>
		<div>
				<span style="FONT-SIZE: 9pt">         public changeARP(byte[] targetMAC, String targetIp,byte[] gateMAC, String gateIp)</span>
		</div>
		<div>
				<span style="FONT-SIZE: 9pt">                            throws UnknownHostException,InterruptedException {</span>
		</div>
		<div>
				<span style="FONT-SIZE: 9pt">                   this. targetMAC =  targetMAC;</span>
		</div>
		<div>
				<span style="FONT-SIZE: 9pt">                   this. targetIp =  targetIp;</span>
		</div>
		<div>
				<span style="FONT-SIZE: 9pt">                   this. gateMAC = gateMAC;</span>
		</div>
		<div>
				<span style="FONT-SIZE: 9pt">                   this. gateIp = gateIp;</span>
		</div>
		<div>
				<span style="FONT-SIZE: 9pt">                   getDevice();</span>
		</div>
		<div>
				<span style="FONT-SIZE: 9pt">                   arpTarget = new ARPPacket();                                                     //</span>
				<span>修改</span>
				<span>B</span>
				<span>的</span>
				<span>ARP</span>
				<span>表的</span>
				<span>ARP</span>
				<span>包</span>
		</div>
		<div>
				<span style="FONT-SIZE: 9pt">                   arpTarget.hardtype = ARPPacket.HARDTYPE_ETHER;          //</span>
				<span>选择以太网类型</span>
				<span>(Ethernet)</span>
		</div>
		<div>
				<span style="FONT-SIZE: 9pt">                   arpTarget.prototype = ARPPacket.PROTOTYPE_IP;                //</span>
				<span>选择</span>
				<span>IP</span>
				<span>网络协议类型</span>
		</div>
		<div>
				<span style="FONT-SIZE: 9pt">                   arpTarget.operation = ARPPacket.ARP_REPLY;                         //</span>
				<span>选择</span>
				<span>REPLY</span>
				<span>类型</span>
		</div>
		<div>
				<span style="FONT-SIZE: 9pt">                   arpTarget.hlen = 6;                                                                        //MAC</span>
				<span>地址长度固定</span>
				<span>6</span>
				<span>个字节</span>
		</div>
		<div>
				<span style="FONT-SIZE: 9pt">                   arpTarget.plen = 4;                                                                        //IP</span>
				<span>地址长度固定</span>
				<span>4</span>
				<span>个字节</span>
		</div>
		<div>
				<span style="FONT-SIZE: 9pt">                   arpTarget.sender_hardaddr = device.mac_address;                       //A</span>
				<span>的</span>
				<span>MAC</span>
				<span>地址</span>
		</div>
		<div>
				<span style="FONT-SIZE: 9pt">                   arpTarget.sender_protoaddr = InetAddress.getByName(gateIp).getAddress();       //</span>
				<span>网关</span>
				<span>IP</span>
		</div>
		<div>
				<span style="FONT-SIZE: 9pt">                   arpTarget.target_hardaddr = targetMAC;                                               //B</span>
				<span>的</span>
				<span>MAC</span>
				<span>地址</span>
		</div>
		<div>
				<span style="FONT-SIZE: 9pt">    &amp;nbs</span>
		</div>
<img src ="http://www.blogjava.net/19851985lili/aggbug/97623.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/19851985lili/" target="_blank">☜♥☞MengChuChen</a> 2007-02-02 19:46 <a href="http://www.blogjava.net/19851985lili/articles/97623.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>EqualsBuilder和HashCodeBuilder </title><link>http://www.blogjava.net/19851985lili/articles/95448.html</link><dc:creator>☜♥☞MengChuChen</dc:creator><author>☜♥☞MengChuChen</author><pubDate>Tue, 23 Jan 2007 01:07:00 GMT</pubDate><guid>http://www.blogjava.net/19851985lili/articles/95448.html</guid><wfw:comment>http://www.blogjava.net/19851985lili/comments/95448.html</wfw:comment><comments>http://www.blogjava.net/19851985lili/articles/95448.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/19851985lili/comments/commentRss/95448.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/19851985lili/services/trackbacks/95448.html</trackback:ping><description><![CDATA[
		<font size="2">自动化hashCode()和equals()<br />  问题产生：当需要自动实现hashCode()和equals()方法<br />  解决方法：使用<font face="Courier New">EqualsBuilder和</font><tt>HashCodeBuilder</tt></font>
		<a name="jakartackbk-CHP-1-ITERM-1797">
		</a>
		<font size="2">
				<br />  使用举例：<br />  </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">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
						<span style="COLOR: #0000ff">import</span>
				</font>
				<font size="2">
						<span style="COLOR: #000000"> org.apache.commons.lang.builder.HashCodeBuilder;<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /></span>
						<span style="COLOR: #0000ff">import</span>
				</font>
				<font size="2">
						<span style="COLOR: #000000"> org.apache.commons.lang.builder.EqualsBuilder;<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /><br /><img id="Codehighlighter1_143_1005_Open_Image" onclick="this.style.display='none'; Codehighlighter1_143_1005_Open_Text.style.display='none'; Codehighlighter1_143_1005_Closed_Image.style.display='inline'; Codehighlighter1_143_1005_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_143_1005_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_143_1005_Closed_Text.style.display='none'; Codehighlighter1_143_1005_Open_Image.style.display='inline'; Codehighlighter1_143_1005_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span>
						<span style="COLOR: #0000ff">public</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #0000ff">class</span>
						<span style="COLOR: #000000"> PoliticalCandidate </span>
						<span id="Codehighlighter1_143_1005_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" />
						</span>
				</font>
				<span id="Codehighlighter1_143_1005_Open_Text">
						<font size="2">
								<span style="COLOR: #000000">{<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    </span>
								<span style="COLOR: #008000">//</span>
						</font>
						<font size="2">
								<span style="COLOR: #008000"> Member variables - omitted for brevity<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    </span>
								<span style="COLOR: #008000">//</span>
						</font>
						<font size="2">
								<span style="COLOR: #008000"> Constructors - omitted for brevity<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    </span>
								<span style="COLOR: #008000">//</span>
						</font>
						<font size="2">
								<span style="COLOR: #008000"> get/set methods - omitted for brevity<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    </span>
								<span style="COLOR: #008000">//</span>
								<span style="COLOR: #008000"> A hashCode which creates a hash from the two unique identifiers</span>
						</font>
						<span style="COLOR: #008000">
								<br />
								<font size="2">
										<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />
								</font>
						</span>
						<span style="COLOR: #000000">
								<br />
								<font size="2">
										<img id="Codehighlighter1_377_524_Open_Image" onclick="this.style.display='none'; Codehighlighter1_377_524_Open_Text.style.display='none'; Codehighlighter1_377_524_Closed_Image.style.display='inline'; Codehighlighter1_377_524_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" />
										<img id="Codehighlighter1_377_524_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_377_524_Closed_Text.style.display='none'; Codehighlighter1_377_524_Open_Image.style.display='inline'; Codehighlighter1_377_524_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />    </font>
						</span>
						<font size="2">
								<span style="COLOR: #0000ff">public</span>
								<span style="COLOR: #000000"> </span>
								<span style="COLOR: #0000ff">int</span>
								<span style="COLOR: #000000"> hashCode( ) </span>
								<span id="Codehighlighter1_377_524_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" />
								</span>
						</font>
						<span id="Codehighlighter1_377_524_Open_Text">
								<font size="2">
										<span style="COLOR: #000000">{<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />        </span>
										<span style="COLOR: #0000ff">return</span>
										<span style="COLOR: #000000"> </span>
										<span style="COLOR: #0000ff">new</span>
										<span style="COLOR: #000000"> HashCodeBuilder(</span>
										<span style="COLOR: #000000">17</span>
										<span style="COLOR: #000000">, </span>
										<span style="COLOR: #000000">37</span>
								</font>
								<span style="COLOR: #000000">
										<font size="2">)<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />                       .append(firstName)<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />                       .append(lastName).toHashCode( );<br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />    }</font>
								</span>
						</span>
						<span style="COLOR: #000000">
								<br />
								<font size="2">
										<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />
										<br />
										<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    </font>
						</span>
						<font size="2">
								<span style="COLOR: #008000">//</span>
								<span style="COLOR: #008000"> An equals which compares two unique identifiers</span>
						</font>
						<span style="COLOR: #008000">
								<br />
								<font size="2">
										<img id="Codehighlighter1_618_1002_Open_Image" onclick="this.style.display='none'; Codehighlighter1_618_1002_Open_Text.style.display='none'; Codehighlighter1_618_1002_Closed_Image.style.display='inline'; Codehighlighter1_618_1002_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" />
										<img id="Codehighlighter1_618_1002_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_618_1002_Closed_Text.style.display='none'; Codehighlighter1_618_1002_Open_Image.style.display='inline'; Codehighlighter1_618_1002_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />
								</font>
						</span>
						<font size="2">
								<span style="COLOR: #000000">    </span>
								<span style="COLOR: #0000ff">public</span>
								<span style="COLOR: #000000"> </span>
								<span style="COLOR: #0000ff">boolean</span>
								<span style="COLOR: #000000"> equals(Object o) </span>
								<span id="Codehighlighter1_618_1002_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" />
								</span>
						</font>
						<span id="Codehighlighter1_618_1002_Open_Text">
								<font size="2">
										<span style="COLOR: #000000">{<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />        </span>
										<span style="COLOR: #0000ff">boolean</span>
										<span style="COLOR: #000000"> equals </span>
										<span style="COLOR: #000000">=</span>
										<span style="COLOR: #000000"> </span>
										<span style="COLOR: #0000ff">false</span>
								</font>
								<font size="2">
										<span style="COLOR: #000000">;<br /><img id="Codehighlighter1_736_973_Open_Image" onclick="this.style.display='none'; Codehighlighter1_736_973_Open_Text.style.display='none'; Codehighlighter1_736_973_Closed_Image.style.display='inline'; Codehighlighter1_736_973_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_736_973_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_736_973_Closed_Text.style.display='none'; Codehighlighter1_736_973_Open_Image.style.display='inline'; Codehighlighter1_736_973_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />        </span>
										<span style="COLOR: #0000ff">if</span>
										<span style="COLOR: #000000"> ( o </span>
										<span style="COLOR: #000000">!=</span>
										<span style="COLOR: #000000"> </span>
										<span style="COLOR: #0000ff">null</span>
										<span style="COLOR: #000000"> </span>
										<span style="COLOR: #000000">&amp;&amp;</span>
										<span style="COLOR: #000000">PoliticalCandidate.</span>
										<span style="COLOR: #0000ff">class</span>
										<span style="COLOR: #000000">.isAssignableFrom(o) ) </span>
										<span id="Codehighlighter1_736_973_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" />
										</span>
								</font>
								<span id="Codehighlighter1_736_973_Open_Text">
										<font size="2">
												<span style="COLOR: #000000">{<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />            PoliticalCandidate pc </span>
												<span style="COLOR: #000000">=</span>
										</font>
										<font size="2">
												<span style="COLOR: #000000"> (PoliticalCandidate) o;<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />            equals </span>
												<span style="COLOR: #000000">=</span>
												<span style="COLOR: #000000"> (</span>
												<span style="COLOR: #0000ff">new</span>
										</font>
										<span style="COLOR: #000000">
												<font size="2"> EqualsBuilder( )<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />                       .append(firstName, ps.firstName)<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />                       .append(lastName, ps.lastName)).isEquals( );<br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />        }</font>
										</span>
								</span>
								<span style="COLOR: #000000">
										<br />
										<font size="2">
												<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />        </font>
								</span>
								<span style="COLOR: #0000ff">
										<font size="2">return</font>
								</span>
								<span style="COLOR: #000000">
										<font size="2"> equals;<br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />    }</font>
								</span>
						</span>
						<span style="COLOR: #000000">
								<br />
								<font size="2">
										<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />
										<br />
										<img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</font>
						</span>
				</span>
				<span style="COLOR: #000000">
						<br />
						<font size="2">
								<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
						</font>
				</span>
		</div>
		<font size="2">Discussion：<br />1.在上述例子中，当有相同的firstname和lastname时,认为两个对象的hashCode相同，从而equals()返回true.<br />如果hashCode取决于该class的所有filed时需要使用反射机制来产生一个hashCode。<br /></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">
						<img id="Codehighlighter1_23_78_Open_Image" onclick="this.style.display='none'; Codehighlighter1_23_78_Open_Text.style.display='none'; Codehighlighter1_23_78_Closed_Image.style.display='inline'; Codehighlighter1_23_78_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" />
						<img id="Codehighlighter1_23_78_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_23_78_Closed_Text.style.display='none'; Codehighlighter1_23_78_Open_Image.style.display='inline'; Codehighlighter1_23_78_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align="top" />
						<span style="COLOR: #0000ff">public</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #0000ff">int</span>
						<span style="COLOR: #000000"> hashCode( ) </span>
						<span id="Codehighlighter1_23_78_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" />
						</span>
				</font>
				<span id="Codehighlighter1_23_78_Open_Text">
						<font size="2">
								<span style="COLOR: #000000">{<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    </span>
								<span style="COLOR: #0000ff">return</span>
								<span style="COLOR: #000000"> HashCodeBuilder.reflectionHashCode(</span>
								<span style="COLOR: #0000ff">this</span>
						</font>
						<span style="COLOR: #000000">
								<font size="2">);<br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</font>
						</span>
				</span>
		</div>
		<font size="2">
				<font face="Courier New">和ToStringBuilder</font> 与 <tt>HashCodeBuilder一样</tt><tt>EqualsBuilder</tt> 也是使用append()方法进行配置，</font>
		<font size="2">
				<font face="Courier New">EqualsBuilder的append()方法可以接受基本类型、对象、数组作为参数。EqualsBuilder强大的地方在于可以直接把数组作为参数传入append()方法，EqualsBuilder会依次比较数组中的每个元素。<br /></font>2.如果两个对象相等当且仅当每个属性值都相等 这句话可以由以下代码实现：<br /></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">
						<img id="Codehighlighter1_32_86_Open_Image" onclick="this.style.display='none'; Codehighlighter1_32_86_Open_Text.style.display='none'; Codehighlighter1_32_86_Closed_Image.style.display='inline'; Codehighlighter1_32_86_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" />
						<img id="Codehighlighter1_32_86_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_32_86_Closed_Text.style.display='none'; Codehighlighter1_32_86_Open_Image.style.display='inline'; Codehighlighter1_32_86_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align="top" />
						<span style="COLOR: #0000ff">public</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #0000ff">boolean</span>
						<span style="COLOR: #000000"> equals(Object o) </span>
						<span id="Codehighlighter1_32_86_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" />
						</span>
				</font>
				<span id="Codehighlighter1_32_86_Open_Text">
						<font size="2">
								<span style="COLOR: #000000">{<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    </span>
								<span style="COLOR: #0000ff">return</span>
								<span style="COLOR: #000000"> EqualsBuilder.reflectionEquals(</span>
								<span style="COLOR: #0000ff">this</span>
						</font>
						<span style="COLOR: #000000">
								<font size="2">, o);<br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</font>
						</span>
				</span>
		</div>
		<p>
				<font size="2">问题提出：需要快速实现compareTo()方法<br />解决方法：使用<font face="Courier New"><font color="#ff0000">CompareToBuilder</font>提供的<font color="#ff0000">compareTo()</font>方法。同样的CompareToBuilder也使用了反射机制。以下代码提供了一个compareTo()方法，用于比较两个对象所有的非static和非transient成员变量。<br /></font></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">
				<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
				<span style="COLOR: #0000ff">import</span>
				<span style="COLOR: #000000"> org.apache.commons.lang.builder.CompareToBuilder;<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /></span>
				<span style="COLOR: #008000">//</span>
				<span style="COLOR: #008000"> Build a compareTo function from reflection </span>
				<span style="COLOR: #008000">
						<br />
						<img id="Codehighlighter1_136_197_Open_Image" onclick="this.style.display='none'; Codehighlighter1_136_197_Open_Text.style.display='none'; Codehighlighter1_136_197_Closed_Image.style.display='inline'; Codehighlighter1_136_197_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" />
						<img id="Codehighlighter1_136_197_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_136_197_Closed_Text.style.display='none'; Codehighlighter1_136_197_Open_Image.style.display='inline'; Codehighlighter1_136_197_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align="top" />
				</span>
				<span style="COLOR: #0000ff">public</span>
				<span style="COLOR: #000000"> </span>
				<span style="COLOR: #0000ff">int</span>
				<span style="COLOR: #000000"> compareTo(Object o) </span>
				<span id="Codehighlighter1_136_197_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" />
				</span>
				<span id="Codehighlighter1_136_197_Open_Text">
						<span style="COLOR: #000000">{<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    </span>
						<span style="COLOR: #0000ff">return</span>
						<span style="COLOR: #000000"> CompareToBuilder.reflectionCompare(</span>
						<span style="COLOR: #0000ff">this</span>
						<span style="COLOR: #000000">, obj);<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span>
				</span>
		</div>
		<br />
		<font face="Verdana" size="2">Discussion：</font>
		<font size="2">
				<font face="Courier New">CompareToBuilder.reflectionCompare()提供了两个对象non-static和nontransient成员变量的方法。 reflectionCompare()方法不予理会static和transient变量，因此以下代码中的averageAge和fullName变量是不会进入比较表达式的。<br /></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">
								<img id="Codehighlighter1_32_420_Open_Image" onclick="this.style.display='none'; Codehighlighter1_32_420_Open_Text.style.display='none'; Codehighlighter1_32_420_Closed_Image.style.display='inline'; Codehighlighter1_32_420_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" />
								<img id="Codehighlighter1_32_420_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_32_420_Closed_Text.style.display='none'; Codehighlighter1_32_420_Open_Image.style.display='inline'; Codehighlighter1_32_420_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align="top" />
								<span style="COLOR: #0000ff">public</span>
								<span style="COLOR: #000000"> </span>
								<span style="COLOR: #0000ff">class</span>
								<span style="COLOR: #000000"> PoliticalCandidate </span>
								<span id="Codehighlighter1_32_420_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" />
								</span>
						</font>
						<span id="Codehighlighter1_32_420_Open_Text">
								<font size="2">
										<span style="COLOR: #000000">{<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    </span>
										<span style="COLOR: #008000">//</span>
										<span style="COLOR: #008000"> Static variable</span>
								</font>
								<span style="COLOR: #008000">
										<br />
										<font size="2">
												<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />
										</font>
								</span>
								<font size="2">
										<span style="COLOR: #000000">    </span>
										<span style="COLOR: #0000ff">private</span>
										<span style="COLOR: #000000"> </span>
										<span style="COLOR: #0000ff">static</span>
								</font>
								<font size="2">
										<span style="COLOR: #000000"> String averageAge;<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    </span>
										<span style="COLOR: #008000">//</span>
										<span style="COLOR: #008000"> Member variables </span>
								</font>
								<span style="COLOR: #008000">
										<br />
										<font size="2">
												<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />
										</font>
								</span>
								<font size="2">
										<span style="COLOR: #000000">    </span>
										<span style="COLOR: #0000ff">private</span>
								</font>
								<font size="2">
										<span style="COLOR: #000000"> String firstName;<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    </span>
										<span style="COLOR: #0000ff">private</span>
								</font>
								<font size="2">
										<span style="COLOR: #000000"> String lastName;<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    </span>
										<span style="COLOR: #0000ff">private</span>
										<span style="COLOR: #000000"> </span>
										<span style="COLOR: #0000ff">transient</span>
								</font>
								<font size="2">
										<span style="COLOR: #000000"> String fullName;<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    </span>
										<span style="COLOR: #008000">//</span>
								</font>
								<font size="2">
										<span style="COLOR: #008000"> Constructors<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    </span>
										<span style="COLOR: #008000">//</span>
								</font>
								<font size="2">
										<span style="COLOR: #008000"> get/set methods<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    </span>
										<span style="COLOR: #008000">//</span>
										<span style="COLOR: #008000"> Build a compareTo function from reflection </span>
								</font>
								<span style="COLOR: #008000">
										<br />
										<font size="2">
												<img id="Codehighlighter1_349_417_Open_Image" onclick="this.style.display='none'; Codehighlighter1_349_417_Open_Text.style.display='none'; Codehighlighter1_349_417_Closed_Image.style.display='inline'; Codehighlighter1_349_417_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" />
												<img id="Codehighlighter1_349_417_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_349_417_Closed_Text.style.display='none'; Codehighlighter1_349_417_Open_Image.style.display='inline'; Codehighlighter1_349_417_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />
										</font>
								</span>
								<font size="2">
										<span style="COLOR: #000000">    </span>
										<span style="COLOR: #0000ff">public</span>
										<span style="COLOR: #000000"> </span>
										<span style="COLOR: #0000ff">int</span>
										<span style="COLOR: #000000"> compareTo(Object o) </span>
										<span id="Codehighlighter1_349_417_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" />
										</span>
								</font>
								<span id="Codehighlighter1_349_417_Open_Text">
										<font size="2">
												<span style="COLOR: #000000">{<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />        </span>
												<span style="COLOR: #0000ff">return</span>
												<span style="COLOR: #000000"> CompareToBuilder.reflectionCompare(</span>
												<span style="COLOR: #0000ff">this</span>
										</font>
										<span style="COLOR: #000000">
												<font size="2">, obj);<br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />    }</font>
										</span>
								</span>
								<span style="COLOR: #000000">
										<br />
										<font size="2">
												<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />
												<br />
												<img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</font>
								</span>
						</span>
				</div>
		</font>
		<font face="Verdana" size="2">比较对象成员变量的时候应该有一个比较的次序存在，上述代码中默认的应该是先比较lastName,然后是firstName。调用append()方法可以把要比较的变量加入比较表达式中，并且遵循后加入的先比较的次序。<br />例如：<br /></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">
						<font face="Verdana">
								<img id="Codehighlighter1_31_444_Open_Image" onclick="this.style.display='none'; Codehighlighter1_31_444_Open_Text.style.display='none'; Codehighlighter1_31_444_Closed_Image.style.display='inline'; Codehighlighter1_31_444_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" />
								<img id="Codehighlighter1_31_444_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_31_444_Closed_Text.style.display='none'; Codehighlighter1_31_444_Open_Image.style.display='inline'; Codehighlighter1_31_444_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align="top" />
						</font>
						<span style="COLOR: #0000ff">public</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #0000ff">int</span>
						<span style="COLOR: #000000"> compareTo(Object o) </span>
						<span id="Codehighlighter1_31_444_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" />
						</span>
				</font>
				<span id="Codehighlighter1_31_444_Open_Text">
						<font size="2">
								<span style="COLOR: #000000">{<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    </span>
								<span style="COLOR: #0000ff">int</span>
								<span style="COLOR: #000000"> compare </span>
								<span style="COLOR: #000000">=</span>
								<span style="COLOR: #000000"> </span>
								<span style="COLOR: #000000">-</span>
								<span style="COLOR: #000000">1</span>
								<span style="COLOR: #000000">; </span>
								<span style="COLOR: #008000">//</span>
								<span style="COLOR: #008000"> By default return less-than</span>
						</font>
						<span style="COLOR: #008000">
								<br />
								<font size="2">
										<img id="Codehighlighter1_173_421_Open_Image" onclick="this.style.display='none'; Codehighlighter1_173_421_Open_Text.style.display='none'; Codehighlighter1_173_421_Closed_Image.style.display='inline'; Codehighlighter1_173_421_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" />
										<img id="Codehighlighter1_173_421_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_173_421_Closed_Text.style.display='none'; Codehighlighter1_173_421_Open_Image.style.display='inline'; Codehighlighter1_173_421_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />
								</font>
						</span>
						<font size="2">
								<span style="COLOR: #000000">    </span>
								<span style="COLOR: #0000ff">if</span>
								<span style="COLOR: #000000">( o </span>
								<span style="COLOR: #000000">!=</span>
								<span style="COLOR: #000000"> </span>
								<span style="COLOR: #0000ff">null</span>
								<span style="COLOR: #000000"> </span>
								<span style="COLOR: #000000">&amp;&amp;</span>
								<span style="COLOR: #000000"> PoliticalCandidate.</span>
								<span style="COLOR: #0000ff">class</span>
								<span style="COLOR: #000000">.isAssignableFrom( o.getClass( ) ) ) </span>
								<span id="Codehighlighter1_173_421_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" />
								</span>
						</font>
						<span id="Codehighlighter1_173_421_Open_Text">
								<font size="2">
										<span style="COLOR: #000000">{<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />            PoliticalCandidate pc </span>
										<span style="COLOR: #000000">=</span>
								</font>
								<font size="2">
										<span style="COLOR: #000000"> (PoliticalCandidate) o;<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />            compare </span>
										<span style="COLOR: #000000">=</span>
										<span style="COLOR: #000000"> (</span>
										<span style="COLOR: #0000ff">new</span>
								</font>
								<span style="COLOR: #000000">
										<font size="2"> CompareToBuilder( )<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />                          .append(firstName, pc.firstName)<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />                          .append(lastName, pc.lastName)).toComparison( );<br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />    }</font>
								</span>
						</span>
						<span style="COLOR: #000000">
								<br />
								<font size="2">
										<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />
										<br />
										<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    </font>
						</span>
						<span style="COLOR: #0000ff">
								<font size="2">return</font>
						</span>
						<span style="COLOR: #000000">
								<font size="2"> compare;<br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</font>
						</span>
				</span>
		</div>
		<font size="2">在比较的时候会先比较lastName，只有在lastName相同的情况下才会比较firstName。<br />ps：实现compareTo()的时候应保证和equals()规则相同，即当compareTo()返回是0的时候equals()应该返回true。<br /></font>
		<div class="post">
				<h2>
						<a id="viewpost1_TitleUrl" href="/borball/archive/2006/03/07/34004.html">
								<font color="#770000">1.1 ReflectionToStringBuilder </font>
						</a>
				</h2>
				<font size="2">本笔记是在阅读<strong>Jakarta Commons Cookbook</strong>时所留下的。<br /></font>
				<font color="#0000ff">
						<font color="#000000" size="2">1.使用<font face="Courier New">ReflectionToStringBuilder</font> 或者<tt>ToStringBuilder</tt> 自动产生toString()的内容。<br />   使用举例：假设有一个表征校长候选人信息的javabean－<font face="Courier New">PoliticalCandidate。<br /></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"><img id="Codehighlighter1_32_328_Open_Image" onclick="this.style.display='none'; Codehighlighter1_32_328_Open_Text.style.display='none'; Codehighlighter1_32_328_Closed_Image.style.display='inline'; Codehighlighter1_32_328_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_32_328_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_32_328_Closed_Text.style.display='none'; Codehighlighter1_32_328_Open_Image.style.display='inline'; Codehighlighter1_32_328_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align="top" /><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000"> PoliticalCandidate </span><span id="Codehighlighter1_32_328_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" /></span><span id="Codehighlighter1_32_328_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    </span><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000"> String lastName;<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    </span><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000"> String firstName;<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    </span><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000"> Date dateOfBirth;<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    </span><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000"> BigDecimal moneyRaised;<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    </span><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000"> State homeState;<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> get/set方法省略</span><span style="COLOR: #008000"><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" /></span><span style="COLOR: #000000"><br /><img id="Codehighlighter1_268_326_Open_Image" onclick="this.style.display='none'; Codehighlighter1_268_326_Open_Text.style.display='none'; Codehighlighter1_268_326_Closed_Image.style.display='inline'; Codehighlighter1_268_326_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_268_326_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_268_326_Closed_Text.style.display='none'; Codehighlighter1_268_326_Open_Image.style.display='inline'; Codehighlighter1_268_326_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />    </span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> toString( ) </span><span id="Codehighlighter1_268_326_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" /></span><span id="Codehighlighter1_268_326_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />        ReflectionToStringBuilder.toString( </span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000"> );<br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />    }</span></span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span></span></div><br />该bean里面有个toString()方法，假设有以下操作：<br /><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"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> Create a State</span><span style="COLOR: #008000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #000000">State va </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000"> State( </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">VA</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">, </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Virginia</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> Create a Birth Date</span><span style="COLOR: #008000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #000000">Calendar calendar </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000"> GregorianCalendar( );<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />calendar.set( Calendar.YEAR, </span><span style="COLOR: #000000">1743</span><span style="COLOR: #000000"> );<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />calendar.set( Calendar.MONTH, Calendar.APRIL );<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />calendar.set( Calendar.DAY_OF_MONTH, </span><span style="COLOR: #000000">13</span><span style="COLOR: #000000"> );<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />Date dob </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> calendar.getTime( );<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />BigDecimal moneyRaised </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000"> BigDecimal( </span><span style="COLOR: #000000">293829292.93</span><span style="COLOR: #000000"> );        <br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> Create a Political Candidate</span><span style="COLOR: #008000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #000000">PoliticalCandidate candidate </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> <br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />    </span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000"> PoliticalCandidate( </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Jefferson</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">, </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Thomas</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">, dob, moneyRaised, va );<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />     <br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />System.out.println( candidate );<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /></span></div></font>
				</font>
				<font size="2">假设State对象也是一个使用<font face="Courier New">ReflectionToStringBuilder的javabean，上述程序一种可能的输出为<font color="#000000">com.discursive.jccook.lang.builders.PoliticalCandidate@187aeca</font><br />    [lastName=Jefferson,\firstName=Thomas,<br />     dateOfBirth=Sat Apr 13 22:38:42 CST 1743,<br />     moneyRaised=\293829292.930000007152557373046875,<br />     state=\com.discursive.jccook.lang.builders.State@87816d<br />         [abbreviation=VA,name=Virginia]]<br /></font></font>
				<p class="postfoot"> </p>
		</div>
		<div class="sysBr500 text" id="articleText5377b40a0100077w" align="left">org.apache.commons.lang.builder<br />　　CompareToBuilder – 用于辅助实现Comparable.compareTo(Object)方法；<br />　　<br />　　<b style="COLOR: black; BACKGROUND-COLOR: #ffff66">EqualsBuilder</b> – 用于辅助实现Object.equals()方法；<br />　　<br />　　HashCodeBuilder – 用于辅助实现Object.hashCode()方法；<br />　　<br />　　ToStringBuilder – 用于辅助实现Object.toString()方法；<br />　　<br />　　ReflectionToStringBuilder – 使用反射机制辅助实现Object.toString()方法；<br />　　<br />　　ToStringStyle – 辅助ToStringBuilder控制输出格式；<br />　　<br />　　StandardToStringStyle – 辅助ToStringBuilder控制标准格式。 </div>
<img src ="http://www.blogjava.net/19851985lili/aggbug/95448.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/19851985lili/" target="_blank">☜♥☞MengChuChen</a> 2007-01-23 09:07 <a href="http://www.blogjava.net/19851985lili/articles/95448.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java虚拟机类装载：原理、实现与应用 </title><link>http://www.blogjava.net/19851985lili/articles/94975.html</link><dc:creator>☜♥☞MengChuChen</dc:creator><author>☜♥☞MengChuChen</author><pubDate>Fri, 19 Jan 2007 10:19:00 GMT</pubDate><guid>http://www.blogjava.net/19851985lili/articles/94975.html</guid><wfw:comment>http://www.blogjava.net/19851985lili/comments/94975.html</wfw:comment><comments>http://www.blogjava.net/19851985lili/articles/94975.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/19851985lili/comments/commentRss/94975.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/19851985lili/services/trackbacks/94975.html</trackback:ping><description><![CDATA[
		<h2 class="diaryTitle">Java虚拟机类装载：原理、实现与应用 </h2>                                       
<p></p><table cellspacing="0" cellpadding="0" width="100%" border="0"><tbody><tr><td align="middle" width="3%" height="17" rowspan="2"></td><td colspan="2"><span class="style2"><strong>Java虚拟机类装载：原理、实现与应用 </strong></span><strong><br /></strong><hr align="left" width="95%" color="#597282" noshade="" size="1" /><span class="style3">By jorren 发表于 2005-12-21 15:13:00</span></td></tr><tr><td colspan="2"><br /><span class="style6"><p>一、引言 </p><p>　　Java虚拟机(JVM)的类装载就是指将包含在类文件中的字节码装载到JVM中, 并使其成为JVM一部分的过程。JVM的类动态装载技术能够在运行时刻动态地加载或者替换系统的某些功能模块, 而不影响系统其他功能模块的正常运行。本文将分析JVM中的类装载系统，探讨JVM中类装载的原理、实现以及应用。 </p><p>　　二、Java虚拟机的类装载实现与应用 </p><p>　　2.1 装载过程简介 </p><p>　　所谓装载就是寻找一个类或是一个接口的二进制形式并用该二进制形式来构造代表这个类或是这个接口的class对象的过程，其中类或接口的名称是给定了的。当然名称也可以通过计算得到，但是更常见的是通过搜索源代码经过编译器编译后所得到的二进制形式来构造。 </p><p>　　在Java中，类装载器把一个类装入Java虚拟机中，要经过三个步骤来完成：装载、链接和初始化，其中链接又可以分成校验、准备和解析三步，除了解析外，其它步骤是严格按照顺序完成的，各个步骤的主要工作如下： </p><p>　　装载：查找和导入类或接口的二进制数据； <br />　　链接：执行下面的校验、准备和解析步骤，其中解析步骤是可以选择的； <br />　　校验：检查导入类或接口的二进制数据的正确性； <br />　　准备：给类的静态变量分配并初始化存储空间； <br />　　解析：将符号引用转成直接引用； <br />　　初始化：激活类的静态变量的初始化Java代码和静态Java代码块。 </p><p>　　至于在类装载和虚拟机启动的过程中的具体细节和可能会抛出的错误，请参看《Java虚拟机规范》以及《深入Java虚拟机》，它们在网络上面的资源地址是： <br />　　<a href="http://java.sun.com/docs/books/vmspec/2nd-edition/html/Preface.doc.html">http://java.sun.com/docs/books/vmspec/2nd-edition/html/Preface.doc.html</a><br />　　<a href="http://www.artima.com/insidejvm/ed2/index.html">http://www.artima.com/insidejvm/ed2/index.html</a><br />　　由于本文的讨论重点不在此就不再多叙述。 </p><p>　　2.2 装载的实现 </p><p>　　JVM中类的装载是由ClassLoader和它的子类来实现的,Java ClassLoader 是一个重要的Java运行时系统组件。它负责在运行时查找和装入类文件的类。 </p><p>　　在Java中，ClassLoader是一个抽象类，它在包java.lang中,可以这样说，只要了解了在ClassLoader中的一些重要的方法，再结合上面所介绍的JVM中类装载的具体的过程，对动态装载类这项技术就有了一个比较大概的掌握，这些重要的方法包括以下几个: </p><p>　　①loadCass方法 loadClass(String name ,boolean resolve)其中name参数指定了JVM需要的类的名称,该名称以包表示法表示,如Java.lang.Object；resolve参数告诉方法是否需要解析类，在初始化类之前,应考虑类解析，并不是所有的类都需要解析，如果JVM只需要知道该类是否存在或找出该类的超类,那么就不需要解析。这个方法是ClassLoader 的入口点。 </p><p>　　②defineClass方法 这个方法接受类文件的字节数组并把它转换成Class对象。字节数组可以是从本地文件系统或网络装入的数据。它把字节码分析成运行时数据结构、校验有效性等等。 </p><p>　　③findSystemClass方法 findSystemClass方法从本地文件系统装入文件。它在本地文件系统中寻找类文件,如果存在,就使用defineClass将字节数组转换成Class对象,以将该文件转换成类。当运行Java应用程序时,这是JVM 正常装入类的缺省机制。 </p><p>　　④resolveClass方法 resolveClass(Class c)方法解析装入的类,如果该类已经被解析过那么将不做处理。当调用loadClass方法时,通过它的resolve 参数决定是否要进行解析。 </p><p>　　⑤findLoadedClass方法 当调用loadClass方法装入类时,调用findLoadedClass 方法来查看ClassLoader是否已装入这个类,如果已装入,那么返回Class对象,否则返回NULL。如果强行装载已存在的类,将会抛出链接错误。 </p><p>　　2.3 装载的应用 </p><p>　　一般来说，我们使用虚拟机的类装载时需要继承抽象类java.lang.ClassLoader,其中必须实现的方法是loadClass()，对于这个方法需要实现如下操作:(1) 确认类的名称;(2) 检查请求要装载的类是否已经被装载;(3) 检查请求加载的类是否是系统类;(4) 尝试从类装载器的存储区获取所请求的类;(5) 在虚拟机中定义所请求的类;(6) 解析所请求的类;(7) 返回所请求的类。 </p><p>　　所有的Java 虚拟机都包括一个内置的类装载器，这个内置的类库装载器被称为根装载器(bootstrap ClassLoader)。根装载器的特殊之处是它只能够装载在设计时刻已知的类,因此虚拟机假定由根装载器所装载的类都是安全的、可信任的,可以不经过安全认证而直接运行。当应用程序需要加载并不是设计时就知道的类时,必须使用用户自定义的装载器(user-defined ClassLoader)。下面我们举例说明它的应用。 </p><p>　　public abstract class MultiClassLoader extends ClassLoader{ <br />　　... <br />　　public synchronized Class loadClass(String s, boolean flag) <br />　　throws ClassNotFoundException <br />　　{ <br />　　/* 检查类s是否已经在本地内存*/ <br />　　Class class1 = (Class)classes.get(s); </p><p>　　/* 类s已经在本地内存*/ <br />　　if(class1 != null) return class1; <br />　　try/*用默认的ClassLoader 装入类*/ { <br />　　class1 = super.findSystemClass(s); <br />　　return class1; <br />　　} <br />　　catch(ClassNotFoundException _ex) { <br />　　System.out.println("&gt;&gt; Not a system class."); <br />　　} </p><p>　　/* 取得类s的字节数组*/ <br />　　byte abyte0[] = loadClassBytes(s); <br />　　if(abyte0 == null) throw new ClassNotFoundException(); </p><p>　　/* 将类字节数组转换为类*/ <br />　　class1 = defineClass(null, abyte0, 0, abyte0.length); <br />　　if(class1 == null) throw new ClassFormatError(); <br />　　if(flag) resolveClass(class1); /*解析类*/ </p><p>　　/* 将新加载的类放入本地内存*/ <br />　　classes.put(s, class1); <br />　　System.out.println("&gt;&gt; Returning newly loaded class."); </p><p>　　/* 返回已装载、解析的类*/ <br />　　return class1; <br />　　} <br />　　... <br />　　} <br />三、Java虚拟机的类装载原理 </p><p>　　前面我们已经知道，一个Java应用程序使用两种类型的类装载器：根装载器(bootstrap)和用户定义的装载器(user-defined)。根装载器是Java虚拟机实现的一部分，举个例子来说，如果一个Java虚拟机是在现在已经存在并且正在被使用的操作系统的顶部用C程序来实现的，那么根装载器将是那些C程序的一部分。根装载器以某种默认的方式将类装入，包括那些Java API的类。在运行期间一个Java程序能安装用户自己定义的类装载器。根装载器是虚拟机固有的一部分，而用户定义的类装载器则不是，它是用Java语言写的，被编译成class文件之后然后再被装入到虚拟机，并像其它的任何对象一样可以被实例化。 Java类装载器的体系结构如下所示： <br />　　 <br />　　Java的类装载模型是一种代理(delegation)模型。当JVM 要求类装载器CL(ClassLoader)装载一个类时,CL首先将这个类装载请求转发给他的父装载器。只有当父装载器没有装载并无法装载这个类时,CL才获得装载这个类的机会。这样, 所有类装载器的代理关系构成了一种树状的关系。树的根是类的根装载器(bootstrap ClassLoader) , 在JVM 中它以"null"表示。除根装载器以外的类装载器有且仅有一个父装载器。在创建一个装载器时, 如果没有显式地给出父装载器, 那么JVM将默认系统装载器为其父装载器。Java的基本类装载器代理结构如图2所示： <br />下面针对各种类装载器分别进行详细的说明。 <br />      根(Bootstrap) 装载器:该装载器没有父装载器，它是JVM实现的一部分，从sun.boot.class.path装载运行时库的核心代码。 <br />     扩展(Extension) 装载器:继承的父装载器为根装载器，不像根装载器可能与运行时的操作系统有关，这个类装载器是用纯Java代码实现的，它从java.ext.dirs (扩展目录)中装载代码。 <br />　　系统(System or Application) 装载器:装载器为扩展装载器，我们都知道在安装JDK的时候要设置环境变量(CLASSPATH )，这个类装载器就是从java.class.path(CLASSPATH 环境变量)中装载代码的，它也是用纯Java代码实现的，同时还是用户自定义类装载器的缺省父装载器。 </p><p>　　小应用程序(Applet) 装载器: 装载器为系统装载器，它从用户指定的网络上的特定目录装载小应用程序代码。 </p><p>　　在设计一个类装载器的时候，应该满足以下两个条件： </p><p>　　对于相同的类名，类装载器所返回的对象应该是同一个类对象 </p><p>　　如果类装载器CL1将装载类C的请求转给类装载器CL2，那么对于以下的类或接口,CL1和CL2应该返回同一个类对象:a)S为C的直接超类;b)S为C的直接超接口;c)S为C的成员变量的类型;d)S为C的成员方法或构建器的参数类型;e)S为C的成员方法的返回类型。 <br />　　每个已经装载到JVM中的类都隐式含有装载它的类装载器的信息。类方法getClassLoader 可以得到装载这个类的类装载器。一个类装载器认识的类包括它的父装载器认识的类和它自己装载的类，可见类装载器认识的类是它自己装载的类的超集。注意我们可以得到类装载器的有关的信息，但是已经装载到JVM中的类是不能更改它的类装载器的。 </p><p>　　Java中的类的装载过程也就是代理装载的过程。比如:Web浏览器中的JVM需要装载一个小应用程序TestApplet。JVM调用小应用程序装载器ACL(Applet ClassLoader)来完成装载。ACL首先请求它的父装载器, 即系统装载器装载TestApplet是否装载了这个类, 由于TestApplet不在系统装载器的装载路径中, 所以系统装载器没有找到这个类, 也就没有装载成功。接着ACL自己装载TestApplet。ACL通过网络成功地找到了TestApplet.class 文件并将它导入到了JVM中。在装载过程中, JVM发现TestAppet是从超类java.applet.Applet继承的。所以JVM再次调用ACL来装载java.applet.Applet类。ACL又再次按上面的顺序装载Applet类, 结果ACL发现他的父装载器已经装载了这个类, 所以ACL就直接将这个已经装载的类返回给了JVM , 完成了Applet类的装载。接下来,Applet类的超类也一样处理。最后, TestApplet及所有有关的类都装载到了JVM中。 </p><p>　　四、结论 </p><p>　　类的动态装载机制是JVM的一项核心技术, 也是容易被忽视而引起很多误解的地方。本文介绍了JVM中类装载的原理、实现以及应用，尤其分析了ClassLoader的结构、用途以及如何利用自定义的ClassLoader装载并执行Java类，希望能使读者对JVM中的类装载有一个比较深入的理解 </p></span></td></tr></tbody></table><img src ="http://www.blogjava.net/19851985lili/aggbug/94975.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/19851985lili/" target="_blank">☜♥☞MengChuChen</a> 2007-01-19 18:19 <a href="http://www.blogjava.net/19851985lili/articles/94975.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java中的XML </title><link>http://www.blogjava.net/19851985lili/articles/93522.html</link><dc:creator>☜♥☞MengChuChen</dc:creator><author>☜♥☞MengChuChen</author><pubDate>Fri, 12 Jan 2007 12:04:00 GMT</pubDate><guid>http://www.blogjava.net/19851985lili/articles/93522.html</guid><wfw:comment>http://www.blogjava.net/19851985lili/comments/93522.html</wfw:comment><comments>http://www.blogjava.net/19851985lili/articles/93522.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/19851985lili/comments/commentRss/93522.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/19851985lili/services/trackbacks/93522.html</trackback:ping><description><![CDATA[
		<div class="diaryBody">
				<p>在IBM的developerWorks上有两篇非常优秀的关于<span style="COLOR: #cc0000">Java</span><span style="COLOR: #cc0000">XML</span> API的评测文章：</p>
				<p>
						<a href="http://www-900.ibm.com/developerWorks/cn/xml/x-injava/index.shtml" target="_blank">
								<span style="COLOR: #cc0000">Java</span>
								<font color="#006699">中</font>
								<span style="COLOR: #cc0000">XML</span>
								<font color="#006699">文档模型的性能</font>
						</a>
				</p>
				<p>
						<a href="http://www-900.ibm.com/developerWorks/cn/xml/x-injava2/index.shtml" target="_blank">
								<span style="COLOR: #cc0000">Java</span>
								<font color="#006699">中</font>
								<span style="COLOR: #cc0000">XML</span>
								<font color="#006699">文档模型的用法</font>
						</a>
				</p>
				<p>对这两篇文章我想说的就是 <strong>吐血推荐</strong></p>
				<p>
						<span style="COLOR: #cc0000">Java</span>的<span style="COLOR: #cc0000">XML</span> API这几篇文章该讲的都讲到了，我只想补充几点：</p>
				<a name="A2">
				</a>
				<h4>一、Crimson和Xerces恩仇录</h4>
				<blockquote>
						<p>Crimson来自于Sun捐赠给Apache的ProjectX项目，Xerces来自IBM捐赠给Apache的<span style="COLOR: #cc0000">XML</span>4J项目，结果Xerces胜出，成了Apache <span style="COLOR: #cc0000">XML</span>小组全力开发的<span style="COLOR: #cc0000">XML</span> API，而Crimon已经早就不做了，如今Xerces名满天下，到处都是在用Xerces DOM和SAX解析器，只有Sun不服气，非要在JDK1.4里面使用过时的Crimson，让人感觉像是在赌气一样，真是让人可怜又可气！不过IBM发行JDK用的<span style="COLOR: #cc0000">XML</span> 解析器自然是Xerces。</p>
						<p>由于JDK的Class Loader的优先级关系，当你采用JAXP编写<span style="COLOR: #cc0000">XML</span>程序的时候，即使把Xerces包引入CLASSPATH，JDK还是会顽固的使用Crimson，这一点通过打开JVM的verbose参数可以观察到。不过JDK也允许你采用其它的解析器，因此我们可以通过在JRE\lib\目录下建一个jaxp.properties的文件，来替换解析器，jaxp.properties内容如下：</p>
						<pre class="code">
								<span style="COLOR: #cc0000">java</span>x.<span style="COLOR: #cc0000">xml</span>.parsers.DocumentBuilderFactory=org.apache.xerces.jaxp.DocumentBuilderFactoryImpl

<span style="COLOR: #cc0000">java</span>x.<span style="COLOR: #cc0000">xml</span>.parsers.SAXParserFactory=org.apache.xerces.jaxp.SAXParserFactoryImpl

</pre>
						<p>这样就可以使用Xerces，当然你必须还是要把Xerces包放到CLASSPATH下。</p>
				</blockquote>
				<a name="A3">
				</a>
				<h4>二、JAXP的姗姗来迟</h4>
				<blockquote>
						<p>Sun在<span style="COLOR: #cc0000">XML</span>领域总是后知后觉，等到Sun重视<span style="COLOR: #cc0000">XML</span>的时候，<span style="COLOR: #cc0000">XML</span>的API早就满天 飞了，尤其是IBM具有非常大的领先优势。不过Sun是规范的制订者，于是参考W3C的标准制订了JAXP规范。JAXP不像Xerces和Crimon那样，它只是一个spec，本身是不做任何事情的，它的作用就是提出一个统一的接口，让其它的<span style="COLOR: #cc0000">XML</span> API都来遵循JAXP编程，那么用JAXP写出来的程序，底层的API可以任意切换。</p>
						<p>具体来说JAXP包括了几个工厂类，这就是JDK1.4里面的<span style="COLOR: #cc0000">java</span>x.<span style="COLOR: #cc0000">xml</span>.parsers 包，用来寻找符合DOM标准的<span style="COLOR: #cc0000">XML</span> API实现类的位置；此外JAXP还包括一整套interface，这就是JDK1.4里面的org.w3c.dom那几个包。工厂类负责加载DOM的实现类。那么加载的规则是什么呢？</p>
						<p>我是通过阅读JAXP的源代码知道的，工厂类首先会根据<span style="COLOR: #cc0000">java</span>命令行传入的参数进行寻找，然后在根据JRE\lib\jaxp.properties中定义的实现类寻找，最后什么都找不到的话，就用Crimson。注意Crimons是由Bootstrap Class Loader来load的，如果你不通过上面两个方法来改变工厂的寻找顺序，那么铁定用Crimson了 :(</p>
				</blockquote>
				<a name="A4">
				</a>
				<h4>三、DOM解析器和DOM API</h4>
				<blockquote>
						<p>当你严格采用JAXP编程的时候，是遵循W3C的DOm标准的，那么在JAXP底层你实际上可以任意切换不同的DOM实现，例如Xerces，或者Crimon，再或者其它，切换方法就是配置jaxp.properties。因此JAXP就是一些标准接口而已。</p>
						<p>而Xerces和Crimon也不单单是一个DOM实现那么简单，他们本身实际上也包含SAX解析器和DOM解析器。所以一个JAXP程序下面有如下层次：</p>
						<pre class="code">JAXP应用程序 -&gt; JAXP接口 -&gt; Xerces DOM实现 -&gt; Xerces DOM/SAX 解析器

</pre>
						<p>只要你用JAXP编程，那么你就可以切换到Crimson上来</p>
						<pre class="code">JAXP应用程序 -&gt; JAXP接口 -&gt; Crimson DOM实现 -&gt; Crimson DOM/SAX 解析器

</pre>
						<p>另外你也可以这样来做：</p>
						<pre class="code">JAXP应用程序 -&gt; JAXP接口 -&gt; Crimson DOM实现 -&gt; Xerces DOM/SAX 解析器

</pre>
						<p>不过如果你的程序不安装JAXP来写，那么就没有办法切换不同的DOM实现了。</p>
				</blockquote>
				<a name="A5">
				</a>
				<h4>四、不是标准的dom4j和jdom</h4>
				<blockquote>
						<p>W3C的DOM标准API难用的让人想撞墙，于是有一帮人开发<span style="COLOR: #cc0000">Java</span>专用的<span style="COLOR: #cc0000">XML</span> API目的是为了便于使用，这就是jdom的由来，开发到一半的时候，另一部分人又分了出来，他们有自己的想法，于是他们就去开发dom4j，形成了今天这样两个API，至于他们之间的性能，功能之比较看看上面我推荐的文章就知道了，jdom全面惨败。</p>
						<p>jdom 相当于上面的 JAXP接口 ＋ Xerces DOM实现部分，它本身没有解析器，它可以使用Xerces或者Crimson的解析器，就是这样：</p>
						<pre class="code">jdom应用程序 -&gt; jdom API -&gt; Xerces/Crimson解析器

</pre>
						<p>dom4j 和jdom类似，不过他自己绑定了一个叫做Alfred2的解析器，功能不是很全，但是速度很快，当没有其它的解析器的时候，dom4j将使用Alfred2解析器，如下：</p>
						<pre class="code">dom4j应用程序 -&gt; dom4j API -&gt;  Xerces/Crimson解析器

</pre>
						<p>或者</p>
						<pre class="code">dom4j应用程序 -&gt; dom4j API -&gt;  Alfred2解析器

</pre>
						<p>你在SF上下载的dom4j.jar是不含 Alfred2解析器的，而dom4j-full.jar包含了 Alfred2解析器，在这种情况下，实际上你什么也不需要，光是一个dom4j-full.jar就全部都包括了。</p>
						<p>因此可以看出采用dom4j/jdom编写的应用程序，已经不具备可移植性了。</p>
				</blockquote>
				<a name="A6">
				</a>
				<h4>五、小插曲</h4>
				<blockquote>
						<p>Sun是JAXP标准的制订者，甚至很执著的在JDK1.4里面绑定Crimson DOM实现和解析器，然后可笑的是，Sun自己的JAXM RI竟然不是用JAXP写出来的，而是dom4j，制订标准让大家遵守，自己却监守自盗，这未免太说不过去了吧！</p>
						<p>BTW: Hibernate也用的是dom4j来读取<span style="COLOR: #cc0000">XML</span>配置文件，如今已经越来越多的程序纷纷采用dom4j，如果你不是那么在乎可移植性，我强烈建议你采用dom4j。</p>
				</blockquote>
		</div>
<img src ="http://www.blogjava.net/19851985lili/aggbug/93522.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/19851985lili/" target="_blank">☜♥☞MengChuChen</a> 2007-01-12 20:04 <a href="http://www.blogjava.net/19851985lili/articles/93522.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JAVA实现断点续传</title><link>http://www.blogjava.net/19851985lili/articles/93514.html</link><dc:creator>☜♥☞MengChuChen</dc:creator><author>☜♥☞MengChuChen</author><pubDate>Fri, 12 Jan 2007 11:19:00 GMT</pubDate><guid>http://www.blogjava.net/19851985lili/articles/93514.html</guid><wfw:comment>http://www.blogjava.net/19851985lili/comments/93514.html</wfw:comment><comments>http://www.blogjava.net/19851985lili/articles/93514.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/19851985lili/comments/commentRss/93514.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/19851985lili/services/trackbacks/93514.html</trackback:ping><description><![CDATA[
		<p>)断点续传的原理 <br />其实断点续传的原理很简单，就是在Http的请求上和一般的下载有所不同而已。<br />打个比方，浏览器请求服务器上的一个文时，所发出的请求如下：<br />假设服务器域名为wwww.sjtu.edu.cn，文件名为down.zip。<br />GET /down.zip HTTP/1.1<br />Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-<br />excel, application/msword, application/vnd.ms-powerpoint, */*<br />Accept-Language: zh-cn<br />Accept-Encoding: gzip, deflate<br />User-Agent: Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)<br />Connection: Keep-Alive<br /><br /><br />服务器收到请求后，按要求寻找请求的文件，提取文件的信息，然后返回给浏览器，返回信息如下：<br /><br /><br />200<br />Content-Length=106786028<br />Accept-Ranges=bytes<br />Date=Mon, 30 Apr 2001 12:56:11 GMT<br />ETag=W/"02ca57e173c11:95b"<br />Content-Type=application/octet-stream<br />Server=Microsoft-IIS/5.0<br />Last-Modified=Mon, 30 Apr 2001 12:56:11 GMT<br /><br /><br />所谓断点续传，也就是要从文件已经下载的地方开始继续下载。所以在客户端浏览器传给<br />Web服务器的时候要多加一条信息--从哪里开始。<br />下面是用自己编的一个"浏览器"来传递请求信息给Web服务器，要求从2000070字节开始。<br />GET /down.zip HTTP/1.0<br />User-Agent: NetFox<br />RANGE: bytes=2000070-<br />Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2<br /><br /><br />仔细看一下就会发现多了一行RANGE: bytes=2000070-<br />这一行的意思就是告诉服务器down.zip这个文件从2000070字节开始传，前面的字节不用传了。<br />服务器收到这个请求以后，返回的信息如下：<br />206<br />Content-Length=106786028<br />Content-Range=bytes 2000070-106786027/106786028<br />Date=Mon, 30 Apr 2001 12:55:20 GMT<br />ETag=W/"02ca57e173c11:95b"<br />Content-Type=application/octet-stream<br />Server=Microsoft-IIS/5.0<br />Last-Modified=Mon, 30 Apr 2001 12:55:20 GMT<br /><br /><br />和前面服务器返回的信息比较一下，就会发现增加了一行：<br />Content-Range=bytes 2000070-106786027/106786028<br />返回的代码也改为206了，而不再是200了。<br /><br /><br />知道了以上原理，就可以进行断点续传的编程了。<br /><br /><br />(二)Java实现断点续传的关键几点 <br /><br /><br />(1)用什么方法实现提交RANGE: bytes=2000070-。<br />当然用最原始的Socket是肯定能完成的，不过那样太费事了，其实Java的net包中提供了这种功能。代码如下：<br />URL url = new URL("http://www.sjtu.edu.cn/down.zip");<br />HttpURLConnection httpConnection = (HttpURLConnection)url.openConnection<br /><br /><br />();<br />//设置User-Agent<br />httpConnection.setRequestProperty("User-Agent","NetFox");<br />//设置断点续传的开始位置<br />httpConnection.setRequestProperty("RANGE","bytes=2000070");<br />//获得输入流<br />InputStream input = httpConnection.getInputStream();<br /><br /><br />从输入流中取出的字节流就是down.zip文件从2000070开始的字节流。<br />大家看，其实断点续传用Java实现起来还是很简单的吧。<br />接下来要做的事就是怎么保存获得的流到文件中去了。<br /><br /><br />保存文件采用的方法。<br />我采用的是IO包中的RandAccessFile类。<br />操作相当简单，假设从2000070处开始保存文件，代码如下：<br />RandomAccess oSavedFile = new RandomAccessFile("down.zip","rw");<br />long nPos = 2000070;<br />//定位文件指针到nPos位置<br />oSavedFile.seek(nPos);<br />byte[] b = new byte[1024];<br />int nRead;<br />//从输入流中读入字节流，然后写到文件中<br />while((nRead=input.read(b,0,1024)) &gt; 0)<br />{<br />oSavedFile.write(b,0,nRead);<br />}<br /><br />怎么样，也很简单吧。<br />接下来要做的就是整合成一个完整的程序了。包括一系列的线程控制等等。<br /><br /><br /><br />(三)断点续传内核的实现<br />主要用了6个类，包括一个测试类。<br />SiteFileFetch.java负责整个文件的抓取，控制内部线程(FileSplitterFetch类)。<br />FileSplitterFetch.java负责部分文件的抓取。<br />FileAccess.java负责文件的存储。<br />SiteInfoBean.java要抓取的文件的信息，如文件保存的目录，名字，抓取文件的URL等。<br />Utility.java工具类，放一些简单的方法。<br />TestMethod.java测试类。<br /><br /><br />下面是源程序： <br />/*<br />**SiteFileFetch.java<br />*/<br />package NetFox;<br />import java.io.*;<br />import java.net.*;<br /><br /><br />public class SiteFileFetch extends Thread {<br /><br /><br />SiteInfoBean siteInfoBean = null; //文件信息Bean<br />long[] nStartPos; //开始位置<br />long[] nEndPos; //结束位置<br />FileSplitterFetch[] fileSplitterFetch; //子线程对象<br />long nFileLength; //文件长度<br />boolean bFirst = true; //是否第一次取文件<br />boolean bStop = false; //停止标志<br />File tmpFile; //文件下载的临时信息<br />DataOutputStream output; //输出到文件的输出流<br /><br /><br />public SiteFileFetch(SiteInfoBean bean) throws IOException<br />{<br />siteInfoBean = bean;<br />//tmpFile = File.createTempFile ("zhong","1111",new File(bean.getSFilePath()));<br />tmpFile = new File(bean.getSFilePath()+File.separator + bean.getSFileName()+".info");<br />if(tmpFile.exists ())<br />{<br />bFirst = false;<br />read_nPos();<br />}<br />else<br />{<br />nStartPos = new long[bean.getNSplitter()];<br />nEndPos = new long[bean.getNSplitter()];<br />}<br /><br /><br /><br />}<br /><br /><br />public void run()<br />{<br />//获得文件长度<br />//分割文件<br />//实例FileSplitterFetch<br />//启动FileSplitterFetch线程<br />//等待子线程返回<br />try{<br />if(bFirst)<br />{<br />nFileLength = getFileSize();<br />if(nFileLength == -1)<br />{<br />System.err.println("File Length is not known!");<br />}<br />else if(nFileLength == -2)<br />{<br />System.err.println("File is not access!");<br />}<br />else<br />{<br />for(int i=0;i&lt;nStartPos.length;i++)<br />{<br />nStartPos[i] = (long)(i*(nFileLength/nStartPos.length));<br />}<br />for(int i=0;i&lt;nEndPos.length-1;i++)<br />{<br />nEndPos[i] = nStartPos[i+1];<br />}<br />nEndPos[nEndPos.length-1] = nFileLength;<br />}<br />}<br /><br /><br />//启动子线程<br />fileSplitterFetch = new FileSplitterFetch[nStartPos.length];<br />for(int i=0;i&lt;nStartPos.length;i++)<br />{<br />fileSplitterFetch[i] = new FileSplitterFetch(siteInfoBean.getSSiteURL(),<br />siteInfoBean.getSFilePath() + File.separator + siteInfoBean.getSFileName(),<br />nStartPos[i],nEndPos[i],i);<br />Utility.log("Thread " + i + " , nStartPos = " + nStartPos[i] + ", nEndPos = " + nEndPos[i]);<br />fileSplitterFetch[i].start();<br />}<br />// fileSplitterFetch[nPos.length-1] = new FileSplitterFetch(siteInfoBean.getSSiteURL(),<br />siteInfoBean.getSFilePath() + File.separator + siteInfoBean.getSFileName(),nPos[nPos.length-1],nFileLength,nPos.length-1);<br />// Utility.log("Thread " + (nPos.length-1) + " , nStartPos = " + nPos[nPos.length-1] + ",<br />nEndPos = " + nFileLength);<br />// fileSplitterFetch[nPos.length-1].start();<br /><br /><br />//等待子线程结束<br />//int count = 0;<br />//是否结束while循环<br />boolean breakWhile = false;<br /><br /><br />while(!bStop)<br />{<br />write_nPos();<br />Utility.sleep(500);<br />breakWhile = true;<br /><br /><br />for(int i=0;i&lt;nStartPos.length;i++)<br />{<br />if(!fileSplitterFetch[i].bDownOver)<br />{<br />breakWhile = false;<br />break;<br />}<br />}<br />if(breakWhile)<br />break;<br /><br /><br />//count++;<br />//if(count&gt;4)<br />// siteStop();<br />}<br /><br /><br />System.err.println("文件下载结束！");<br />}<br />catch(Exception e){e.printStackTrace ();}<br />}<br /><br /><br />//获得文件长度<br />public long getFileSize()<br />{<br />int nFileLength = -1;<br />try{<br />URL url = new URL(siteInfoBean.getSSiteURL());<br />HttpURLConnection httpConnection = (HttpURLConnection)url.openConnection ();<br />httpConnection.setRequestProperty("User-Agent","NetFox");<br /><br /><br />int responseCode=httpConnection.getResponseCode();<br />if(responseCode&gt;=400)<br />{<br />processErrorCode(responseCode);<br />return -2; //-2 represent access is error<br />}<br /><br /><br />String sHeader;<br /><br /><br />for(int i=1;;i++)<br />{<br />//DataInputStream in = new DataInputStream(httpConnection.getInputStream ());<br />//Utility.log(in.readLine());<br />sHeader=httpConnection.getHeaderFieldKey(i);<br />if(sHeader!=null)<br />{<br />if(sHeader.equals("Content-Length"))<br />{<br />nFileLength = Integer.parseInt(httpConnection.getHeaderField(sHeader));<br />break;<br />}<br />}<br />else<br />break;<br />}<br />}<br />catch(IOException e){e.printStackTrace ();}<br />catch(Exception e){e.printStackTrace ();}<br /><br /><br />Utility.log(nFileLength);<br /><br /><br />return nFileLength;<br />}<br /><br /><br />//保存下载信息（文件指针位置）<br />private void write_nPos()<br />{<br />try{<br />output = new DataOutputStream(new FileOutputStream(tmpFile));<br />output.writeInt(nStartPos.length);<br />for(int i=0;i&lt;nStartPos.length;i++)<br />{<br />// output.writeLong(nPos[i]);<br />output.writeLong(fileSplitterFetch[i].nStartPos);<br />output.writeLong(fileSplitterFetch[i].nEndPos);<br />}<br />output.close();<br />}<br />catch(IOException e){e.printStackTrace ();}<br />catch(Exception e){e.printStackTrace ();}<br />}<br /><br /><br />//读取保存的下载信息（文件指针位置）<br />private void read_nPos()<br />{<br />try{<br />DataInputStream input = new DataInputStream(new FileInputStream(tmpFile));<br />int nCount = input.readInt();<br />nStartPos = new long[nCount];<br />nEndPos = new long[nCount];<br />for(int i=0;i&lt;nStartPos.length;i++)<br />{<br />nStartPos[i] = input.readLong();<br />nEndPos[i] = input.readLong();<br />}<br />input.close();<br />}<br />catch(IOException e){e.printStackTrace ();}<br />catch(Exception e){e.printStackTrace ();}<br />}<br /><br /><br />private void processErrorCode(int nErrorCode)<br />{<br />System.err.println("Error Code : " + nErrorCode);<br />}<br /><br /><br />//停止文件下载<br />public void siteStop()<br />{<br />bStop = true;<br />for(int i=0;i&lt;nStartPos.length;i++)<br />fileSplitterFetch[i].splitterStop();<br /><br /><br />}<br />}<br />/*<br />**FileSplitterFetch.java<br />*/<br />package NetFox;<br /><br /><br />import java.io.*;<br />import java.net.*;<br /><br /><br />public class FileSplitterFetch extends Thread {<br /><br /><br />String sURL; //File URL<br />long nStartPos; //File Snippet Start Position<br />long nEndPos; //File Snippet End Position<br />int nThreadID; //Thread's ID<br />boolean bDownOver = false; //Downing is over<br />boolean bStop = false; //Stop identical<br />FileAccessI fileAccessI = null; //File Access interface<br /><br /><br />public FileSplitterFetch(String sURL,String sName,long nStart,long nEnd,int id) throws IOException<br />{<br />this.sURL = sURL;<br />this.nStartPos = nStart;<br />this.nEndPos = nEnd;<br />nThreadID = id;<br />fileAccessI = new FileAccessI(sName,nStartPos);<br />}<br /><br /><br />public void run()<br />{<br />while(nStartPos &lt; nEndPos &amp;&amp; !bStop)<br />{<br /><br /><br />try{<br />URL url = new url(/sURL);<br />HttpURLConnection httpConnection = (HttpURLConnection)url.openConnection ();<br />httpConnection.setRequestProperty("User-Agent","NetFox");<br />String sProperty = "bytes="+nStartPos+"-";<br />httpConnection.setRequestProperty("RANGE",sProperty);<br />Utility.log(sProperty);<br /><br /><br />InputStream input = httpConnection.getInputStream();<br />//logResponseHead(httpConnection);<br /><br /><br />byte[] b = new byte[1024];<br />int nRead;<br />while((nRead=input.read(b,0,1024)) &gt; 0 &amp;&amp; nStartPos &lt; nEndPos &amp;&amp; !bStop)<br />{<br />nStartPos += fileAccessI.write(b,0,nRead);<br />//if(nThreadID == 1)<br />// Utility.log("nStartPos = " + nStartPos + ", nEndPos = " + nEndPos);<br />}<br /><br /><br />Utility.log("Thread " + nThreadID + " is over!");<br />bDownOver = true;<br />//nPos = fileAccessI.write (b,0,nRead);<br />}<br />catch(Exception e){e.printStackTrace ();}<br />}<br />}<br /><br /><br />//打印回应的头信息<br />public void logResponseHead(HttpURLConnection con)<br />{<br />for(int i=1;;i++)<br />{<br />String header=con.getHeaderFieldKey(i);<br />if(header!=null)<br />//responseHeaders.put(header,httpConnection.getHeaderField(header));<br />Utility.log(header+" : "+con.getHeaderField(header));<br />else<br />break;<br />}<br />}<br /><br /><br />public void splitterStop()<br />{<br />bStop = true;<br />}<br /><br /><br />}<br /><br /><br />/*<br />**FileAccess.java<br />*/<br />package NetFox;<br />import java.io.*;<br /><br /><br />public class FileAccessI implements Serializable{<br /><br /><br />RandomAccessFile oSavedFile;<br />long nPos;<br /><br /><br />public FileAccessI() throws IOException<br />{<br />this("",0);<br />}<br /><br /><br />public FileAccessI(String sName,long nPos) throws IOException<br />{<br />oSavedFile = new RandomAccessFile(sName,"rw");<br />this.nPos = nPos;<br />oSavedFile.seek(nPos);<br />}<br /><br /><br />public synchronized int write(byte[] b,int nStart,int nLen)<br />{<br />int n = -1;<br />try{<br />oSavedFile.write(b,nStart,nLen);<br />n = nLen;<br />}<br />catch(IOException e)<br />{<br />e.printStackTrace ();<br />}<br /><br /><br />return n;<br />}<br /><br /><br />}<br /><br /><br />/*<br />**SiteInfoBean.java<br />*/<br />package NetFox;<br /><br /><br />public class SiteInfoBean {<br /><br /><br />private String sSiteURL; //Site's URL<br />private String sFilePath; //Saved File's Path<br />private String sFileName; //Saved File's Name<br />private int nSplitter; //Count of Splited Downloading File<br /><br /><br />public SiteInfoBean()<br />{<br />//default value of nSplitter is 5<br />this("","","",5);<br />}<br /><br /><br />public SiteInfoBean(String sURL,String sPath,String sName,int nSpiltter)<br />{<br />sSiteURL= sURL;<br />sFilePath = sPath;<br />sFileName = sName;<br />this.nSplitter = nSpiltter;<br /><br /><br />}<br /><br /><br />public String getSSiteURL()<br />{<br />return sSiteURL;<br />}<br /><br /><br />public void setSSiteURL(String value)<br />{<br />sSiteURL = value;<br />}<br /><br /><br />public String getSFilePath()<br />{<br />return sFilePath;<br />}<br /><br /><br />public void setSFilePath(String value)<br />{<br />sFilePath = value;<br />}<br /><br /><br />public String getSFileName()<br />{<br />return sFileName;<br />}<br /><br /><br />public void setSFileName(String value)<br />{<br />sFileName = value;<br />}<br /><br /><br />public int getNSplitter()<br />{<br />return nSplitter;<br />}<br /><br /><br />public void setNSplitter(int nCount)<br />{<br />nSplitter = nCount;<br />}<br />}<br /><br /><br />/*<br />**Utility.java<br />*/<br />package NetFox;<br /><br /><br />public class Utility {<br /><br /><br />public Utility()<br />{<br /><br /><br />}<br /><br /><br />public static void sleep(int nSecond)<br />{<br />try{<br />Thread.sleep(nSecond);<br />}<br />catch(Exception e)<br />{<br />e.printStackTrace ();<br />}<br />}<br /><br /><br />public static void log(String sMsg)<br />{<br />System.err.println(sMsg);<br />}<br /><br /><br />public static void log(int sMsg)<br />{<br />System.err.println(sMsg);<br />}<br />}<br /><br /><br />/*<br />**TestMethod.java<br />*/<br />package NetFox;<br /><br /><br />public class TestMethod {<br /><br /><br />public TestMethod()<br />{ ///xx/weblogic60b2_win.exe<br />try{<br />SiteInfoBean bean = new SiteInfoBean("http://localhost/xx/weblogic60b2_win.exe","L:\\temp","weblogic60b2_win.exe",5);<br />//SiteInfoBean bean = new SiteInfoBean("http://localhost:8080/down.zip","L:\\temp","weblogic60b2_win.exe",5);<br />SiteFileFetch fileFetch = new SiteFileFetch(bean);<br />fileFetch.start();<br />}<br />catch(Exception e){e.printStackTrace ();}<br /><br /><br />}<br /><br /><br />public static void main(String[] args)<br />{<br />new TestMethod();<br />}<br />}<br /></p>
<img src ="http://www.blogjava.net/19851985lili/aggbug/93514.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/19851985lili/" target="_blank">☜♥☞MengChuChen</a> 2007-01-12 19:19 <a href="http://www.blogjava.net/19851985lili/articles/93514.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java的秘密武器：使用全屏幕模式</title><link>http://www.blogjava.net/19851985lili/articles/93181.html</link><dc:creator>☜♥☞MengChuChen</dc:creator><author>☜♥☞MengChuChen</author><pubDate>Thu, 11 Jan 2007 07:14:00 GMT</pubDate><guid>http://www.blogjava.net/19851985lili/articles/93181.html</guid><wfw:comment>http://www.blogjava.net/19851985lili/comments/93181.html</wfw:comment><comments>http://www.blogjava.net/19851985lili/articles/93181.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/19851985lili/comments/commentRss/93181.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/19851985lili/services/trackbacks/93181.html</trackback:ping><description><![CDATA[什么时候会用到全屏幕模式？ <br /><br />　　也许用到的机会很少，但JDK还是为我们提供了这个的功能。像许多软件中的打印预览功能，还有某些文本编辑器中为了获得更大的编辑画面，也用到了全屏幕模式，如果你有兴趣写一个像ACDSee这样的软件，使用全屏幕模式可以让用户看到更大的图片画面。 <br /><br />　　如何使用全屏幕模式？ <br /><br />　　关键是java.awt.*里面的两个与显示设备有关的类：GraphicsEnvironment和GraphicsDevice。 <br /><br />　　GraphicsEnvironment为Java应用程序提供了特定平台的 GraphicsDevice 对象和 Font 对象集合。这些GraphicsDevice可以是各种本机和远端机器的资源，如屏幕、打印机或者是Image Buffer,甚至是Graphics2D绘图方法的目标对象。 <br /><br />　　而GraphicsDevice就是指特定的图形环境了，如屏幕和打印设备等。这样，我们就可以用GraphicsDevice来操纵屏幕了。GraphicsDevice提供的setFullScreenWindow()方法就是设置全屏幕用的。 <br /><br />　　由于GraphicsEnvironment的构造器是受保护的(protected)，我们不能直接构造一个GraphicsEnvironment对象来获得GraphicsDevice对象。幸好它提供了getLocalGraphicsEnvironment()方法，用来获得一个GraphicsEnvironment实例： <br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#e6e4dd" border="1"><tbody><tr><td>GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); </td></tr></tbody></table><br />　　有了GraphicsEnvironment可以调用getDefaultScreenDevice方法获得当前的屏幕设备了： <br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#e6e4dd" border="1"><tbody><tr><td>GraphicsDevice gd = ge.getDefaultScreenDevice(); </td></tr></tbody></table><br />　　自己动手体验一下 <br /><br />　　有了上面的简介，写一个实例来体验一下吧： <br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#e6e4dd" border="1"><tbody><tr><td>import java.awt.*; <br />import java.awt.event.*; <br />import javax.swing.*; <br /><br />public class FullScreenTest <br />{ <br />　public static void main(String[] args) <br />　{ <br />　　GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); <br />　　GraphicsDevice gd = ge.getDefaultScreenDevice(); <br />　　FullScreenWindow myWindow = new FullScreenWindow(); <br />　　if ( gd.isFullScreenSupported() ) <br />　　　gd.setFullScreenWindow(myWindow); <br />　　else <br />　　　System.out.println("Unsupported full screen."); <br />　} <br />} <br /><br />class FullScreenWindow extends JWindow <br />{ <br />　public FullScreenWindow() <br />　{ <br />　　this.addMouseListener(new MouseAdapter() <br />　　{ <br />　　　public void mousePressed(MouseEvent evt) <br />　　　{ <br />　　　　quit(); <br />　　　} <br />　　}); <br />　} <br /><br />　public void quit() <br />　{ <br />　　this.dispose(); <br />　} <br /><br />　public void paint(Graphics g) <br />　{ <br />　　g.setFont(new Font("Arial",Font.BOLD,30)); <br />　　g.setColor(Color.RED); <br />　　g.drawString("这是全屏幕模式",100,100); <br />　} <br />}</td></tr></tbody></table><img src ="http://www.blogjava.net/19851985lili/aggbug/93181.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/19851985lili/" target="_blank">☜♥☞MengChuChen</a> 2007-01-11 15:14 <a href="http://www.blogjava.net/19851985lili/articles/93181.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>