﻿<?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-decorator</title><link>http://www.blogjava.net/decorator/</link><description /><language>zh-cn</language><lastBuildDate>Fri, 17 Apr 2026 22:38:19 GMT</lastBuildDate><pubDate>Fri, 17 Apr 2026 22:38:19 GMT</pubDate><ttl>60</ttl><item><title>HttpAsyncClient</title><link>http://www.blogjava.net/decorator/archive/2012/11/26/391950.html</link><dc:creator>庄主游骥</dc:creator><author>庄主游骥</author><pubDate>Mon, 26 Nov 2012 02:46:00 GMT</pubDate><guid>http://www.blogjava.net/decorator/archive/2012/11/26/391950.html</guid><wfw:comment>http://www.blogjava.net/decorator/comments/391950.html</wfw:comment><comments>http://www.blogjava.net/decorator/archive/2012/11/26/391950.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/decorator/comments/commentRss/391950.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/decorator/services/trackbacks/391950.html</trackback:ping><description><![CDATA[<div><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; text-align: left; background-color: #fafafa; "><font class="Apple-style-span" color="#404040" face="arial, sans-serif, verdana, helvetica"><span class="Apple-style-span" style="line-height: 25px;">HttpAsyncClient 是一个异步的 HTTP 客户端开发包，基于 HttpCore NIO 和 HttpClient 组件。</span></font><br /><font class="Apple-style-span" color="#404040" face="arial, sans-serif, verdana, helvetica"><span class="Apple-style-span" style="line-height: 25px;">HttpAsyncClient 的出现并不是为了替换 HttpClient，而是作为一个补充用于需要大量并发连接，对性能要求非常高的基于HTTP的原生数据通信，而且提供了事件驱动的 API。<br /><br /></span></font>代码示例：<br /></p><div style="border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: #cccccc; border-right-color: #cccccc; border-bottom-color: #cccccc; border-left-color: #cccccc; padding-right: 5px; padding-bottom: 4px; padding-left: 4px; padding-top: 4px; width: 98%; word-break: break-all; background-color: #eeeeee; "><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><font class="Apple-style-span" color="#0000ff" face="arial, sans-serif, verdana, helvetica" size="2"><span class="Apple-style-span" style="line-height: 25px;">&nbsp; &nbsp; &nbsp;&nbsp;</span></font><span style="line-height: 25px; background-color: #fafafa; white-space: pre; ">	</span><span class="Apple-style-span" style="line-height: 25px; background-color: #fafafa; ">public Vector&lt;Long&gt; Gets(List&lt;String&gt; urls)</span></div><div><div><span style="line-height: 25px;"><span style="white-space:pre">			</span>throws IOReactorException, InterruptedException {</span></div><div><span style="white-space: pre; line-height: 25px;">	</span></div><div><span style="line-height: 25px;"><span style="white-space:pre">		</span>List&lt;HttpGet&gt; requests = new ArrayList&lt;HttpGet&gt;();</span></div><div><span style="line-height: 25px;"><span style="white-space:pre">		</span>for (String url : urls) {</span></div><div><span style="line-height: 25px;"><span style="white-space:pre">			</span>HttpGet get = new HttpGet(url);</span></div><div><span style="line-height: 25px;"><span style="white-space:pre">			</span>requests.add(get);</span></div><div><span style="line-height: 25px;"><span style="white-space:pre">		</span>}</span></div><div><span style="white-space: pre; line-height: 25px;">		</span></div><div><span style="line-height: 25px;"><span style="white-space:pre">		</span>final Vector&lt;Long&gt; dataPackages = new Vector&lt;Long&gt;();</span></div><div><span style="line-height: 25px;"><span style="white-space:pre">		</span>HttpAsyncClient httpclient = new DefaultHttpAsyncClient();</span></div><div><span style="line-height: 25px;"><span style="white-space:pre">		</span>httpclient.getParams().setIntParameter("http.socket.timeout", 5000)</span></div><div><span style="line-height: 25px;"><span style="white-space:pre">				</span>.setIntParameter("http.connection.timeout", 5000)</span></div><div><span style="line-height: 25px;"><span style="white-space:pre">				</span>.setIntParameter("http.socket.buffer-size", 8192)</span></div><div><span style="line-height: 25px;"><span style="white-space:pre">				</span>.setBooleanParameter("http.tcp.nodelay", true);</span></div><div><span style="line-height: 25px;"><span style="white-space:pre">		</span>final CountDownLatch latch = new CountDownLatch(requests.size());</span></div><div><span style="line-height: 25px;"><span style="white-space:pre">		</span>httpclient.start();</span></div><div><span style="line-height: 25px;"><span style="white-space:pre">		</span>try {</span></div><div><span style="line-height: 25px;"><span style="white-space:pre">			</span>for (final HttpGet request : requests) {</span></div><div><span style="line-height: 25px;"><span style="white-space:pre">				</span>httpclient.execute(request, new FutureCallback&lt;HttpResponse&gt;() {</span></div><div><span style="line-height: 25px;"><br /></span></div><div><span style="line-height: 25px;"><span style="white-space:pre">					</span>@Override</span></div><div><span style="line-height: 25px;"><span style="white-space:pre">					</span>public void completed(HttpResponse result) {</span></div><div><span style="line-height: 25px;"><span style="white-space:pre">						</span>String statInfo = "";</span></div><div><span style="line-height: 25px;"><span style="white-space:pre">						</span>try {</span></div><div><span style="line-height: 25px;"><span style="white-space:pre">							</span>statInfo = result.getFirstHeader("statInfo").getValue();</span></div><div><span style="line-height: 25px;"><span style="white-space:pre">							</span>if (statInfo != null) {</span></div><div><span style="line-height: 25px;"><span style="white-space:pre">								</span>Long size = Long.parseLong(statInfo.split(",")[0].split(":")[1]);</span></div><div><span style="line-height: 25px;"><span style="white-space:pre">								</span>dataPackages.add(size);</span></div><div><span style="line-height: 25px;"><span style="white-space:pre">							</span>}</span></div><div><span style="line-height: 25px;"><span style="white-space:pre">						</span>} catch (Exception e) {</span></div><div><span style="line-height: 25px;"><span style="white-space:pre">							</span>System.out.println(e);</span></div><div><span style="line-height: 25px;"><span style="white-space:pre">							</span>System.out.println(statInfo);</span></div><div><span style="line-height: 25px;"><span style="white-space:pre">						</span>}</span></div><div><span style="line-height: 25px;"><span style="white-space:pre">						</span>latch.countDown();</span></div><div><span style="line-height: 25px;"><span style="white-space:pre">					</span>}</span></div><div><span style="line-height: 25px;"><br /></span></div><div><span style="line-height: 25px;"><span style="white-space:pre">					</span>@Override</span></div><div><span style="line-height: 25px;"><span style="white-space:pre">					</span>public void failed(Exception ex) {</span></div><div><span style="white-space: pre; line-height: 25px;">						</span></div><div><span style="line-height: 25px;"><span style="white-space:pre">						</span>latch.countDown();</span></div><div><span style="line-height: 25px;"><span style="white-space:pre">					</span>}</span></div><div><span style="line-height: 25px;"><br /></span></div><div><span style="line-height: 25px;"><span style="white-space:pre">					</span>@Override</span></div><div><span style="line-height: 25px;"><span style="white-space:pre">					</span>public void cancelled() {</span></div><div><span style="white-space: pre; line-height: 25px;">						</span></div><div><span style="line-height: 25px;"><span style="white-space:pre">						</span>latch.countDown();</span></div><div><span style="line-height: 25px;"><span style="white-space:pre">					</span>}</span></div><div><span style="line-height: 25px;"><span style="white-space:pre">				</span>});</span></div><div><span style="line-height: 25px;"><span style="white-space:pre">			</span>}</span></div><div><span style="line-height: 25px;"><span style="white-space:pre">			</span>latch.await();</span></div><div><span style="line-height: 25px;"><span style="white-space:pre">		</span>} finally {</span></div><div><span style="line-height: 25px;"><span style="white-space:pre">			</span>httpclient.shutdown();</span></div><div><span style="line-height: 25px;"><span style="white-space:pre">		</span>}</span></div><div><span style="line-height: 25px;"><span style="white-space:pre">		</span>return dataPackages;</span></div><div><span style="line-height: 25px;"><span style="white-space: pre; ">	</span>}</span></div></div><p>&nbsp;</p><span style="color: #404040; font-family: arial, sans-serif, verdana, helvetica; line-height: 25px; background-color: #fafafa; "><br />依赖的pom，</span>httpasyncclient已经有4.0-beta3版本了<div><div>&lt;dependency&gt;</div><div>&nbsp;&nbsp;&nbsp;&nbsp;&lt;groupId&gt;org.apache.httpcomponents&lt;/groupId&gt;</div><div>&nbsp;&nbsp;&nbsp;&nbsp;&lt;artifactId&gt;httpasyncclient&lt;/artifactId&gt;</div><div>&nbsp;&nbsp;&nbsp;&nbsp;&lt;version&gt;4.0-beta1&lt;/version&gt;</div><div>&lt;/dependency&gt;</div><div>&lt;dependency&gt;</div><div>&nbsp;&nbsp;&nbsp;&nbsp;&lt;groupId&gt;org.apache.httpcomponents&lt;/groupId&gt;</div><div>&nbsp;&nbsp;&nbsp;&nbsp;&lt;artifactId&gt;httpclient&lt;/artifactId&gt;</div><div>&nbsp;&nbsp;&nbsp;&nbsp;&lt;version&gt;4.2-beta1&lt;/version&gt;</div><div>&lt;/dependency&gt;</div></div><span style="color: #404040; font-family: arial, sans-serif, verdana, helvetica; line-height: 25px; background-color: #fafafa; "><br /><br /></span></div><img src ="http://www.blogjava.net/decorator/aggbug/391950.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/decorator/" target="_blank">庄主游骥</a> 2012-11-26 10:46 <a href="http://www.blogjava.net/decorator/archive/2012/11/26/391950.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>web.xml页面配置</title><link>http://www.blogjava.net/decorator/archive/2012/11/13/391250.html</link><dc:creator>庄主游骥</dc:creator><author>庄主游骥</author><pubDate>Tue, 13 Nov 2012 03:37:00 GMT</pubDate><guid>http://www.blogjava.net/decorator/archive/2012/11/13/391250.html</guid><wfw:comment>http://www.blogjava.net/decorator/comments/391250.html</wfw:comment><comments>http://www.blogjava.net/decorator/archive/2012/11/13/391250.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/decorator/comments/commentRss/391250.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/decorator/services/trackbacks/391250.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: web.xml页面配置参数详解&nbsp;  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;加载顺序与它们在 web.xml 文件中的先后顺序无关。即不会因为 filter 写在 listener 的前面而会先加载 filter。最终得出的结论是：listener -&gt; filter -&gt; servlet。  &nbsp;同时还存在着这样一种配置节...&nbsp;&nbsp;<a href='http://www.blogjava.net/decorator/archive/2012/11/13/391250.html'>阅读全文</a><img src ="http://www.blogjava.net/decorator/aggbug/391250.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/decorator/" target="_blank">庄主游骥</a> 2012-11-13 11:37 <a href="http://www.blogjava.net/decorator/archive/2012/11/13/391250.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>gc 对象晋升old区的一些规则总结</title><link>http://www.blogjava.net/decorator/archive/2012/10/23/390125.html</link><dc:creator>庄主游骥</dc:creator><author>庄主游骥</author><pubDate>Tue, 23 Oct 2012 12:52:00 GMT</pubDate><guid>http://www.blogjava.net/decorator/archive/2012/10/23/390125.html</guid><wfw:comment>http://www.blogjava.net/decorator/comments/390125.html</wfw:comment><comments>http://www.blogjava.net/decorator/archive/2012/10/23/390125.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/decorator/comments/commentRss/390125.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/decorator/services/trackbacks/390125.html</trackback:ping><description><![CDATA[<div><p style="margin-top: 0px; margin-right: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; list-style-type: none; list-style-position: initial; list-style-image: initial; word-wrap: normal; word-break: normal; color: #464646; font-family: simsun; font-size: 15px; text-align: left; background-color: #bcd3e5; "><div><div>ygc做步骤为：清空eden+from中所有no ref的对象占用的内存</div><div>将eden+from中的所有存活的对象copy到to中</div><div>在这个过程中一些对象将晋升到old中:</div><div>--to放不下的</div><div>--存活次数超过tenuring threshold的</div><div>重新计算Tenuring Threshold<br /><br />然后谈谈MaxTenuringThreshold这个参数用于控制对象能经历多少次Minor GC才晋升到旧生代，<span style="word-wrap: normal; word-break: normal; color: #ff0000; ">默认值是15</span>，那是不是意味着对象要经历15次minor gc才晋升到旧生代呢，来看下面的一个例子。</div></div><br />public&nbsp;class GCTenuringThreshold{<br />public static void main(String[] args) throws Exception{<br />GCMemoryObject object1=new GCMemoryObject(2);<br />GCMemoryObject object2=new GCMemoryObject(8);<br />GCMemoryObject object3=new GCMemoryObject(8);<br />GCMemoryObject object4=new GCMemoryObject(8);<br /><span style="word-wrap: normal; word-break: normal; color: #ed1c24; ">object2=null;</span><br style="color: #ed1c24; " /><span style="word-wrap: normal; word-break: normal; color: #ed1c24; ">object3=null;</span><br />GCMemoryObject object5=new GCMemoryObject(8);<br />Thread.sleep(4000);<br />object2=new GCMemoryObject(8);<br />object3=new GCMemoryObject(8);<br /><span style="word-wrap: normal; word-break: normal; color: #ed1c24; ">object2=null;</span><br style="color: #ed1c24; " /><span style="word-wrap: normal; word-break: normal; color: #ed1c24; ">object3=null;</span><br style="color: #ed1c24; " /><span style="word-wrap: normal; word-break: normal; color: #ed1c24; ">object5=null;</span><br />GCMemoryObject object6=new GCMemoryObject(8);<br />Thread.sleep(5000);<br />}<br />}<br />class GCMemoryObject{<br />private byte[] bytes=null;<br />public GCMemoryObject(int multi){<br />bytes=new byte[1024*256*multi];<br />}<br />}<br /><br />以-Xms20M &#8211;Xmx20M &#8211;Xmn10M &#8211;XX:+UseSerialGC参数执行以上代码，通过<span style="word-wrap: normal; word-break: normal; color: #ff0000; ">jstat -gcutil [pid] 1000 10的方式查看执行效果</span>，很惊讶执行结果竟然是在第二次minor GC的时候object1就被晋升到old中了，而可以肯定的是这个时候<span style="word-wrap: normal; word-break: normal; color: #ff0000; ">to space空间是充足的，也就是说并不是在to space空间充足的情况下，对象一定要经历MaxTenuringThreshold次才会晋升到old，</span>那具体规则到底是怎么样的呢，翻看 Hotspot 6 update 21中SerialGC的实现，可以看到在每次minor GC后，会对这个存活周期的阈值做计算，计算的代码如下：<br /><br />size_t desired_survivor_size = (size_t)((((double) survivor_capacity)*TargetSurvivorRatio)/100);<br />size_t total = 0;<br />int age = 1;<br />assert(sizes[0] == 0, "no objects with age zero should be recorded");<br />while (age total += sizes[age];<br />// check if including objects of age 'age' made us pass the desired<br />// size, if so 'age' is the new threshold<br />if (total &gt; desired_survivor_size) break;<br />age++;<br />}<br />int result = age<br />其中desired_survivor_size是指survivor space/2，从上面的代码可看出，在计算存活周期这个阈值时，<span style="word-wrap: normal; word-break: normal; color: #ff0000; ">hotspot会遍历所有age的table，并对其所占用的大小进行累积，当累积的大 小超过了survivor space的一半时，则以这个age作为新的存活周期阈值，最后取age和MaxTenuringThreshold中更小的一个值。</span></p><p style="margin-top: 0px; margin-right: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; list-style-type: none; list-style-position: initial; list-style-image: initial; word-wrap: normal; word-break: normal; color: #464646; font-family: simsun; font-size: 15px; text-align: left; background-color: #bcd3e5; ">按照这样的规则，上面的运行效果就可验证了，第一次minor gc的时候存活周期的阈值为MaxTenuringThreshold，minor gc结束后计算出新的阈值为1，在第二次minor gc时object 1的age已经是1了，因此object1被晋升到了旧生代。</p><p style="margin-top: 0px; margin-right: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; list-style-type: none; list-style-position: initial; list-style-image: initial; word-wrap: normal; word-break: normal; color: #464646; font-family: simsun; font-size: 15px; text-align: left; background-color: #bcd3e5; "><span style="word-wrap: normal; word-break: normal; color: #ff0000; ">这个规则对于Serial GC以及ParNew GC（但对于开启了UseAdaptiveSizePolicy的ParNew GC而言也无效，默认是不开启的）均有效</span>，对于PS（Parallel Scavenge） GC而言，<span style="word-wrap: normal; word-break: normal; color: #ff0000; ">在默认的情况下第一次以InitialTenuringThreshold<wbr>（默认为7）为准，之后在每次minor GC后均会动态计算，</span>规则比上面的复杂，在设置-XX:-UseAdaptiveSizePolicy后，则以 MaxTenuringThrehsold为准，并且不会重新计算，会是恒定值。</p><p style="margin-top: 0px; margin-right: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; list-style-type: none; list-style-position: initial; list-style-image: initial; word-wrap: normal; word-break: normal; color: #464646; font-family: simsun; font-size: 15px; text-align: left; background-color: #bcd3e5; ">如希望跟踪每次minor GC后新的存活周期的阈值，可在启动参数上增加：<span style="word-wrap: normal; word-break: normal; color: #ff0000; ">-XX:+PrintTenuringDistributio<wbr>n</span>，输出的信息中的：<br />Desired survivor size 1048576 bytes, new threshold 7 (max 15)<br />new threshold 7即标识新的存活周期的阈值为7。</p></div><img src ="http://www.blogjava.net/decorator/aggbug/390125.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/decorator/" target="_blank">庄主游骥</a> 2012-10-23 20:52 <a href="http://www.blogjava.net/decorator/archive/2012/10/23/390125.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java序列化机制</title><link>http://www.blogjava.net/decorator/archive/2012/09/03/386821.html</link><dc:creator>庄主游骥</dc:creator><author>庄主游骥</author><pubDate>Sun, 02 Sep 2012 16:48:00 GMT</pubDate><guid>http://www.blogjava.net/decorator/archive/2012/09/03/386821.html</guid><wfw:comment>http://www.blogjava.net/decorator/comments/386821.html</wfw:comment><comments>http://www.blogjava.net/decorator/archive/2012/09/03/386821.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/decorator/comments/commentRss/386821.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/decorator/services/trackbacks/386821.html</trackback:ping><description><![CDATA[<div><p style="margin-top: 3px; margin-bottom: 17px; font-family: Arial, Helvetica, FreeSans, Luxi-sans, 'Nimbus Sans L', sans-serif; font-size: 12px; line-height: normal; background-color: #ffffff; ">原文链接：<a href="http://java.sun.com/developer/technicalArticles/Programming/serialization/">http://java.sun.com/developer/technicalArticles/Programming/serialization/<br /></a><br />We all know the Java platform allows us to create reusable objects in memory. However, all of those objects exist only as long as the Java virtual machine<a href="http://java.sun.com/developer/technicalArticles/Programming/serialization/#TJVM" style="color: #666666; "><sup>1</sup></a>&nbsp;remains running. It would be nice if the objects we create could exist beyond the lifetime of the virtual machine, wouldn't it? Well, with object serialization, you can flatten your objects and reuse them in powerful ways.</p><p style="margin-top: 3px; margin-bottom: 17px; font-family: Arial, Helvetica, FreeSans, Luxi-sans, 'Nimbus Sans L', sans-serif; font-size: 12px; line-height: normal; background-color: #ffffff; ">Object serialization is the process of saving an object's state to a sequence of bytes, as well as the process of rebuilding those bytes into a live object at some future time. The Java Serialization API provides a standard mechanism for developers to handle object serialization. The API is small and easy to use, provided the classes and methods are understood.</p><p style="margin-top: 3px; margin-bottom: 17px; font-family: Arial, Helvetica, FreeSans, Luxi-sans, 'Nimbus Sans L', sans-serif; font-size: 12px; line-height: normal; background-color: #ffffff; ">Throughout this article, we'll examine how to persist your Java objects, starting with the basics and proceeding to the more advanced concepts. We'll learn three different ways to perform serialization -- using the default protocol, customizing the default protocol, and creating our own protocol -- and we'll investigate concerns that arise with any persistence scheme such as object caching, version control, and performance issues.</p><p style="margin-top: 3px; margin-bottom: 17px; font-family: Arial, Helvetica, FreeSans, Luxi-sans, 'Nimbus Sans L', sans-serif; font-size: 12px; line-height: normal; background-color: #ffffff; ">By the conclusion of this article, you should have a solid comprehension of that powerful yet sometimes poorly understood Java API.</p><h3>First Things First: The Default Mechanism</h3><p style="margin-top: 2px; margin-bottom: 17px; font-family: Arial, Helvetica, FreeSans, Luxi-sans, 'Nimbus Sans L', sans-serif; font-size: 12px; line-height: normal; background-color: #ffffff; ">Let's start with the basics. To persist an object in Java, we must have a persistent object. An object is marked serializable by implementing the<code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">java.io.Serializable</code>&nbsp;interface, which signifies to the underlying API that the object can be flattened into bytes and subsequently inflated in the future.</p><p style="margin-top: 3px; margin-bottom: 17px; font-family: Arial, Helvetica, FreeSans, Luxi-sans, 'Nimbus Sans L', sans-serif; font-size: 12px; line-height: normal; background-color: #ffffff; ">Let's look at a persistent class we'll use to demonstrate the serialization mechanism:</p><p style="margin-top: 3px; margin-bottom: 17px; font-family: Arial, Helvetica, FreeSans, Luxi-sans, 'Nimbus Sans L', sans-serif; font-size: 12px; line-height: normal; background-color: #ffffff; "><code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">10 import java.io.Serializable;<br />20 import java.util.Date;<br />30 import java.util.Calendar;<br />40 public class PersistentTime&nbsp;<strong>implements Serializable</strong><br />50 {<br />60 private Date time;<br />70&nbsp;<br />80 public PersistentTime()<br />90 {<br />100 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;time = Calendar.getInstance().getTime();<br />110 &nbsp;&nbsp;&nbsp;}<br />120<br />130 &nbsp;&nbsp;&nbsp;public Date getTime()<br />140 &nbsp;&nbsp;&nbsp;{<br />150 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return time;<br />160 &nbsp;&nbsp;&nbsp;}<br />170 &nbsp;}<br /></code></p><p style="margin-top: 3px; margin-bottom: 17px; font-family: Arial, Helvetica, FreeSans, Luxi-sans, 'Nimbus Sans L', sans-serif; font-size: 12px; line-height: normal; background-color: #ffffff; ">As you can see, the only thing we had to do differently from creating a normal class is implement the&nbsp;<code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">java.io.Serializable</code>&nbsp;interface on line 40. The completely empty&nbsp;<code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">Serializable</code>&nbsp;is only a&nbsp;<em>marker</em>&nbsp;interface -- it simply allows the serialization mechanism to verify that the class is able to be persisted. Thus, we turn to the first rule of serialization:</p><strong style="font-family: Arial, Helvetica, FreeSans, Luxi-sans, 'Nimbus Sans L', sans-serif; font-size: 12px; line-height: normal; background-color: #ffffff; "><p style="margin-top: 3px; margin-bottom: 17px; ">Rule #1: The object to be persisted must implement the&nbsp;<code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">Serializable</code>&nbsp;interface or inherit that implementation from its object hierarchy.</p></strong><p style="margin-top: 3px; margin-bottom: 17px; font-family: Arial, Helvetica, FreeSans, Luxi-sans, 'Nimbus Sans L', sans-serif; font-size: 12px; line-height: normal; background-color: #ffffff; ">The next step is to actually persist the object. That is done with the&nbsp;<code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">java.io.ObjectOutputStream</code>&nbsp;class. That class is a&nbsp;<em>filter stream</em>--it is wrapped around a lower-level byte stream (called a&nbsp;<em>node stream</em>) to handle the serialization protocol for us. Node streams can be used to write to file systems or even across sockets. That means we could easily transfer a flattened object across a network wire and have it be rebuilt on the other side!</p><p style="margin-top: 3px; margin-bottom: 17px; font-family: Arial, Helvetica, FreeSans, Luxi-sans, 'Nimbus Sans L', sans-serif; font-size: 12px; line-height: normal; background-color: #ffffff; ">Take a look at the code used to save the&nbsp;<code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">PersistentTime</code>&nbsp;object:</p><p style="margin-top: 3px; margin-bottom: 17px; font-family: Arial, Helvetica, FreeSans, Luxi-sans, 'Nimbus Sans L', sans-serif; font-size: 12px; line-height: normal; background-color: #ffffff; "><code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">10 import java.io.ObjectOutputStream;<br />20 import java.io.FileOutputStream;<br />30 import java.io.IOException;<br />40 public class FlattenTime<br />50 {<br />60 public static void main(String [] args)<br />70 {<br />80 String filename = "time.ser";<br />90 if(args.length &gt; 0)<br />100 &nbsp;&nbsp;&nbsp;&nbsp;{<br />110 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;filename = args[0];<br />120 &nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<br />130 &nbsp;&nbsp;&nbsp;&nbsp;PersistentTime time = new PersistentTime();<br />140 &nbsp;&nbsp;&nbsp;&nbsp;FileOutputStream fos = null;<br />150 &nbsp;&nbsp;&nbsp;&nbsp;ObjectOutputStream out = null;<br />160 &nbsp;&nbsp;&nbsp;&nbsp;try<br />170 &nbsp;&nbsp;&nbsp;&nbsp;{<br />180 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fos = new FileOutputStream(filename);<br />190 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;out = new ObjectOutputStream(fos);<br />200 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;out.writeObject(time);<br />210 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;out.close();<br />220 &nbsp;&nbsp;&nbsp;&nbsp;}<br />230 &nbsp;&nbsp;&nbsp;&nbsp;catch(IOException ex)<br />240 &nbsp;&nbsp;&nbsp;&nbsp;{<br />250 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ex.printStackTrace();<br />260 &nbsp;&nbsp;&nbsp;&nbsp;}<br />270 &nbsp;&nbsp;}<br />280 }<br /></code></p><p style="margin-top: 3px; margin-bottom: 17px; font-family: Arial, Helvetica, FreeSans, Luxi-sans, 'Nimbus Sans L', sans-serif; font-size: 12px; line-height: normal; background-color: #ffffff; ">The real work happens on line 200 when we call the&nbsp;<code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">ObjectOutputStream.writeObject()</code>&nbsp;method, which kicks off the serialization mechanism and the object is flattened (in that case to a file).</p><p style="margin-top: 3px; margin-bottom: 17px; font-family: Arial, Helvetica, FreeSans, Luxi-sans, 'Nimbus Sans L', sans-serif; font-size: 12px; line-height: normal; background-color: #ffffff; ">To restore the file, we can employ the following code:</p><p style="margin-top: 3px; margin-bottom: 17px; font-family: Arial, Helvetica, FreeSans, Luxi-sans, 'Nimbus Sans L', sans-serif; font-size: 12px; line-height: normal; background-color: #ffffff; "><code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">10 import java.io.ObjectInputStream;<br />20 import java.io.FileInputStream;<br />30 import java.io.IOException;<br />40 import java.util.Calendar;<br />50 public class InflateTime<br />60 {<br />70 public static void main(String [] args)<br />80 {<br />90 String filename = "time.ser";&nbsp;<br />100 &nbsp;&nbsp;&nbsp;&nbsp;if(args.length &gt; 0)<br />110 &nbsp;&nbsp;&nbsp;&nbsp;{<br />120 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;filename = args[0];<br />130 &nbsp;&nbsp;&nbsp;&nbsp;}<br />140 &nbsp;&nbsp;PersistentTime time = null;<br />150 &nbsp;&nbsp;FileInputStream fis = null;<br />160 &nbsp;&nbsp;ObjectInputStream in = null;<br />170 &nbsp;&nbsp;try<br />180 &nbsp;&nbsp;{<br />190 &nbsp;&nbsp;&nbsp;&nbsp;fis = new FileInputStream(filename);<br />200 &nbsp;&nbsp;&nbsp;&nbsp;in = new ObjectInputStream(fis);<br />210 &nbsp;&nbsp;&nbsp;&nbsp;time = (PersistentTime)in.readObject();<br />220 &nbsp;&nbsp;&nbsp;&nbsp;in.close();<br />230 &nbsp;&nbsp;}<br />240 &nbsp;&nbsp;catch(IOException ex)<br />250 &nbsp;&nbsp;{<br />260 &nbsp;&nbsp;&nbsp;&nbsp;ex.printStackTrace();<br />270 &nbsp;&nbsp;}<br />280 &nbsp;&nbsp;catch(ClassNotFoundException ex)<br />290 &nbsp;&nbsp;{<br />300 &nbsp;&nbsp;&nbsp;&nbsp;ex.printStackTrace();<br />310 &nbsp;&nbsp;}<br />320 &nbsp;&nbsp;// print out restored time<br />330 &nbsp;&nbsp;System.out.println("Flattened time: " + time.getTime());<br />340 &nbsp;&nbsp;System.out.println();<br />350 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// print out the current time<br />360 &nbsp;&nbsp;System.out.println("Current time: " + Calendar.getInstance().getTime());<br />370 }<br />380}<br /></code></p><p style="margin-top: 3px; margin-bottom: 17px; font-family: Arial, Helvetica, FreeSans, Luxi-sans, 'Nimbus Sans L', sans-serif; font-size: 12px; line-height: normal; background-color: #ffffff; ">In the code above, the object's restoration occurs on line 210 with the&nbsp;<code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">ObjectInputStream.readObject()</code>&nbsp;method call. The method call reads in the raw bytes that we previously persisted and creates a live object that is an exact replica of the original. Because&nbsp;<code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">readObject()</code>&nbsp;can read any serializable object, a cast to the correct type is required. With that in mind, the class file must be accessible from the system in which the restoration occurs. In other words, the object's class file and methods are not saved; only the object's&nbsp;<em>state</em>&nbsp;is saved.</p><p style="margin-top: 3px; margin-bottom: 17px; font-family: Arial, Helvetica, FreeSans, Luxi-sans, 'Nimbus Sans L', sans-serif; font-size: 12px; line-height: normal; background-color: #ffffff; ">Later, on line 360, we simply call the&nbsp;<code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">getTime()</code>&nbsp;method to retrieve the time that the original object flattened. The flatten time is compared to the current time to demonstrate that the mechanism indeed worked as expected.</p><h4>Nonserializable Objects</h4><p style="margin-top: 2px; margin-bottom: 17px; font-family: Arial, Helvetica, FreeSans, Luxi-sans, 'Nimbus Sans L', sans-serif; font-size: 12px; line-height: normal; background-color: #ffffff; ">The basic mechanism of Java serialization is simple to use, but there are some more things to know. As mentioned before, only objects marked<code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">Serializable</code>&nbsp;can be persisted. The&nbsp;<code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">java.lang.Object</code>&nbsp;class does not implement that interface. Therefore, not all the objects in Java can be persisted automatically. The good news is that most of them -- like AWT and Swing GUI components, strings, and arrays -- are serializable.</p><p style="margin-top: 3px; margin-bottom: 17px; font-family: Arial, Helvetica, FreeSans, Luxi-sans, 'Nimbus Sans L', sans-serif; font-size: 12px; line-height: normal; background-color: #ffffff; ">On the other hand, certain system-level classes such as&nbsp;<code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">Thread</code>,&nbsp;<code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">OutputStream</code>&nbsp;and its subclasses, and&nbsp;<code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">Socket</code>&nbsp;are not serializable. Indeed, it would not make any sense if they were. For example, thread running in my JVM would be using my system's memory. Persisting it and trying to run it in your JVM would make no sense at all. Another important point about&nbsp;<code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">java.lang.Object</code>&nbsp;not implementing the&nbsp;<code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">Serializable</code>&nbsp;interface is that any class you create that extends only&nbsp;<code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">Object</code>&nbsp;(and no other serializable classes) is not serializable unless you implement the interface yourself (as done with the previous example).</p><p style="margin-top: 3px; margin-bottom: 17px; font-family: Arial, Helvetica, FreeSans, Luxi-sans, 'Nimbus Sans L', sans-serif; font-size: 12px; line-height: normal; background-color: #ffffff; ">That situation presents a problem: what if we have a class that contains an instance of&nbsp;<code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">Thread</code>? In that case, can we ever persist objects of that type? The answer is yes, as long as we tell the serialization mechanism our intentions by marking our class's&nbsp;<code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">Thread</code>&nbsp;object as&nbsp;<code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">transient</code>.</p><p style="margin-top: 3px; margin-bottom: 17px; font-family: Arial, Helvetica, FreeSans, Luxi-sans, 'Nimbus Sans L', sans-serif; font-size: 12px; line-height: normal; background-color: #ffffff; ">Let's assume we want to create a class that performs an animation. I will not actually provide the animation code here, but here is the class we'll use:</p><p style="margin-top: 3px; margin-bottom: 17px; font-family: Arial, Helvetica, FreeSans, Luxi-sans, 'Nimbus Sans L', sans-serif; font-size: 12px; line-height: normal; background-color: #ffffff; "><code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">10 import java.io.Serializable;<br />20 public class PersistentAnimation implements Serializable, Runnable<br />30 {<br />40&nbsp;<strong>transient</strong>&nbsp;private Thread animator;<br />50 private int animationSpeed;<br />60 public PersistentAnimation(int animationSpeed)<br />70 {<br />80 this.animationSpeed = animationSpeed;<br />90 animator = new Thread(this);<br />100 &nbsp;&nbsp;&nbsp;&nbsp;animator.start();<br />110 &nbsp;&nbsp;}<br />120 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public void run()<br />130 &nbsp;&nbsp;{<br />140 &nbsp;&nbsp;&nbsp;&nbsp;while(true)<br />150 &nbsp;&nbsp;&nbsp;&nbsp;{<br />160 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// do animation here<br />170 &nbsp;&nbsp;&nbsp;&nbsp;}<br />180 &nbsp;&nbsp;}&nbsp;<br />190 }<br /></code></p><p style="margin-top: 3px; margin-bottom: 17px; font-family: Arial, Helvetica, FreeSans, Luxi-sans, 'Nimbus Sans L', sans-serif; font-size: 12px; line-height: normal; background-color: #ffffff; ">When we create an instance of the&nbsp;<code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">PersistentAnimation</code>&nbsp;class, the thread&nbsp;<code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">animator</code>&nbsp;will be created and started as we expect. We've marked the thread on line 40&nbsp;<code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">transient</code>&nbsp;to tell the serialization mechanism that the field should not be saved along with the rest of that object's state (in that case, the field&nbsp;<code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">speed</code>). The bottom line: you must mark&nbsp;<code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">transient</code>&nbsp;any field that either cannot be serialized or any field you do not want serialized. Serialization does not care about access modifiers such as&nbsp;<code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">private</code>&nbsp;-- all nontransient fields are considered part of an object's persistent state and are eligible for persistence.</p><p style="margin-top: 3px; margin-bottom: 17px; font-family: Arial, Helvetica, FreeSans, Luxi-sans, 'Nimbus Sans L', sans-serif; font-size: 12px; line-height: normal; background-color: #ffffff; ">Therefore, we have another rule to add. Here are both rules concerning persistent objects:</p><ul style="margin-left: 13px; padding-left: 0px; font-family: Arial, Helvetica, FreeSans, Luxi-sans, 'Nimbus Sans L', sans-serif; font-size: 12px; line-height: normal; background-color: #ffffff; "><p style="margin-top: 3px; margin-bottom: 17px; "></p><li style="margin-left: 13px; padding-left: 0px; list-style-image: url(http://java.sun.com/im/ul_bullet.gif); "><strong>Rule #1: The object to be persisted must implement the&nbsp;<code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">Serializable</code>&nbsp;interface or inherit that implementation from its object hierarchy</strong></li><p style="margin-top: 3px; margin-bottom: 17px; "></p><p style="margin-top: 3px; margin-bottom: 17px; "></p><li style="margin-left: 13px; padding-left: 0px; list-style-image: url(http://java.sun.com/im/ul_bullet.gif); "><strong>Rule #2: The object to be persisted must mark all nonserializable fields&nbsp;<code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">transient</code></strong></li><p style="margin-top: 3px; margin-bottom: 17px; "></p></ul><h3>Customize the Default Protocol</h3><p style="margin-top: 2px; margin-bottom: 17px; font-family: Arial, Helvetica, FreeSans, Luxi-sans, 'Nimbus Sans L', sans-serif; font-size: 12px; line-height: normal; background-color: #ffffff; ">Let's move on to the second way to perform serialization: customize the default protocol. Though the animation code above demonstrates how a thread could be included as part of an object while still making that object be serializable, there is a major problem with it if we recall how Java creates objects. To wit, when we create an object with the&nbsp;<code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">new</code>&nbsp;keyword, the object's constructor is called only when a new instance of a class is created. Keeping that basic fact in mind, let's revisit our animation code. First, we instantiate an object of type&nbsp;<code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">PersistentAnimation</code>, which begins the animation thread sequence. Next, we serialize the object with that code:</p><p style="margin-top: 3px; margin-bottom: 17px; font-family: Arial, Helvetica, FreeSans, Luxi-sans, 'Nimbus Sans L', sans-serif; font-size: 12px; line-height: normal; background-color: #ffffff; "><code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">PersistentAnimation animation = new PersistentAnimation(10);<br />FileOutputStream fos = ...<br />ObjectOutputStream out = new ObjectOutputStream(fos);<br />out.<strong>writeObject(animation)</strong>;<br /></code></p><p style="margin-top: 3px; margin-bottom: 17px; font-family: Arial, Helvetica, FreeSans, Luxi-sans, 'Nimbus Sans L', sans-serif; font-size: 12px; line-height: normal; background-color: #ffffff; ">All seems fine until we read the object back in with a call to the&nbsp;<code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">readObject()</code>&nbsp;method. Remember, a constructor is called only when a new instance is created. We are not creating a new instance here, we are restoring a persisted object. The end result is the animation object will work only once, when it is first instantiated. Kind of makes it useless to persist it, huh?</p><p style="margin-top: 3px; margin-bottom: 17px; font-family: Arial, Helvetica, FreeSans, Luxi-sans, 'Nimbus Sans L', sans-serif; font-size: 12px; line-height: normal; background-color: #ffffff; ">Well, there is good news. We can make our object work the way we want it to; we can make the animation restart upon restoration of the object. To accomplish that, we could, for example, create a&nbsp;<code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">startAnimation()</code>&nbsp;helper method that does what the constructor currently does. We could then call that method from the constructor, after which we read the object back in. Not bad, but it introduces more complexity. Now, anyone who wants to use that animation object will have to know that method has to be called following the normal deserialization process. That does not make for a seamless mechanism, something the Java Serialization API promises developers.</p><p style="margin-top: 3px; margin-bottom: 17px; font-family: Arial, Helvetica, FreeSans, Luxi-sans, 'Nimbus Sans L', sans-serif; font-size: 12px; line-height: normal; background-color: #ffffff; ">There is, however, a strange yet crafty solution. By using a built-in feature of the serialization mechanism, developers can enhance the normal process by providing two methods inside their class files. Those methods are:</p><ul style="margin-left: 13px; padding-left: 0px; font-family: Arial, Helvetica, FreeSans, Luxi-sans, 'Nimbus Sans L', sans-serif; font-size: 12px; line-height: normal; background-color: #ffffff; "><p style="margin-top: 3px; margin-bottom: 17px; "></p><li style="margin-left: 13px; padding-left: 0px; list-style-image: url(http://java.sun.com/im/ul_bullet.gif); "><code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">private void writeObject(ObjectOutputStream out) throws IOException;</code></li><p style="margin-top: 3px; margin-bottom: 17px; "></p><p style="margin-top: 3px; margin-bottom: 17px; "></p><li style="margin-left: 13px; padding-left: 0px; list-style-image: url(http://java.sun.com/im/ul_bullet.gif); "><code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException;</code></li><p style="margin-top: 3px; margin-bottom: 17px; "></p></ul><p style="margin-top: 3px; margin-bottom: 17px; font-family: Arial, Helvetica, FreeSans, Luxi-sans, 'Nimbus Sans L', sans-serif; font-size: 12px; line-height: normal; background-color: #ffffff; ">Notice that both methods are (and must be) declared&nbsp;<code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">private</code>, proving that neither method is inherited and overridden or overloaded. The trick here is that the virtual machine will automatically check to see if either method is declared during the corresponding method call. The virtual machine can call private methods of your class whenever it wants but no other objects can. Thus, the integrity of the class is maintained and the serialization protocol can continue to work as normal. The serialization protocol is always used the same way, by calling either<code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">ObjectOutputStream.writeObject()</code>&nbsp;or&nbsp;<code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">ObjectInputStream.readObject()</code>. So, even though those specialized private methods are provided, the object serialization works the same way as far as any calling object is concerned.</p><p style="margin-top: 3px; margin-bottom: 17px; font-family: Arial, Helvetica, FreeSans, Luxi-sans, 'Nimbus Sans L', sans-serif; font-size: 12px; line-height: normal; background-color: #ffffff; ">Considering all that, let's look at a revised version of&nbsp;<code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">PersistentAnimation</code>&nbsp;that includes those private methods to allow us to have control over the deserialization process, giving us a pseudo-constructor:</p><p style="margin-top: 3px; margin-bottom: 17px; font-family: Arial, Helvetica, FreeSans, Luxi-sans, 'Nimbus Sans L', sans-serif; font-size: 12px; line-height: normal; background-color: #ffffff; "><code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">10 import java.io.Serializable;<br />20 public class PersistentAnimation implements Serializable, Runnable<br />30 {<br />40&nbsp;<strong>transient</strong>&nbsp;private Thread animator;<br />50 private int animationSpeed;<br />60 public PersistentAnimation(int animationSpeed)<br />70 {<br />80 this.animationSpeed = animationSpeed;<br />90 startAnimation();&nbsp;<br />100 &nbsp;&nbsp;}<br />110 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public void run()<br />120 &nbsp;&nbsp;{<br />130 &nbsp;&nbsp;&nbsp;&nbsp;while(true)<br />140 &nbsp;&nbsp;&nbsp;&nbsp;{<br />150 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// do animation here<br />160 &nbsp;&nbsp;&nbsp;&nbsp;}<br />170 &nbsp;&nbsp;}&nbsp;<br />180 &nbsp;&nbsp;private void writeObject(ObjectOutputStream out) throws IOException<br />190 &nbsp;&nbsp;{<br />200 &nbsp;&nbsp;&nbsp;&nbsp;out.defaultWriteObject();&nbsp;<br />220 &nbsp;&nbsp;}<br />230 &nbsp;&nbsp;private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException<br />240 &nbsp;&nbsp;{<br />250 &nbsp;&nbsp;&nbsp;&nbsp;// our "pseudo-constructor"<br />260 &nbsp;&nbsp;&nbsp;&nbsp;in.defaultReadObject();<br />270 &nbsp;&nbsp;&nbsp;&nbsp;// now we are a "live" object again, so let's run rebuild and start<br />280 &nbsp;&nbsp;&nbsp;&nbsp;startAnimation();<br />290<br />300 &nbsp;&nbsp;}<br />310 &nbsp;&nbsp;private void startAnimation()<br />320 &nbsp;&nbsp;{<br />330 &nbsp;&nbsp;&nbsp;&nbsp;animator = new Thread(this);<br />340 &nbsp;&nbsp;&nbsp;&nbsp;animator.start();<br />350 &nbsp;&nbsp;}<br />360 }<br /></code></p><p style="margin-top: 3px; margin-bottom: 17px; font-family: Arial, Helvetica, FreeSans, Luxi-sans, 'Nimbus Sans L', sans-serif; font-size: 12px; line-height: normal; background-color: #ffffff; ">Notice the first line of each of the new private methods. Those calls do what they sound like -- they perform the default writing and reading of the flattened object, which is important because we are not replacing the normal process, we are only adding to it. Those methods work because the call to&nbsp;<code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">ObjectOutputStream.writeObject()</code>&nbsp;kicks off the serialization protocol. First, the object is checked to ensure it implements<code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">Serializable</code>&nbsp;and then it is checked to see whether either of those private methods are provided. If they are provided, the stream class is passed as the parameter, giving the code control over its usage.</p><p style="margin-top: 3px; margin-bottom: 17px; font-family: Arial, Helvetica, FreeSans, Luxi-sans, 'Nimbus Sans L', sans-serif; font-size: 12px; line-height: normal; background-color: #ffffff; ">Those private methods can be used for any customization you need to make to the serialization process. Encryption could be added to the output and decryption to the input (note that the bytes are written and read in cleartext with no obfuscation at all). They could be used to add extra data to the stream, perhaps a company versioning code. The possibilities are truly limitless.</p><h4>Stop That Serialization!</h4><p style="margin-top: 2px; margin-bottom: 17px; font-family: Arial, Helvetica, FreeSans, Luxi-sans, 'Nimbus Sans L', sans-serif; font-size: 12px; line-height: normal; background-color: #ffffff; ">OK, we have seen quite a bit about the serialization process, now let's see some more. What if you create a class whose superclass is serializable but you do not want that new class to be serializable? You cannot unimplement an interface, so if your superclass does implement<code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">Serializable</code>, your new class implements it, too (assuming both rules listed above are met). To stop the automatic serialization, you can once again use the private methods to just throw the&nbsp;<code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">NotSerializableException</code>. Here is how that would be done:</p><p style="margin-top: 3px; margin-bottom: 17px; font-family: Arial, Helvetica, FreeSans, Luxi-sans, 'Nimbus Sans L', sans-serif; font-size: 12px; line-height: normal; background-color: #ffffff; "><code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">10 private void writeObject(ObjectOutputStream out) throws IOException<br />20 {<br />30 throw new NotSerializableException("Not today!");<br />40 }<br />50 private void readObject(ObjectInputStream in) throws IOException<br />60 {<br />70 throw new NotSerializableException("Not today!");<br />80 }<br /></code></p><p style="margin-top: 3px; margin-bottom: 17px; font-family: Arial, Helvetica, FreeSans, Luxi-sans, 'Nimbus Sans L', sans-serif; font-size: 12px; line-height: normal; background-color: #ffffff; ">Any attempt to write or read that object will now always result in the exception being thrown. Remember, since those methods are declared<code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">private</code>, nobody could modify your code without the source code available to them -- no overriding of those methods would be allowed by Java.</p><h3>Create Your Own Protocol: the Externalizable Interface</h3><p style="margin-top: 2px; margin-bottom: 17px; font-family: Arial, Helvetica, FreeSans, Luxi-sans, 'Nimbus Sans L', sans-serif; font-size: 12px; line-height: normal; background-color: #ffffff; ">Our discussion would be incomplete not to mention the third option for serialization: create your own protocol with the&nbsp;<code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">Externalizable</code>&nbsp;interface. Instead of implementing the&nbsp;<code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">Serializable</code>&nbsp;interface, you can implement&nbsp;<code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">Externalizable</code>, which contains two methods:</p><ul style="margin-left: 13px; padding-left: 0px; font-family: Arial, Helvetica, FreeSans, Luxi-sans, 'Nimbus Sans L', sans-serif; font-size: 12px; line-height: normal; background-color: #ffffff; "><p style="margin-top: 3px; margin-bottom: 17px; "></p><li style="margin-left: 13px; padding-left: 0px; list-style-image: url(http://java.sun.com/im/ul_bullet.gif); "><code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">public void writeExternal(ObjectOutput out) throws IOException;</code></li><p style="margin-top: 3px; margin-bottom: 17px; "></p><p style="margin-top: 3px; margin-bottom: 17px; "></p><li style="margin-left: 13px; padding-left: 0px; list-style-image: url(http://java.sun.com/im/ul_bullet.gif); "><code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException;</code></li><p style="margin-top: 3px; margin-bottom: 17px; "></p></ul><p style="margin-top: 3px; margin-bottom: 17px; font-family: Arial, Helvetica, FreeSans, Luxi-sans, 'Nimbus Sans L', sans-serif; font-size: 12px; line-height: normal; background-color: #ffffff; ">Just override those methods to provide your own protocol. Unlike the previous two serialization variations, nothing is provided for free here, though. That is, the protocol is entirely in your hands. Although it's the more difficult scenario, it's also the most controllable. An example situation for that alternate type of serialization: read and write PDF files with a Java application. If you know how to write and read PDF (the sequence of bytes required), you could provide the PDF-specific protocol in the&nbsp;<code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">writeExternal</code>&nbsp;and&nbsp;<code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">readExternal</code>&nbsp;methods.</p><p style="margin-top: 3px; margin-bottom: 17px; font-family: Arial, Helvetica, FreeSans, Luxi-sans, 'Nimbus Sans L', sans-serif; font-size: 12px; line-height: normal; background-color: #ffffff; ">Just as before, though, there is no difference in how a class that implements&nbsp;<code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">Externalizable</code>&nbsp;is used. Just call&nbsp;<code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">writeObject()</code>&nbsp;or&nbsp;<code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">readObject</code>and, voila, those externalizable methods will be called automatically.</p><h3>Gotchas</h3><p style="margin-top: 2px; margin-bottom: 17px; font-family: Arial, Helvetica, FreeSans, Luxi-sans, 'Nimbus Sans L', sans-serif; font-size: 12px; line-height: normal; background-color: #ffffff; ">There are a few things about the serialization protocol that can seem very strange to developers who are not aware. Of course, that is the purpose of the article -- to get you aware! So let's discuss a few of those gotchas and see if we can understand why they exist and how to handle them.</p><h4>Caching Objects in the Stream</h4><p style="margin-top: 2px; margin-bottom: 17px; font-family: Arial, Helvetica, FreeSans, Luxi-sans, 'Nimbus Sans L', sans-serif; font-size: 12px; line-height: normal; background-color: #ffffff; ">First, consider the situation in which an object is written to a stream and then written again later. By default, an&nbsp;<code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">ObjectOutputStream</code>&nbsp;will maintain a reference to an object written to it. That means that if the state of the written object is written and then written again, the new state will not be saved! Here is a code snippet that shows that problem in action:</p><p style="margin-top: 3px; margin-bottom: 17px; font-family: Arial, Helvetica, FreeSans, Luxi-sans, 'Nimbus Sans L', sans-serif; font-size: 12px; line-height: normal; background-color: #ffffff; "><code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">10 ObjectOutputStream out = new ObjectOutputStream(...);<br />20 MyObject obj = new MyObject(); // must be Serializable<br />30 obj.setState(100);<br />40 out.writeObject(obj); // saves object with state = 100<br />50 obj.setState(200);<br />60 out.writeObject(obj); // does not save new object state<br /></code></p><p style="margin-top: 3px; margin-bottom: 17px; font-family: Arial, Helvetica, FreeSans, Luxi-sans, 'Nimbus Sans L', sans-serif; font-size: 12px; line-height: normal; background-color: #ffffff; ">There are two ways to control that situation. First, you could make sure to always close the stream after a write call, ensuring the new object is written out each time. Second, you could call the&nbsp;<code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">ObjectOutputStream.reset()</code>&nbsp;method, which would tell the stream to release the cache of references it is holding so all new write calls will actually be written. Be careful, though -- the&nbsp;<code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">reset</code>&nbsp;flushes the entire object cache, so all objects that have been written could be rewritten.</p><h4>Version Control</h4><p style="margin-top: 2px; margin-bottom: 17px; font-family: Arial, Helvetica, FreeSans, Luxi-sans, 'Nimbus Sans L', sans-serif; font-size: 12px; line-height: normal; background-color: #ffffff; ">With our second gotcha, imagine you create a class, instantiate it, and write it out to an object stream. That flattened object sits in the file system for some time. Meanwhile, you update the class file, perhaps adding a new field. What happens when you try to read in the flattened object?</p><p style="margin-top: 3px; margin-bottom: 17px; font-family: Arial, Helvetica, FreeSans, Luxi-sans, 'Nimbus Sans L', sans-serif; font-size: 12px; line-height: normal; background-color: #ffffff; ">Well, the bad news is that an exception will be thrown -- specifically, the&nbsp;<code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">java.io.InvalidClassException</code>&nbsp;-- because all persistent-capable classes are automatically given a unique identifier. If the identifier of the class does not equal the identifier of the flattened object, the exception will be thrown. However, if you really think about it, why should it be thrown just because I added a field? Couldn't the field just be set to its default value and then written out next time?</p><p style="margin-top: 3px; margin-bottom: 17px; font-family: Arial, Helvetica, FreeSans, Luxi-sans, 'Nimbus Sans L', sans-serif; font-size: 12px; line-height: normal; background-color: #ffffff; ">Yes, but it takes a little code manipulation. The identifier that is part of all classes is maintained in a field called&nbsp;<code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">serialVersionUID</code>. If you wish to control versioning, you simply have to provide the&nbsp;<code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">serialVersionUID</code>&nbsp;field manually and ensure it is always the same, no matter what changes you make to the classfile. You can use a utility that comes with the JDK distribution called&nbsp;<code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">serialver</code>&nbsp;to see what that code would be by default (it is just the hash code of the object by default).</p><p style="margin-top: 3px; margin-bottom: 17px; font-family: Arial, Helvetica, FreeSans, Luxi-sans, 'Nimbus Sans L', sans-serif; font-size: 12px; line-height: normal; background-color: #ffffff; ">Here is an example of using&nbsp;<code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">serialver</code>&nbsp;with a class called&nbsp;<code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">Baz</code>:</p><p style="margin-top: 3px; margin-bottom: 17px; font-family: Arial, Helvetica, FreeSans, Luxi-sans, 'Nimbus Sans L', sans-serif; font-size: 12px; line-height: normal; background-color: #ffffff; "><code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">&gt; serialver Baz<br />&gt; Baz: static final long serialVersionUID = 10275539472837495L;<br /></code></p><p style="margin-top: 3px; margin-bottom: 17px; font-family: Arial, Helvetica, FreeSans, Luxi-sans, 'Nimbus Sans L', sans-serif; font-size: 12px; line-height: normal; background-color: #ffffff; ">Simply copy the returned line with the version ID and paste it into your code. (On a Windows box, you can run that utility with the&nbsp;<code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">- show</code>&nbsp;option to simplify the copy and paste procedure.) Now, if you make any changes to the&nbsp;<code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">Baz</code>&nbsp;class file, just ensure that same version ID is specified and all will be well.</p><p style="margin-top: 3px; margin-bottom: 17px; font-family: Arial, Helvetica, FreeSans, Luxi-sans, 'Nimbus Sans L', sans-serif; font-size: 12px; line-height: normal; background-color: #ffffff; ">The version control works great as long as the changes are compatible. Compatible changes include adding or removing a method or a field. Incompatible changes include changing an object's hierarchy or removing the implementation of the&nbsp;<code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">Serializable</code>&nbsp;interface. A complete list of compatible and incompatible changes is given in the Java Serialization Specification.</p><h4>Performance Considerations</h4><p style="margin-top: 2px; margin-bottom: 17px; font-family: Arial, Helvetica, FreeSans, Luxi-sans, 'Nimbus Sans L', sans-serif; font-size: 12px; line-height: normal; background-color: #ffffff; ">Our third gotcha: the default mechanism, although simple to use, is not the best performer. I wrote out a&nbsp;<code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">Date</code>&nbsp;object to a file 1,000 times, repeating that procedure 100 times. The average time to write out the&nbsp;<code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">Date</code>&nbsp;object was 115 milliseconds. I then manually wrote out the&nbsp;<code style="font-family: Monaco, Courier, 'Courier New', monospace; color: #444444; ">Date</code>object, using standard I/O the same number of iterations; the average time was 52 milliseconds. Almost half the time! There is often a trade-off between convenience and performance, and serialization proves no different. If speed is the primary consideration for your application, you may want to consider building a custom protocol.</p><p style="margin-top: 3px; margin-bottom: 17px; font-family: Arial, Helvetica, FreeSans, Luxi-sans, 'Nimbus Sans L', sans-serif; font-size: 12px; line-height: normal; background-color: #ffffff; ">Another consideration concerns the aforementioned fact that object references are cached in the output stream. Due to that, the system may not garbage collect the objects written to a stream if the stream is not closed. The best move, as always with I/O, is to close the streams as soon as possible, following the write operations.</p><h3>Conclusion</h3><p style="margin-top: 2px; margin-bottom: 17px; font-family: Arial, Helvetica, FreeSans, Luxi-sans, 'Nimbus Sans L', sans-serif; font-size: 12px; line-height: normal; background-color: #ffffff; ">Serialization in Java is simple to instigate and almost as simple to implement. Understanding the three different ways of implementing serialization should aid in bending the API to your will. We have seen a lot of the serialization mechanism in that article, and I hope it made things clearer and not worse. The bottom line, as with all coding, is to maintain common sense within the bounds of API familiarity. That article has laid out a strong basis of understanding the Java Serialization API, but I recommend perusing the specification to discover more fine-grained details.</p></div><img src ="http://www.blogjava.net/decorator/aggbug/386821.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/decorator/" target="_blank">庄主游骥</a> 2012-09-03 00:48 <a href="http://www.blogjava.net/decorator/archive/2012/09/03/386821.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>正则表达式规则</title><link>http://www.blogjava.net/decorator/archive/2012/08/30/386631.html</link><dc:creator>庄主游骥</dc:creator><author>庄主游骥</author><pubDate>Thu, 30 Aug 2012 13:29:00 GMT</pubDate><guid>http://www.blogjava.net/decorator/archive/2012/08/30/386631.html</guid><wfw:comment>http://www.blogjava.net/decorator/comments/386631.html</wfw:comment><comments>http://www.blogjava.net/decorator/archive/2012/08/30/386631.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/decorator/comments/commentRss/386631.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/decorator/services/trackbacks/386631.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 正则表达式  引言  &nbsp;&nbsp;&nbsp;&nbsp;正则表达式（regular expression）就是用一个&#8220;字符串&#8221;来描述一个特征，然后去验证另一个&#8220;字符串&#8221;是否符合这个特征。比如表达式&#8220;ab+&#8221;&nbsp;描述的特征是&#8220;一个&nbsp;'a'&nbsp;和&nbsp;任意个&nbsp;'b...&nbsp;&nbsp;<a href='http://www.blogjava.net/decorator/archive/2012/08/30/386631.html'>阅读全文</a><img src ="http://www.blogjava.net/decorator/aggbug/386631.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/decorator/" target="_blank">庄主游骥</a> 2012-08-30 21:29 <a href="http://www.blogjava.net/decorator/archive/2012/08/30/386631.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>