﻿<?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/calvinlau/category/39179.html</link><description>技术储备，从这里开始</description><language>zh-cn</language><lastBuildDate>Mon, 05 Oct 2009 10:15:24 GMT</lastBuildDate><pubDate>Mon, 05 Oct 2009 10:15:24 GMT</pubDate><ttl>60</ttl><item><title>zz finally的小特性</title><link>http://www.blogjava.net/calvinlau/articles/296745.html</link><dc:creator>calvinlau</dc:creator><author>calvinlau</author><pubDate>Mon, 28 Sep 2009 03:09:00 GMT</pubDate><guid>http://www.blogjava.net/calvinlau/articles/296745.html</guid><wfw:comment>http://www.blogjava.net/calvinlau/comments/296745.html</wfw:comment><comments>http://www.blogjava.net/calvinlau/articles/296745.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/calvinlau/comments/commentRss/296745.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/calvinlau/services/trackbacks/296745.html</trackback:ping><description><![CDATA[<span style="font-size: large;">http://zangxt.javaeye.com/blog/421508<br />
<br />
try/catch/finally语句下，finally子句是肯定会执行的。但是很多人做不同的测试，却得出了不同的结论。</span>
<p><span style="font-size: large;">具体的原理最好是去看《深入java虚拟机》，里面对jsr、ret等几个指令做了详细的说明。这里不深入分析，而仅仅是从表现形式上看一下finally的特征。</span></p>
<p><span style="font-size: large;">代码：</span></p>
<p><span style="font-size: large;">&nbsp;&nbsp;
<pre name="code" class="java">/*<br />
* author: Zang XT<br />
*/<br />
<br />
public class TestFinal {<br />
public static void main(String[] args) {<br />
System.out.println("test1:" + testFinal1());<br />
System.out.println("test2:" + testFinal2());<br />
System.out.println("test3:" + testFinal3());<br />
System.out.println("test4:" + testFinal4());<br />
}<br />
<br />
static int testFinal1() {<br />
int i = 1;<br />
try {<br />
return i;<br />
} finally {<br />
System.out.println("in testFinal1():finally 肯定会被执行的！");<br />
i = 48;<br />
}<br />
}<br />
<br />
static String testFinal2() {<br />
String str = "try";<br />
try {<br />
return str;<br />
} finally {<br />
System.out.println("in testFinal2():finally 肯定会被执行的！");<br />
str = "finally";<br />
}<br />
}<br />
<br />
static StringBuilder testFinal3() {<br />
StringBuilder build = new StringBuilder("try ");<br />
try {<br />
return build;<br />
} finally {<br />
System.out.println("in testFinal3():finally 肯定会被执行的！");<br />
build.append("finally");<br />
build = new StringBuilder("你猜我是谁！");<br />
}<br />
}<br />
<br />
static String testFinal4() {<br />
try {<br />
return "return in try";<br />
} finally {<br />
System.out.println("in testFinal4():finally 肯定会被执行的！");<br />
return "return in finally";<br />
}<br />
}<br />
}<br />
<br />
</pre>
<font size="5">
<p>&nbsp;</p>
</font></span></p>
<p>&nbsp;</p>
<p><span style="font-size: large;">输出是：</span></p>
<p><span style="font-size: large;">in testFinal1():finally 肯定会被执行的！</span></p>
<p><span style="font-size: large;">test1:1</span></p>
<p><span style="font-size: large;">in testFinal2():finally 肯定会被执行的！</span></p>
<p><span style="font-size: large;">test2:try</span></p>
<p><span style="font-size: large;">in testFinal3():finally 肯定会被执行的！</span></p>
<p><span style="font-size: large;">test3:try finally</span></p>
<p><span style="font-size: large;">in testFinal4():finally 肯定会被执行的！</span></p>
<p><span style="font-size: large;">test4:return in finally</span></p>
<div><span style="font-size: large;">&nbsp;&nbsp;&nbsp;&nbsp;
结论很明显，finally的语句确实执行了，而且肯定是在方法return之前执行的，而且，如果finally中有return语句的话，方法直接结
束。这里需要注意的只有一点：在try中的return语句会将返回结果值压栈，然后转入到finally子过程，等到finally子过程执行完毕之后
（没有return），再返回。</span></div>
<div><span style="font-size: large;">下面具体看4个例子：</span></div>
<div><span style="font-size: large;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在testFinal1()中，return i;会将结果i的值，也就是1压入栈。即使在finally中将i修改了（i=48），也不回对已经压入栈里的1造成任何影响。</span></div>
<div><span style="font-size: large;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在testFinal2()中，return
str;将str的内容压入栈，比如我们假设str的内容为0x108(只是一个地址值),通过这个地址值我们能找到"try"，那栈里的内容就是
0x108。执行str =
"finally"，这时候str这个变量的内容可能变为0x237了，这是串"finally"的地址。方法调用结束后，返回的是什么？return时
压入栈里的0x108。所以在打印结果时，我们打印的是通过0x108找到的字符串"try"。</span></div>
<div><span style="font-size: large;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在testFinal3()中，return
压栈的是build这个变量的值，比如是0x3579，通过这个值我们可以找到StringBuilder对象。finally语句块中对这个对象的内容
进行了修改。build = new
StringBuilder("你猜我是谁！");让build变量指向了一个新的对象，这时候build的值可能是0x4579了。但是，别忘了，原来
的StringBuilder对象仍然在0x3579处，而我们压栈的正是0x3579啊！方法返回后，我们得到的返回值0x3579，通过这个引用值找
到相应的StringBuilder对象，所以打印的结果是test3:try finally。</span></div>
<div><span style="font-size: large;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在testFinal4()中，finally有return语句，直接返回，方法结束。</span></div>
<div><span style="font-size: large;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 为什么不同的人有不同的结论？关键是没有正确理解压栈的是什么东西。其实初学java的时候，如果理解了变量是什么，并区分引用和对象本身就不会得到错误的结论了。再有，如果理解java中，方法调用都是采用传值模式的话，这里也就类似的可以明白了。</span></div>
<img src ="http://www.blogjava.net/calvinlau/aggbug/296745.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/calvinlau/" target="_blank">calvinlau</a> 2009-09-28 11:09 <a href="http://www.blogjava.net/calvinlau/articles/296745.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>HashMap &amp; Hashtable</title><link>http://www.blogjava.net/calvinlau/articles/267242.html</link><dc:creator>calvinlau</dc:creator><author>calvinlau</author><pubDate>Thu, 23 Apr 2009 14:20:00 GMT</pubDate><guid>http://www.blogjava.net/calvinlau/articles/267242.html</guid><wfw:comment>http://www.blogjava.net/calvinlau/comments/267242.html</wfw:comment><comments>http://www.blogjava.net/calvinlau/articles/267242.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/calvinlau/comments/commentRss/267242.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/calvinlau/services/trackbacks/267242.html</trackback:ping><description><![CDATA[关于两者的区别，转载内容如下：<br />
<br />
1、Hashtable是Dictionary的子类，HashMap是Map接口的一个实现类；<br />
<br />
2、<span style="color: red;">Hashtable中的方法是同步的，而HashMap中的方法在缺省情况下是非同步的</span>。即是说，在多线程应用程序中，不用专门的操作就安全地可以使用Hashtable了；而对于
HashMap，则需要额外的同步机制。但HashMap的同步问题可通过Collections的一个静态方法得到解决：<br />
<strong>Map Collections.synchronizedMap(Map m)</strong><br />
这个方法返回一个同步的Map，这个Map封装了底层的HashMap的所有方法，使得底层的HashMap即使是在多线程的环境中也是安全的。<br />
<br />
3、<span style="color: red;">在HashMap中，null可以作为键</span>，这样的键只有一个；可以有一个或多个键所对应的值为null。当get()方法返回null值时，即可以表示
HashMap中没有该键，也可以表示该键所对应的值为null。因此，在HashMap中不能由get()方法来判断HashMap中是否存在某个键，
而应该用containsKey()方法来判断。 <br />
<br />
4、其底层的实现机制不同，HashMap的访问速度要快于Hashtable，因为它不需要进行同步检验，建议在非多线程环境中使用HashMap代替Hashtable<br />
<br />
补充：<br />
5、HashMap的默认初始容量是16；Hashtable的默认初始容量是11<br />
6、keySet()、values() 、entrySet() 支持元素的删除，但是不支持元素的添加<br />
<br />
==================== 分割线：JDK5帮助文档的描述 ==================<em><br />
</em>
<p><strong>HashMap:</strong></p>
<p>基于哈希表的 Map 接口的实现。此实现提供所有可选的映射操作，<span style="color: red;">并允许使用 null 值和 null 键。（除了不同步和允许使用 null 之外，HashMap 类与 Hashtable 大致相同。）</span>此类不保证映射的顺序，特别是它不保证该顺序恒久不变。&nbsp;</p>
<p><br />
此实现假定哈希函数将元素正确分布在各桶之间，可为基本操作（get 和 put）提供稳定的性能。<span style="color: red;">迭代集合视图所需的时间与 HashMap 实例的&#8220;容量&#8221;（桶的数量）及其大小（键-值映射关系数）的和成比例</span>。所以，如果迭代性能很重要，则不要将初始容量设置得太高（或将加载因子设置得太低）。 <br />
<br />
HashMap 的实例有两个参数影响其性能：初始容量和加载因子。容量是哈希表中桶的数量，初始容量只是哈希表在创建时的容量。加载因子
是哈希表在其容量自动增加之前可以达到多满的一种尺度。当哈希表中的条目数超出了加载因子与当前容量的乘积时，通过调用 rehash
方法将容量翻倍。 <br />
<br />
通常，<span style="color: rgb(32, 88, 255);">默认加载因子 (.75) 在时间和空间成本上寻求一种折衷</span>。
加载因子过高虽然减少了空间开销，但同时也增加了查询成本（在大多数 HashMap 类的操作中，包括 get 和 put
操作，都反映了这一点）。在设置初始容量时应该考虑到映射中所需的条目数及其加载因子，以便最大限度地降低 rehash
操作次数。如果初始容量大于最大条目数除以加载因子，则不会发生 rehash 操作。 <br />
<br />
如果很多映射关系要存储在 HashMap 实例中，则相对于按需执行自动的 rehash 操作以增大表的容量来说，使用足够大的初始容量创建它将使得映射关系能更有效地存储。 <br />
<br />
注意，<span style="color: rgb(255, 0, 0);">此实现不是同步的</span>。如果多个线程同时访问此映射，而其中至少一个线程从结构上修改了该映射，则它必须保持外部同步。（<span style="color: rgb(255, 0, 0);">结构上的修改是指添加或删除一个或多个映射关系的操作；仅改变与实例已经包含的键关联的值不是结构上的修改</span>。）这一般通过对自然封装该映射的对象进行同步操作来完成。如果不存在这样的对象，则应该使用 Collections.synchronizedMap 方法来&#8220;包装&#8221;该映射。最好在创建时完成这一操作，以防止对映射进行意外的不同步访问，如下所示：<br />
<br />
&nbsp;Map m = Collections.synchronizedMap(new HashMap(...));<br />
&nbsp;<span style="color: rgb(255, 0, 0);">由所有此类的&#8220;集合视图方法&#8221;所返回的迭代器都是快速失败的</span>：
在迭代器创建之后，如果从结构上对映射进行修改，除非通过迭代器自身的 remove 或 add 方法，其他任何时间任何方式的修改，迭代器都将抛出
ConcurrentModificationException。因此，面对并发的修改，迭代器很快就会完全失败，而不冒在将来不确定的时间任意发生不
确定行为的风险。 <br />
<br />
注意，迭代器的快速失败行为不能得到保证，一般来说，存在不同步的并发修改时，不可能作出任何坚决的保证。快速失败迭代器尽最大努力抛出
ConcurrentModificationException。因此，编写依赖于此异常程序的方式是错误的，正确做法是：迭代器的快速失败行为应该仅
用于检测程序错误。&nbsp;</p>
<p><br />
</p>
<p><strong>Hashtable:</strong></p>
<p>此类实现一个哈希表，该哈希表将键映射到相应的值。<span style="color: rgb(255, 0, 0);">任何非 null 对象都可以用作键或值</span>。<br />
<br />
为了成功地在哈希表中存储和检索对象，用作键的对象必须实现 hashCode 方法和 equals 方法。<br />
<br />
Hashtable
的实例有两个参数影响其性能：初始容量和加载因子。容量是哈希表中桶的数量，初始容量就是哈希表创建时的容量。注意，哈希表的状态为
open：在发生&#8220;哈希冲突&#8221;的情况下，单个桶会存储多个条目，这些条目必须按顺序搜索。加载因子是对哈希表在其容量自动增加之前可以达到多满的一个尺
度。初始容量和加载因子这两个参数只是对该实现的提示。关于何时以及是否调用 rehash 方法的具体细节则依赖于该实现。<br />
<br />
通常，默认加载因子(.75)在时间和空间成本上寻求一种折衷。加载因子过高虽然减少了空间开销，但同时也增加了查找某个条目的时间（在大多数 Hashtable 操作中，包括 get 和 put 操作，都反映了这一点）。<br />
<br />
初始容量主要控制空间消耗与执行 rehash 操作所需要的时间损耗之间的平衡。如果初始容量大于Hashtable 所包含的最大条目数除以加载因子，则永远不会发生 rehash 操作。但是，将初始容量设置太高可能会浪费空间。<br />
<br />
如果很多条目要存储在一个 Hashtable 中，那么与根据需要执行自动 rehashing 操作来增大表的容量的做法相比，使用足够大的初始容量创建哈希表或许可以更有效地插入条目。<br />
<br />
下面这个示例创建了一个数字的哈希表。它将数字的名称用作键：</p>
<div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: rgb(0, 128, 128);">1</span>&nbsp;<span style="color: rgb(0, 0, 0);">Hashtable&nbsp;numbers&nbsp;</span><span style="color: rgb(0, 0, 0);">=</span>&nbsp;<span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);">&nbsp;Hashtable();<br />
</span><span style="color: rgb(0, 128, 128);">2</span>&nbsp;<span style="color: rgb(0, 0, 0);">numbers.put(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">one</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">,&nbsp;</span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);">&nbsp;Integer(</span><span style="color: rgb(0, 0, 0);">1</span><span style="color: rgb(0, 0, 0);">));<br />
</span><span style="color: rgb(0, 128, 128);">3</span>&nbsp;<span style="color: rgb(0, 0, 0);">numbers.put(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">two</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">,&nbsp;</span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);">&nbsp;Integer(</span><span style="color: rgb(0, 0, 0);">2</span><span style="color: rgb(0, 0, 0);">));<br />
</span><span style="color: rgb(0, 128, 128);">4</span>&nbsp;<span style="color: rgb(0, 0, 0);">numbers.put(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">three</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">,&nbsp;</span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);">&nbsp;Integer(</span><span style="color: rgb(0, 0, 0);">3</span><span style="color: rgb(0, 0, 0);">));</span></div>
<p> 要检索一个数字，可以使用以下代码： <br />
</p>
<div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: rgb(0, 0, 0);">Integer&nbsp;n&nbsp;</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">&nbsp;(Integer)numbers.get(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">two</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">);<br />
</span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);">&nbsp;(n&nbsp;</span><span style="color: rgb(0, 0, 0);">!=</span>&nbsp;<span style="color: rgb(0, 0, 255);">null</span><span style="color: rgb(0, 0, 0);">)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">two&nbsp;=&nbsp;</span><span style="color: rgb(0, 0, 0);">"</span>&nbsp;<span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);">&nbsp;n);<br />
}</span></div>
<p><br />
&nbsp;自 Java 2 平台 v1.2 以来，此类已经改进为可以实现 Map，因此它变成了 Java Collections Framework 的一部分。与新集合的实现不同，Hashtable 是同步的。<br />
<br />
由迭代器返回的 Iterator 和由所有 Hashtable 的&#8220;collection 视图方法&#8221;返回的 Collection 的
listIterator 方法都是快速失败 的：在创建 Iterator 之后，如果从结构上对 Hashtable 进行修改，除非通过
Iterator 自身的移除或添加方法，否则在任何时间以任何方式对其进行修改，Iterator 都将抛出
ConcurrentModificationException。因此，面对并发的修改，Iterator
很快就会完全失败，而不冒在将来某个不确定的时间发生任意不确定行为的风险。由 Hashtable 的键和值方法返回的 Enumeration 不
是快速失败的。 <br />
<br />
注意，迭代器的快速失败行为无法得到保证，因为一般来说，不可能对是否出现不同步并发修改做出任何硬性保证。快速失败迭代器会尽最大努力抛出
ConcurrentModificationException。因此，为提高这类迭代器的正确性而编写一个依赖于此异常的程序是错误做法：迭代器的快
速失败行为应该仅用于检测程序错误。
</p>
<img src ="http://www.blogjava.net/calvinlau/aggbug/267242.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/calvinlau/" target="_blank">calvinlau</a> 2009-04-23 22:20 <a href="http://www.blogjava.net/calvinlau/articles/267242.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>HashMap &amp; Hashtable</title><link>http://www.blogjava.net/calvinlau/articles/267238.html</link><dc:creator>calvinlau</dc:creator><author>calvinlau</author><pubDate>Thu, 23 Apr 2009 13:49:00 GMT</pubDate><guid>http://www.blogjava.net/calvinlau/articles/267238.html</guid><wfw:comment>http://www.blogjava.net/calvinlau/comments/267238.html</wfw:comment><comments>http://www.blogjava.net/calvinlau/articles/267238.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/calvinlau/comments/commentRss/267238.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/calvinlau/services/trackbacks/267238.html</trackback:ping><description><![CDATA[关于两者的区别，转载内容如下：<br />
<br />
1、Hashtable是Dictionary的子类，HashMap是Map接口的一个实现类；<br />
<br />
2、<span style="color: red;">Hashtable中的方法是同步的，而HashMap中的方法在缺省情况下是非同步的</span>。即是说，在多线程应用程序中，不用专门的操作就安全地可以使用Hashtable了；而对于
HashMap，则需要额外的同步机制。但HashMap的同步问题可通过Collections的一个静态方法得到解决：<br />
<strong>Map Collections.synchronizedMap(Map m)</strong><br />
这个方法返回一个同步的Map，这个Map封装了底层的HashMap的所有方法，使得底层的HashMap即使是在多线程的环境中也是安全的。<br />
<br />
3、<span style="color: red;">在HashMap中，null可以作为键</span>，这样的键只有一个；可以有一个或多个键所对应的值为null。当get()方法返回null值时，即可以表示
HashMap中没有该键，也可以表示该键所对应的值为null。因此，在HashMap中不能由get()方法来判断HashMap中是否存在某个键，
而应该用containsKey()方法来判断。 <br />
<br />
4、其底层的实现机制不同，HashMap的访问速度要快于Hashtable，因为它不需要进行同步检验，建议在非多线程环境中使用HashMap代替Hashtable<br />
<br />
==================== 分割线：JDK5帮助文档的描述 ==================<em><br />
</em>
<p><strong>HashMap:</strong></p>
<p>基于哈希表的 Map 接口的实现。此实现提供所有可选的映射操作，<span style="color: red;">并允许使用 null 值和 null 键。（除了不同步和允许使用 null 之外，HashMap 类与 Hashtable 大致相同。）</span>此类不保证映射的顺序，特别是它不保证该顺序恒久不变。&nbsp;</p>
<p><br />
此实现假定哈希函数将元素正确分布在各桶之间，可为基本操作（get 和 put）提供稳定的性能。<span style="color: red;">迭代集合视图所需的时间与 HashMap 实例的&#8220;容量&#8221;（桶的数量）及其大小（键-值映射关系数）的和成比例</span>。所以，如果迭代性能很重要，则不要将初始容量设置得太高（或将加载因子设置得太低）。 <br />
<br />
HashMap 的实例有两个参数影响其性能：初始容量和加载因子。容量是哈希表中桶的数量，初始容量只是哈希表在创建时的容量。加载因子 是哈希表在其容量自动增加之前可以达到多满的一种尺度。当哈希表中的条目数超出了加载因子与当前容量的乘积时，通过调用 rehash 方法将容量翻倍。 <br />
<br />
通常，<span style="color: #2058ff;">默认加载因子 (.75) 在时间和空间成本上寻求一种折衷</span>。加载因子过高虽然减少了空间开销，但同时也增加了查询成本（在大多数 HashMap 类的操作中，包括 get 和 put 操作，都反映了这一点）。在设置初始容量时应该考虑到映射中所需的条目数及其加载因子，以便最大限度地降低 rehash 操作次数。如果初始容量大于最大条目数除以加载因子，则不会发生 rehash 操作。 <br />
<br />
如果很多映射关系要存储在 HashMap 实例中，则相对于按需执行自动的 rehash 操作以增大表的容量来说，使用足够大的初始容量创建它将使得映射关系能更有效地存储。 <br />
<br />
注意，<span style="color: #ff0000;">此实现不是同步的</span>。如果多个线程同时访问此映射，而其中至少一个线程从结构上修改了该映射，则它必须保持外部同步。（<span style="color: #ff0000;">结构上的修改是指添加或删除一个或多个映射关系的操作；仅改变与实例已经包含的键关联的值不是结构上的修改</span>。）这一般通过对自然封装该映射的对象进行同步操作来完成。如果不存在这样的对象，则应该使用 Collections.synchronizedMap 方法来&#8220;包装&#8221;该映射。最好在创建时完成这一操作，以防止对映射进行意外的不同步访问，如下所示：<br />
<br />
&nbsp;Map m = Collections.synchronizedMap(new HashMap(...));<br />
&nbsp;<span style="color: #ff0000;">由所有此类的&#8220;集合视图方法&#8221;所返回的迭代器都是快速失败的</span>：在迭代器创建之后，如果从结构上对映射进行修改，除非通过迭代器自身的 remove 或 add 方法，其他任何时间任何方式的修改，迭代器都将抛出 ConcurrentModificationException。因此，面对并发的修改，迭代器很快就会完全失败，而不冒在将来不确定的时间任意发生不确定行为的风险。 <br />
<br />
注意，迭代器的快速失败行为不能得到保证，一般来说，存在不同步的并发修改时，不可能作出任何坚决的保证。快速失败迭代器尽最大努力抛出 ConcurrentModificationException。因此，编写依赖于此异常程序的方式是错误的，正确做法是：迭代器的快速失败行为应该仅用于检测程序错误。&nbsp;</p>
<p><br />
</p>
<p><strong>Hashtable:</strong></p>
<p>此类实现一个哈希表，该哈希表将键映射到相应的值。<span style="color: #ff0000;">任何非 null 对象都可以用作键或值</span>。<br />
<br />
为了成功地在哈希表中存储和检索对象，用作键的对象必须实现 hashCode 方法和 equals 方法。<br />
<br />
Hashtable 的实例有两个参数影响其性能：初始容量和加载因子。容量是哈希表中桶的数量，初始容量就是哈希表创建时的容量。注意，哈希表的状态为 open：在发生&#8220;哈希冲突&#8221;的情况下，单个桶会存储多个条目，这些条目必须按顺序搜索。加载因子是对哈希表在其容量自动增加之前可以达到多满的一个尺度。初始容量和加载因子这两个参数只是对该实现的提示。关于何时以及是否调用 rehash 方法的具体细节则依赖于该实现。<br />
<br />
通常，默认加载因子(.75)在时间和空间成本上寻求一种折衷。加载因子过高虽然减少了空间开销，但同时也增加了查找某个条目的时间（在大多数 Hashtable 操作中，包括 get 和 put 操作，都反映了这一点）。<br />
<br />
初始容量主要控制空间消耗与执行 rehash 操作所需要的时间损耗之间的平衡。如果初始容量大于Hashtable 所包含的最大条目数除以加载因子，则永远不会发生 rehash 操作。但是，将初始容量设置太高可能会浪费空间。<br />
<br />
如果很多条目要存储在一个 Hashtable 中，那么与根据需要执行自动 rehashing 操作来增大表的容量的做法相比，使用足够大的初始容量创建哈希表或许可以更有效地插入条目。<br />
<br />
下面这个示例创建了一个数字的哈希表。它将数字的名称用作键：</p>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #008080;">1</span>&nbsp;<span style="color: #000000;">Hashtable&nbsp;numbers&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Hashtable();<br />
</span><span style="color: #008080;">2</span>&nbsp;<span style="color: #000000;">numbers.put(</span><span style="color: #000000;">"</span><span style="color: #000000;">one</span><span style="color: #000000;">"</span><span style="color: #000000;">,&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Integer(</span><span style="color: #000000;">1</span><span style="color: #000000;">));<br />
</span><span style="color: #008080;">3</span>&nbsp;<span style="color: #000000;">numbers.put(</span><span style="color: #000000;">"</span><span style="color: #000000;">two</span><span style="color: #000000;">"</span><span style="color: #000000;">,&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Integer(</span><span style="color: #000000;">2</span><span style="color: #000000;">));<br />
</span><span style="color: #008080;">4</span>&nbsp;<span style="color: #000000;">numbers.put(</span><span style="color: #000000;">"</span><span style="color: #000000;">three</span><span style="color: #000000;">"</span><span style="color: #000000;">,&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Integer(</span><span style="color: #000000;">3</span><span style="color: #000000;">));</span></div>
<p> 要检索一个数字，可以使用以下代码： <br />
</p>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000;">Integer&nbsp;n&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;(Integer)numbers.get(</span><span style="color: #000000;">"</span><span style="color: #000000;">two</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br />
</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(n&nbsp;</span><span style="color: #000000;">!=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">null</span><span style="color: #000000;">)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span style="color: #000000;">"</span><span style="color: #000000;">two&nbsp;=&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;n);<br />
}</span></div>
<p><br />
&nbsp;自 Java 2 平台 v1.2 以来，此类已经改进为可以实现 Map，因此它变成了 Java Collections Framework 的一部分。与新集合的实现不同，Hashtable 是同步的。<br />
<br />
由迭代器返回的 Iterator 和由所有 Hashtable 的&#8220;collection 视图方法&#8221;返回的 Collection 的 listIterator 方法都是快速失败 的：在创建 Iterator 之后，如果从结构上对 Hashtable 进行修改，除非通过 Iterator 自身的移除或添加方法，否则在任何时间以任何方式对其进行修改，Iterator 都将抛出 ConcurrentModificationException。因此，面对并发的修改，Iterator 很快就会完全失败，而不冒在将来某个不确定的时间发生任意不确定行为的风险。由 Hashtable 的键和值方法返回的 Enumeration 不 是快速失败的。 <br />
<br />
注意，迭代器的快速失败行为无法得到保证，因为一般来说，不可能对是否出现不同步并发修改做出任何硬性保证。快速失败迭代器会尽最大努力抛出 ConcurrentModificationException。因此，为提高这类迭代器的正确性而编写一个依赖于此异常的程序是错误做法：迭代器的快速失败行为应该仅用于检测程序错误。
</p>
<img src ="http://www.blogjava.net/calvinlau/aggbug/267238.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/calvinlau/" target="_blank">calvinlau</a> 2009-04-23 21:49 <a href="http://www.blogjava.net/calvinlau/articles/267238.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>