﻿<?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/gm_jing/category/13225.html</link><description>生活之点点滴滴</description><language>zh-cn</language><lastBuildDate>Tue, 07 Jun 2011 05:06:24 GMT</lastBuildDate><pubDate>Tue, 07 Jun 2011 05:06:24 GMT</pubDate><ttl>60</ttl><item><title>内存溢出 &amp; 内存泄漏</title><link>http://www.blogjava.net/gm_jing/articles/351786.html</link><dc:creator>黎夕</dc:creator><author>黎夕</author><pubDate>Sun, 05 Jun 2011 13:08:00 GMT</pubDate><guid>http://www.blogjava.net/gm_jing/articles/351786.html</guid><wfw:comment>http://www.blogjava.net/gm_jing/comments/351786.html</wfw:comment><comments>http://www.blogjava.net/gm_jing/articles/351786.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/gm_jing/comments/commentRss/351786.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/gm_jing/services/trackbacks/351786.html</trackback:ping><description><![CDATA[<div><h3><a href="http://cyanicbird.iteye.com/blog/547307">关于内存泄漏与内存溢出</a></h3>                 <strong></strong>&nbsp; 内存溢出就是你要求分配的内存超出了系统能给你的，系统不能满足需求，于是产生溢出。 <br /> <br />&nbsp;&nbsp;&nbsp;  内存泄漏是指你向系统申请分配内存进行使用(new)，可是使用完了以后却不归还(delete)，结果你申请到的那块内存你自己也不能再访问（也许你把 它的地址给弄丢了），而系统也不能再次将它分配给需要的程序。一个盘子用尽各种方法只能装4个果子，你装了5个，结果掉倒地上不能吃了。这就是溢出！比方 说栈，栈满时再做进栈必定产生空间溢出，叫上溢，栈空时再做退栈也产生空间溢出，称为下溢。就是分配的内存不足以放下数据项序列,称为内存溢出. <br /> <br />&nbsp;&nbsp; 以发生的方式来分类，内存泄漏可以分为4类：  <br /> <br />1. 常发性内存泄漏。发生内存泄漏的代码会被多次执行到，每次被执行的时候都会导致一块内存泄漏。  <br />2. 偶发性内存泄漏。发生内存泄漏的代码只有在某些特定环境或操作过程下才会发生。常发性和偶发性是相对的。对于特定的环境，偶发性的也许就变成了常发性的。所以测试环境和测试方法对检测内存泄漏至关重要。  <br />3. 一次性内存泄漏。发生内存泄漏的代码只会被执行一次，或者由于算法上的缺陷，导致总会有一块仅且一块内存发生泄漏。比如，在类的构造函数中分配内存，在析构函数中却没有释放该内存，所以内存泄漏只会发生一次。  <br />4.  隐式内存泄漏。程序在运行过程中不停的分配内存，但是直到结束的时候才释放内存。严格的说这里并没有发生内存泄漏，因为最终程序释放了所有申请的内存。但 是对于一个服务器程序，需要运行几天，几周甚至几个月，不及时释放内存也可能导致最终耗尽系统的所有内存。所以，我们称这类内存泄漏为隐式内存泄漏。  <br /> <br />从用户使用程序的角度来看，内存泄漏本身不会产生什么危害，作为一般的用户，根本感觉不到内存泄漏的存在。真正有危害的是内存泄漏的堆积，这会最 终消耗尽系统所有的内存。从这个角度来说，一次性内存泄漏并没有什么危害，因为它不会堆积，而隐式内存泄漏危害性则非常大，因为较之于常发性和偶发性内存 泄漏它更难被检测到</div><img src ="http://www.blogjava.net/gm_jing/aggbug/351786.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/gm_jing/" target="_blank">黎夕</a> 2011-06-05 21:08 <a href="http://www.blogjava.net/gm_jing/articles/351786.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>hashCode()的作用[引]</title><link>http://www.blogjava.net/gm_jing/articles/302069.html</link><dc:creator>黎夕</dc:creator><author>黎夕</author><pubDate>Thu, 12 Nov 2009 03:26:00 GMT</pubDate><guid>http://www.blogjava.net/gm_jing/articles/302069.html</guid><wfw:comment>http://www.blogjava.net/gm_jing/comments/302069.html</wfw:comment><comments>http://www.blogjava.net/gm_jing/articles/302069.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/gm_jing/comments/commentRss/302069.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/gm_jing/services/trackbacks/302069.html</trackback:ping><description><![CDATA[<br />
1.hashcode是用来查找的，如果你学过数据结构就应该知道，在查找和排序这一章有 <br />
例如内存中有这样的位置 <br />
0 1 2 3 4 5 6 7 <br />
而我有个类，这个类有个字段叫ID,我要把这个类存放在以上8个位置之一，如果不用hashcode而任意存放，那么当查找时就需要到这八个位置里挨个去找，或者用二分法一类的算法。 <br />
但如果用hashcode那就会使效率提高很多。 <br />
我们这个类中有个字段叫ID,那么我们就定义我们的hashcode为ID％8，然后把我们的类存放在取得得余数那个位置。比如我们的ID为9，9除8的余数为1，那么我们就把该类存在1这个位置，如果ID是13，求得的余数是5，那么我们就把该类放在5这个位置。这样，以后在查找该类时就可以通过ID除8求余数直接找到存放的位置了。<br />
<br />
2.但是如果两个类有相同的hashcode怎么办那（我们假设上面的类的ID不是唯一的），例如9除以8和17除以8的余数都是1，那么这是不是合法的，回答是：可以这样。那么如何判断呢？在这个时候就需要定义 equals了。 <br />
也就是说，我们先通过 hashcode来判断两个类是否存放某个桶里，但这个桶里可能有很多类，那么我们就需要再通过 equals 来在这个桶里找到我们要的类。 <br />
那么。重写了equals()，为什么还要重写hashCode()呢？ <br />
想想，你要在一个桶里找东西，你必须先要找到这个桶啊，你不通过重写hashcode()来找到桶，光重写equals()有什么用啊 <br />
3。你要对A类排序，有两种方法，一种就是让A类实现comparabole结构并实现compareTo()方法，那么可以通过Collections.sort(List &lt;A&gt; list)对其进行排序 <br />
另一种方法：自己定义一个类B实现Comparator类并实现compare方法， <br />
然后通过Collections.sort(List &lt;A&gt; list,B b)进行排序<br />
<br />
hashCode()是用来产生哈希玛的，而哈希玛是用来在散列存储结构中确定对象的存储地址的，（这一段在 Java编程思想 中讲的很清楚的）象util包中的 带 hash 的集合类都是用这种存储结构 ：HashMap,HashSet, 他们在将对象存储时（严格说是对象引用），需要确定他们的地址吧， 而HashCode()就是这个用途的，一般都需要重新定义它的，因为默认情况下，由 Object 类定义的 hashCode 方法会针对不同的对象返回不同的整数，这一般是通过将该对象的内部地址转换成一个整数来实现的，现在举个例子来说， 就拿HashSet来说 ，在将对象存入其中时，通过被存入对象的 hashCode() 来确定对象在 HashSet 中的存储地址，通过equals()来确定存入的对象是否重复，hashCode() ，equals()都需要自己重新定义，因为hashCode()默认前面已经说啦，而equals() 默认是比较的对象引用，你现在想一下，如果你不定义equals()的话，那么同一个类产生的两个内容完全相同的对象都可以存入Set，因为他们是通过equals()来确定的，这样就使得HashSet 失去了他的意义，看一下下面这个： <br />
import java.util.*;<br />
/**<br />
*类说明<br />
* @author shellfeng E-mail:lsf830804@yahoo.com.cn<br />
* @version 1.0 <br />
*<br />
*/<br />
public class Test {<br />
public static void main(String[] args) {<br />
HashSet set = new HashSet();<br />
for (int i = 0; i &lt;= 3; i++){<br />
set.add(new Demo1(i,i)); <br />
}<br />
System.out.println(set);<br />
set.add(new Demo1(1,1));<br />
System.out.println(set);<br />
System.out.println(set.contains(new Demo1(0,0)));<br />
System.out.println(set.add(new Demo1(1,1)));<br />
System.out.println(set.add(new Demo1(4,4)));<br />
System.out.println(set);<br />
}<br />
<br />
private static class Demo1 {<br />
private int value;<br />
<br />
private int id;<br />
<br />
public Demo1(int value,int id) {<br />
this.value = value;<br />
this.id=id;<br />
}<br />
<br />
public String toString() {<br />
return " value = " + value;<br />
}<br />
<br />
public boolean equals(Object o) {<br />
Demo1 a = (Demo1) o;<br />
return (a.value == value) ? true : false;<br />
}<br />
<br />
public int hashCode() {<br />
return id;<br />
}<br />
}<br />
}<br />
你分别注释掉hashCode()和 equals()来比较一下他们作用就可以拉，关键要自己动手看看比较的结果你就可以记得很清楚啦<br />
<br />
如果还不是很明确可以再看另一个例子:<br />
import java.util.HashMap;<br />
import java.util.Map;<br />
<br />
/**<br />
* <br />
* 类说明<br />
* <br />
* @author shellfeng E-mail:lsf830804@yahoo.com.cn<br />
* @version 1.0<br />
*/<br />
public final class Test {<br />
<br />
public static void main(String[] args) {<br />
Map m = new HashMap();<br />
m.put(new PhoneNumber(020, 12345678), "shellfeng");<br />
System.out.println(m.get(new PhoneNumber(020, 12345678)));<br />
}<br />
<br />
private static class PhoneNumber {<br />
/**<br />
* 区号<br />
*/<br />
private short areaCode;<br />
<br />
/**<br />
* 扩展号<br />
*/<br />
private short extension;<br />
<br />
public PhoneNumber(int areaCode, int extension) {<br />
this.areaCode = (short) areaCode;<br />
this.extension = (short) extension;<br />
}<br />
<br />
public boolean equals(Object o) {<br />
if (o == this) {<br />
return true;<br />
}<br />
if (!(o instanceof PhoneNumber)) {<br />
return false;<br />
}<br />
PhoneNumber pn = (PhoneNumber) o;<br />
return pn.extension == extension &amp;&amp; pn.areaCode == areaCode;<br />
}<br />
<br />
/**<br />
* @see java.lang.Object#hashCode()<br />
* @return result就是我们得到的散列值,其实我们的计算过程可以多种,这里只不过是一个例子,需要你的灵活运用,使其接近你需要的理想结果<br />
*/<br />
public int hashCode() {<br />
int result = 17;<br />
result = 37 * result + areaCode;<br />
result = 37 * result + extension;<br />
return result;<br />
}<br />
}<br />
}<br />
<br />
还是那句话:你注释掉hashCode()比较一下他们作用就可以拉，关键要自己动手看看比较的结果你就可以记得很清楚啦<br />
<br />
总结<br />
hashCode()方法使用来提高Map里面的搜索效率的,Map会根据不同的hashCode()来放在不同的桶里面,Map在搜索一个对象的时候先通过hashCode()找到相应的桶,然后再根据equals()方法找到相应的对象.要正确的实现Map里面查找元素必须满足一下两个条件: <br />
(1)当obj1.equals(obj2)为true时obj1.hashCode() == obj2.hashCode()必须为true <br />
(2)当obj1.hashCode() == obj2.hashCode()为false时obj.equals(obj2)必须为false<br />
<br />
Java中的集合（Collection）有两类，一类是List，再有一类是Set。你知道它们的区别吗？前者集合内的元素是有序的，元素可以重复；后者元素无序，但元素不可重复。<br />
那么这里就有一个比较严重的问题了：要想保证元素不重复，可两个元素是否重复应该依据什么来判断呢？这就是Object.equals方法了。<br />
但是，如果每增加一个元素就检查一次，那么当元素很多时，后添加到集合中的元素比较的次数就非常多了。<br />
也就是说，如果集合中现在已经有1000个元素，那么第1001个元素加入集合时，它就要调用1000次equals方法。这显然会大大降低效率。<br />
哈希算法也称为散列算法，是将数据依特定算法直接指定到一个地址上。我们可以认为hashCode方法返回的就是对象存储的物理地址（实际可能并不是,例如:通过获取对象的物理地址然后除以8再求余,余数几是计算得到的散列值,我们就认为返回一个不是物理地址的数值,而是一个可以映射到物理地址的值）。<br />
这样一来，当集合要添加新的元素时，先调用这个元素的hashCode方法，就一下子能定位到它应该放置的物理位置上。如果这个位置上没有元素，它就可以直接存储在这个位置上，不用再进行任何比较了；如果这个位置上已经有元素了，就调用它的equals方法与新元素进行比较，相同的话就不存了，不相同就散列其它的地址。所以这里存在一个冲突解决的问题。这样一来实际调用equals方法的次数就大大降低了，几乎只需要一两次。<br />
<br />
上面只是我个人的一下理解,有不当之处请大家指教
<img src ="http://www.blogjava.net/gm_jing/aggbug/302069.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/gm_jing/" target="_blank">黎夕</a> 2009-11-12 11:26 <a href="http://www.blogjava.net/gm_jing/articles/302069.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java并发编程-Executor框架</title><link>http://www.blogjava.net/gm_jing/articles/291024.html</link><dc:creator>黎夕</dc:creator><author>黎夕</author><pubDate>Thu, 13 Aug 2009 07:48:00 GMT</pubDate><guid>http://www.blogjava.net/gm_jing/articles/291024.html</guid><wfw:comment>http://www.blogjava.net/gm_jing/comments/291024.html</wfw:comment><comments>http://www.blogjava.net/gm_jing/articles/291024.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/gm_jing/comments/commentRss/291024.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/gm_jing/services/trackbacks/291024.html</trackback:ping><description><![CDATA[<p>[参考] http://www.javaeye.com/topic/366591<br />
http://blog.csdn.net/liuzhengkang/archive/2008/10/24/3137332.aspx<a href="http://www.javaeye.com/topic/366591"></a></p>
<img src ="http://www.blogjava.net/gm_jing/aggbug/291024.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/gm_jing/" target="_blank">黎夕</a> 2009-08-13 15:48 <a href="http://www.blogjava.net/gm_jing/articles/291024.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【引】java 动态代理</title><link>http://www.blogjava.net/gm_jing/articles/281853.html</link><dc:creator>黎夕</dc:creator><author>黎夕</author><pubDate>Fri, 12 Jun 2009 07:42:00 GMT</pubDate><guid>http://www.blogjava.net/gm_jing/articles/281853.html</guid><wfw:comment>http://www.blogjava.net/gm_jing/comments/281853.html</wfw:comment><comments>http://www.blogjava.net/gm_jing/articles/281853.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/gm_jing/comments/commentRss/281853.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/gm_jing/services/trackbacks/281853.html</trackback:ping><description><![CDATA[<p>&nbsp;</p>
Java 1.3引入了名为&#8220;动态代理类&#8221;（Dynamic Proxy Class）的新特性，利用它可为&#8220;已知接口的实现&#8221;动态地创建包装器（wrapper）类。1.3版本问世以前，当我首次听说当时正在提议的动态代理类时，还以为它只是一种用来吸引人的眼球的特性。虽然把它包括到语言中是一件好事，但我却想不出它有任何实际用处。带着这一成见，我试着用动态代理写了一个示例程序，却惊讶于它的巨大威力，并当即决定把它放到我的工具箱中，以便在将来的项目中使用。此后，我不断体验到它的好处，它总是能用正确的方法来做你想要做的事情！ <br />
<br />
假如没有动态代理 <br />
<br />
深入探索动态代理类之前，先来看看在某些情况下，假如没有动态代理类会是什么样子： <br />
<br />
public interface Robot { <br />
void moveTo(int x, int y); <br />
void workOn(Project p, Tool t); <br />
} <br />
<br />
public class MyRobot implements Robot { <br />
public void moveTo(int x, int y) { <br />
// stuff happens here <br />
} <br />
public void workOn(Project p, Tool t) { <br />
// optionally destructive stuff happens here <br />
} <br />
} <br />
<br />
上述代码展示了一个名为Robot的接口，以及该接口的一个名为MyRobot的大致的实现。假定你现在想拦截对MyRobot类发出的方法调用（可能是为了限制一个参数的值）。 <br />
<br />
public class BuilderRobot implements Robot { <br />
private Robot wrapped; <br />
public BuilderRobot(Robot r) { <br />
wrapped = r; <br />
} <br />
public void moveTo(int x, int y) { <br />
wrapped.moveTo(x, y); <br />
} <br />
public void workOn(Project p, Tool t) { <br />
if (t.isDestructive()) { <br />
t = Tool.RATCHET; <br />
} <br />
wrapped.workOn(p, t); <br />
} <br />
} <br />
<br />
一个办法就是使用显式的包装器类，就像上面显示的那样。BuilderRobot类在其构造函数中获取一个Robot，并拦截workOn方法，确保在任何项目中使用的工具都没有破坏性。另外，由于BuilderRobot这一包装器实现了Robot接口，所以凡是能够使用一个Robot的任何地方，都能使用一个BuilderRobot实例。 <br />
<br />
对于这种包装器风格的BuilderRobot来说，一旦你想修改或扩展Robot接口，它的缺点就会暴露无遗。为Robot接口添加一个方法，就得为BuilderRobot类添加一个包装器方法。为Robot添加10个方法，就得为BuilderRobot添加10个方法。如果BuilderRobot、CrusherRobot、SpeedyRobot和SlowRobot都是Robot包装器类，就必须分别为它们添加10个方法。这显然是效率极差的一种方案。 <br />
<br />
public class BuilderRobot extends MyRobot { <br />
public void workOn(Project p, Tool t) { <br />
if (t.isDestructive()) { <br />
t = Tool.RATCHET; <br />
} <br />
super.workOn(p, t); <br />
} <br />
} <br />
<br />
上述代码是对 BuilderRobot进行编程的另一种方式。注意BuilderRobot变成了MyRobot的一个子类。这样可解决在第2段代码的包装器方案中出现的问题。也就是说，修改Robot接口不必修改BuilderRobot。但这又产生了一个新问题：只有MyRobot对象才能是BuilderRobot。而在此之前，实现了Robot接口的任何对象都可以成为一个BuilderRobot。现在，由Java施加的&#8220;线性类出身限制&#8221;（linear class parentage restrictions）禁止我们将任意Robot（ArbitraryRobot）变成一个BuilderRobot。 <br />
<br />
动态代理也有限制 <br />
<br />
动态代理则综合了以上两种方案的优点。使用动态代理，你创建的包装器类不要求为所有方法都使用显式的包装器，创建的子类也不要求具有严格的出身，两者方法可任选一种你认为最好的。但是，动态代理仍然有一个限制。当你使用动态代理时，要包装/扩展的对象必须实现一个接口，该接口定义了准备在包装器中使用的所有方法。这一限制的宗旨是鼓励良好的设计，而不是为你带来更多的麻烦。根据经验，每个类都至少应该实现一个接口（nonconstant接口）。良好的接口用法不仅使动态代理成为可能，还有利于程序的模块化。 <br />
<br />
使用动态代理 <br />
<br />
下面的代码演示了用动态代理来创建一个BuilderRobot时所必需的类。注意我们创建的这个BuilderRobotInvocationHandler类甚至根本没有实现Robot接口。相反，它实现了java.lang.reflect.InvocationHandler，只提供了一个invoke方法。代理对象上的任何方法调用都要通过这一方法进行。观察invoke的主体，我们发现它会检查准备调用的方法的名称。如果这个名称是workOn，第二个参数就切换成一个非破坏性的工具。 <br />
<br />
然而，我们得到的仍然只是一个具有invoke方法的InvocationHandler，而不是我们真正想要的Robot对象。动态代理真正的魅力要到创建实际的Robot实例时才能反映出来。在源代码的任何地方，我们都没有定义一个Robot包装器或者子类。虽然如此，我们最终仍能获得一个动态创建的类，它通过调用BuilderRobotInvocationHandler的静态方法createBuilderRobot中的代码片断，从而实现了Robot接口，并集成了Builder工具过滤器。 <br />
<br />
import java.lang.reflect.Proxy; <br />
import java.lang.reflect.InvocationHandler; <br />
import java.lang.reflect.Method; <br />
<br />
public class BuilderRobotInvocationHandler implements InvocationHandler { <br />
private Robot wrapped; <br />
public BuilderRobotInvocationHandler(Robot r) { <br />
wrapped = r; <br />
} <br />
public Object invoke(Object proxy, Method method, Object[] args) <br />
throws Throwable { <br />
if ("workOn".equals(method.getName())) { <br />
args[1] = Tool.RATCHET; <br />
} <br />
return method.invoke(wrapped, args); <br />
} <br />
public static Robot createBuilderRobot(Robot toWrap) { <br />
return (Robot)(Proxy.newProxyInstance(Robot.class.getClassLoader(), <br />
new Class[] {Robot.class}, <br />
new BuilderRobotInvocationHandler(toWrap))); <br />
} <br />
public static final void main(String[] args) { <br />
Robot r = createBuilderRobot(new MyRobot()); <br />
r.workOn("scrap", Tool.CUTTING_TORCH); <br />
} <br />
} <br />
<br />
createBuilderRobot中的代码表面上很复杂，但它的作用其实很简单，就是告诉Proxy类用一个指定的类加载器来动态创建一个对象，该对象要实现指定的接口（本例为Robot），并用提供的InvocationHandler来代替传统的方法主体。结果对象在一个instanceof Robot测试中返回true，并提供了在实现了Robot接口的任何类中都能找到的方法。 <br />
<br />
有趣的是，在BuilderRobotInvocationHandler类的invoke方法中，完全不存在对Robot接口的引用。InvocationHandlers并不是它们向其提供了&#8220;代理方法实现&#8221;的接口所专用的，你完全可以写一个InvocationHandler，并将其作为众多代理类的后端来使用。 <br />
但在本例中，我们以构造函数参数的形式，为BuilderRobotInvocationHandler提供了RobotInterface的另一个实例。代理Robot实例上的任何方法调用最终都由BuilderRobotInvocationHandler委托给这个&#8220;包装的&#8221;Robot。但是，虽然这是最常见的设计，但你必须了解，InvocationHandler不一定非要委托给被代理的接口的另一个实例。事实上，InvocationHandler完全能自行提供方法主体，而无需一个委托目标。 <br />
<br />
最后要注意，如果Robot接口中发生改变，那么BuilderRobotInvocationHandler中的invoke方法将反应迟钝。例如，假定workOn方法被重命名，那么非破坏性工具陷阱会悄悄地失败，这时的BuilderRobots就有可能造成损害。较容易检测、但却不一定会造成问题的是workOn方法的重载版本。如果方法具有相同的名称，但使用一个不同的参数列表，就可能在运行时造成一个ClassCastException或者ArrayIndexOutOfBoundsException异常。为此，以下代码给出了一个解决方案，它能生成一个更灵活的BuilderRobotInvocationHandler。在这段代码中，任何时候在任何方法中使用一个工具，这个工具就会被替换成一个非破坏性工具。请试着用子类化处理或者传统的委托来进行试验。 <br />
<br />
import java.lang.reflect.Proxy; <br />
import java.lang.reflect.InvocationHandler; <br />
import java.lang.reflect.Method; <br />
<br />
public class BuilderRobotInvocationHandler implements InvocationHandler { <br />
private Robot wrapped; <br />
public BuilderRobotInvocationHandler(Robot r) { <br />
wrapped = r; <br />
} <br />
public Object invoke(Object proxy, Method method, Object[] args) <br />
throws Throwable { <br />
Class[] paramTypes = method.getParameterTypes(); <br />
for (int i=0; i &lt; paramTypes.length; i++) { <br />
if (Tool.class.isAssignableFrom(paramTypes[i])) { <br />
args[i] = Tool.RATCHET; <br />
} <br />
} <br />
return method.invoke(wrapped, args); <br />
} <br />
public static Robot createBuilderRobot(Robot toWrap) { <br />
return (Robot)(Proxy.newProxyInstance(Robot.class.getClassLoader(), <br />
new Class[] {Robot.class}, <br />
new BuilderRobotInvocationHandler(toWrap))); <br />
} <br />
public static final void main(String[] args) { <br />
Robot r = createBuilderRobot(new MyRobot()); <br />
r.workOn("scrap", Tool.CUTTING_TORCH); <br />
} <br />
} <br />
使用建议 <br />
<br />
在大多数开发环境中，用工具来取代Robot并不是一种常见的操作。还有其他许多方式可以使用动态代理。它们提供了一个调试层，可方便地记录一个对象上的所有方法调用的具体细节。它们可执行绑定检查，并对方法参数进行验证。在与远程数据源发生冲突的前提下，甚至可用它们将备用的本地测试后端动态地交换出去。如果你采用的是良好的、由接口驱动的设计方案，我个人觉得动态代理的用处肯定要比你想象的多，最终你会叹服于它从容解决许多问题的本事！
<img src ="http://www.blogjava.net/gm_jing/aggbug/281853.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/gm_jing/" target="_blank">黎夕</a> 2009-06-12 15:42 <a href="http://www.blogjava.net/gm_jing/articles/281853.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JAVA反射机制</title><link>http://www.blogjava.net/gm_jing/articles/256527.html</link><dc:creator>黎夕</dc:creator><author>黎夕</author><pubDate>Tue, 24 Feb 2009 15:20:00 GMT</pubDate><guid>http://www.blogjava.net/gm_jing/articles/256527.html</guid><wfw:comment>http://www.blogjava.net/gm_jing/comments/256527.html</wfw:comment><comments>http://www.blogjava.net/gm_jing/articles/256527.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/gm_jing/comments/commentRss/256527.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/gm_jing/services/trackbacks/256527.html</trackback:ping><description><![CDATA[<p align="justify">&nbsp;</p>
<div class="gut_p" id="cText">
<p><strong></strong>&nbsp;</p>
<div class="content"><!-- 开始 主体内容 -->
<p>JAVA反射机制<br />
&nbsp;&nbsp;&nbsp;&nbsp;JAVA反射机制是在运行状态中，对于任意一个类，都能够知道这个类的所有属性和方法；对于任意一个对象，都能够调用它的任意一个方法；这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。<br />
Java反射机制主要提供了以下功能：&nbsp;在运行时判断任意一个对象所属的类；在运行时构造任意一个类的对象；在运行时判断任意一个类所具有的成员变量和方法；在运行时调用任意一个对象的方法；生成动态代理。<br />
1.&nbsp;得到某个对象的属性<br />
<br />
1&nbsp;public&nbsp;Object&nbsp;getProperty(Object&nbsp;owner,&nbsp;String&nbsp;fieldName)&nbsp;throws&nbsp;Exception&nbsp;{<br />
2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Class&nbsp;ownerClass&nbsp;=&nbsp;owner.getClass();<br />
3&nbsp;<br />
4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Field&nbsp;field&nbsp;=&nbsp;ownerClass.getField(fieldName);<br />
5&nbsp;<br />
6&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Object&nbsp;property&nbsp;=&nbsp;field.get(owner);<br />
7&nbsp;<br />
8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;property;<br />
9&nbsp;}<br />
Class&nbsp;ownerClass&nbsp;=&nbsp;owner.getClass()：得到该对象的Class。<br />
<br />
Field&nbsp;field&nbsp;=&nbsp;ownerClass.getField(fieldName)：通过Class得到类声明的属性。<br />
<br />
Object&nbsp;property&nbsp;=&nbsp;field.get(owner)：通过对象得到该属性的实例，如果这个属性是非公有的，这里会报IllegalAccessException。<br />
<br />
2.&nbsp;得到某个类的静态属性<br />
<br />
&nbsp;1&nbsp;public&nbsp;Object&nbsp;getStaticProperty(String&nbsp;className,&nbsp;String&nbsp;fieldName)<br />
&nbsp;2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throws&nbsp;Exception&nbsp;{<br />
&nbsp;3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Class&nbsp;ownerClass&nbsp;=&nbsp;Class.forName(className);<br />
&nbsp;4&nbsp;<br />
&nbsp;5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Field&nbsp;field&nbsp;=&nbsp;ownerClass.getField(fieldName);<br />
&nbsp;6&nbsp;<br />
&nbsp;7&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Object&nbsp;property&nbsp;=&nbsp;field.get(ownerClass);<br />
&nbsp;8&nbsp;<br />
&nbsp;9&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;property;<br />
10&nbsp;}<br />
<br />
Class&nbsp;ownerClass&nbsp;=&nbsp;Class.forName(className)&nbsp;：首先得到这个类的Class。<br />
<br />
Field&nbsp;field&nbsp;=&nbsp;ownerClass.getField(fieldName)：和上面一样，通过Class得到类声明的属性。<br />
<br />
Object&nbsp;property&nbsp;=&nbsp;field.get(ownerClass)&nbsp;：这里和上面有些不同，因为该属性是静态的，所以直接从类的Class里取。<br />
<br />
3.&nbsp;执行某对象的方法<br />
<br />
&nbsp;1&nbsp;public&nbsp;Object&nbsp;invokeMethod(Object&nbsp;owner,&nbsp;String&nbsp;methodName,&nbsp;Object[]&nbsp;args)&nbsp;throws&nbsp;Exception&nbsp;{<br />
&nbsp;2&nbsp;<br />
&nbsp;3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Class&nbsp;ownerClass&nbsp;=&nbsp;owner.getClass();<br />
&nbsp;4&nbsp;<br />
&nbsp;5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Class[]&nbsp;argsClass&nbsp;=&nbsp;new&nbsp;Class[args.length];<br />
&nbsp;6&nbsp;<br />
&nbsp;7&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(int&nbsp;i&nbsp;=&nbsp;0,&nbsp;j&nbsp;=&nbsp;args.length;&nbsp;i&nbsp;&lt;&nbsp;j;&nbsp;i++)&nbsp;{<br />
&nbsp;8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;argsClass[i]&nbsp;=&nbsp;args[i].getClass();<br />
&nbsp;9&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
10&nbsp;<br />
11&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Method&nbsp;method&nbsp;=&nbsp;ownerClass.getMethod(methodName,&nbsp;argsClass);<br />
12&nbsp;<br />
13&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;method.invoke(owner,&nbsp;args);<br />
14&nbsp;}<br />
Class&nbsp;owner_class&nbsp;=&nbsp;owner.getClass()&nbsp;：首先还是必须得到这个对象的Class。<br />
<br />
5～9行：配置参数的Class数组，作为寻找Method的条件。<br />
<br />
Method&nbsp;method&nbsp;=&nbsp;ownerClass.getMethod(methodName,&nbsp;argsClass)：通过Method名和参数的Class数组得到要执行的Method。<br />
<br />
method.invoke(owner,&nbsp;args)：执行该Method，invoke方法的参数是执行这个方法的对象，和参数数组。返回值是Object，也既是该方法的返回值。<br />
<br />
4.&nbsp;执行某个类的静态方法<br />
<br />
&nbsp;1&nbsp;public&nbsp;Object&nbsp;invokeStaticMethod(String&nbsp;className,&nbsp;String&nbsp;methodName,<br />
&nbsp;2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Object[]&nbsp;args)&nbsp;throws&nbsp;Exception&nbsp;{<br />
&nbsp;3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Class&nbsp;ownerClass&nbsp;=&nbsp;Class.forName(className);<br />
&nbsp;4&nbsp;<br />
&nbsp;5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Class[]&nbsp;argsClass&nbsp;=&nbsp;new&nbsp;Class[args.length];<br />
&nbsp;6&nbsp;<br />
&nbsp;7&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(int&nbsp;i&nbsp;=&nbsp;0,&nbsp;j&nbsp;=&nbsp;args.length;&nbsp;i&nbsp;&lt;&nbsp;j;&nbsp;i++)&nbsp;{<br />
&nbsp;8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;argsClass[i]&nbsp;=&nbsp;args[i].getClass();<br />
&nbsp;9&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
10&nbsp;<br />
11&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Method&nbsp;method&nbsp;=&nbsp;ownerClass.getMethod(methodName,&nbsp;argsClass);<br />
12&nbsp;<br />
13&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;method.invoke(null,&nbsp;args);<br />
14&nbsp;}<br />
<br />
基本的原理和实例3相同，不同点是最后一行，invoke的一个参数是null，因为这是静态方法，不需要借助实例运行。<br />
<br />
5.&nbsp;新建实例<br />
&nbsp;1&nbsp;<br />
&nbsp;2&nbsp;public&nbsp;Object&nbsp;newInstance(String&nbsp;className,&nbsp;Object[]&nbsp;args)&nbsp;throws&nbsp;Exception&nbsp;{<br />
&nbsp;3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Class&nbsp;newoneClass&nbsp;=&nbsp;Class.forName(className);<br />
&nbsp;4&nbsp;<br />
&nbsp;5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Class[]&nbsp;argsClass&nbsp;=&nbsp;new&nbsp;Class[args.length];<br />
&nbsp;6&nbsp;<br />
&nbsp;7&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(int&nbsp;i&nbsp;=&nbsp;0,&nbsp;j&nbsp;=&nbsp;args.length;&nbsp;i&nbsp;&lt;&nbsp;j;&nbsp;i++)&nbsp;{<br />
&nbsp;8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;argsClass[i]&nbsp;=&nbsp;args[i].getClass();<br />
&nbsp;9&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
10&nbsp;<br />
11&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Constructor&nbsp;cons&nbsp;=&nbsp;newoneClass.getConstructor(argsClass);<br />
12&nbsp;<br />
13&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;cons.newInstance(args);<br />
14&nbsp;<br />
15&nbsp;}<br />
<br />
这里说的方法是执行带参数的构造函数来新建实例的方法。如果不需要参数，可以直接使用newoneClass.newInstance()来实现。<br />
<br />
Class&nbsp;newoneClass&nbsp;=&nbsp;Class.forName(className)：第一步，得到要构造的实例的Class。<br />
<br />
第5～第9行：得到参数的Class数组。<br />
<br />
Constructor&nbsp;cons&nbsp;=&nbsp;newoneClass.getConstructor(argsClass)：得到构造子。<br />
<br />
cons.newInstance(args)：新建实例。<br />
<br />
6.&nbsp;判断是否为某个类的实例<br />
<br />
1&nbsp;public&nbsp;boolean&nbsp;isInstance(Object&nbsp;obj,&nbsp;Class&nbsp;cls)&nbsp;{<br />
2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;cls.isInstance(obj);<br />
3&nbsp;}<br />
<br />
7.&nbsp;得到数组中的某个元素<br />
1&nbsp;public&nbsp;Object&nbsp;getByArray(Object&nbsp;array,&nbsp;int&nbsp;index)&nbsp;{<br />
2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;Array.get(array,index);<br />
3&nbsp;}</p>
</div>
</div>
<img src ="http://www.blogjava.net/gm_jing/aggbug/256527.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/gm_jing/" target="_blank">黎夕</a> 2009-02-24 23:20 <a href="http://www.blogjava.net/gm_jing/articles/256527.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java.util.ConcurrentModificationException</title><link>http://www.blogjava.net/gm_jing/articles/255878.html</link><dc:creator>黎夕</dc:creator><author>黎夕</author><pubDate>Fri, 20 Feb 2009 10:10:00 GMT</pubDate><guid>http://www.blogjava.net/gm_jing/articles/255878.html</guid><wfw:comment>http://www.blogjava.net/gm_jing/comments/255878.html</wfw:comment><comments>http://www.blogjava.net/gm_jing/articles/255878.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/gm_jing/comments/commentRss/255878.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/gm_jing/services/trackbacks/255878.html</trackback:ping><description><![CDATA[<p>工作中碰到个ConcurrentModificationException。代码如下：<br />
<span style="color: #0000ff">List list = ...;<br />
for(Iterator iter = list.iterator(); iter.hasNext();) {<br />
&nbsp;&nbsp;&nbsp; Object obj = iter.next();<br />
&nbsp;&nbsp;&nbsp; ...<br />
&nbsp;&nbsp;&nbsp; if(***) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; list.remove(obj);<br />
&nbsp;&nbsp;&nbsp; }<br />
}<br />
</span>在执行了remove方法之后，再去执行循环，iter.next()的时候，报java.util.ConcurrentModificationException(当然，如果remove的是最后一条，就不会再去执行next()操作了)<br />
<br />
下面来看一下源码<br />
<span style="color: #0000ff">public interface Iterator&lt;E&gt; {<br />
&nbsp;&nbsp;&nbsp; boolean hasNext();<br />
&nbsp;&nbsp;&nbsp; E next();<br />
&nbsp;&nbsp;&nbsp; void remove();<br />
}<br />
<br />
public interface Collection&lt;E&gt; extends Iterable&lt;E&gt; {<br />
&nbsp;&nbsp;&nbsp; ...<br />
&nbsp;&nbsp;&nbsp; Iterator&lt;E&gt; iterator();<br />
&nbsp;&nbsp;&nbsp; boolean add(E o);<br />
&nbsp;&nbsp;&nbsp; boolean remove(Object o);<br />
&nbsp;&nbsp;&nbsp; ...<br />
}</span><br />
这里有两个remove方法<br />
<br />
接下来来看看AbstractList<br />
<span style="color: #0000ff">public abstract class AbstractList&lt;E&gt; extends AbstractCollection&lt;E&gt; implements List&lt;E&gt; {&nbsp; <br />
//AbstractCollection和List都继承了Collection<br />
&nbsp;&nbsp;&nbsp; protected transient int modCount = 0;<br />
&nbsp;&nbsp;&nbsp; private class Itr implements Iterator&lt;E&gt; {&nbsp; //内部类Itr<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int cursor = 0;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int lastRet = -1;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int expectedModCount = modCount;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public boolean hasNext() {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return cursor != size();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public E next() {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; checkForComodification();&nbsp; <span style="color: #ff0000">//特别注意这个方法<br />
</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; E next = get(cursor);<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lastRet = cursor++;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return next;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch(IndexOutOfBoundsException e) {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; checkForComodification();<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw new NoSuchElementException();<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void remove() {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (lastRet == -1)<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw new IllegalStateException();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; checkForComodification();<br />
<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AbstractList.this.remove(lastRet);&nbsp; <span style="color: #ff0000">//执行remove对象的操作<br />
</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (lastRet &lt; cursor)<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cursor--;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lastRet = -1;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; expectedModCount = modCount;&nbsp; <span style="color: #ff0000">//重新设置了expectedModCount的值，避免了ConcurrentModificationException的产生<br />
</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch(IndexOutOfBoundsException e) {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw new ConcurrentModificationException();<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; final void checkForComodification() {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (modCount != expectedModCount)&nbsp; <span style="color: #ff0000">//当expectedModCount和modCount不相等时，就抛出ConcurrentModificationException</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw new ConcurrentModificationException();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp; <br />
}</span><br />
<br />
remove(Object o)在ArrayList中实现如下：<br />
<span style="color: #0000ff">public boolean remove(Object o) {<br />
&nbsp;&nbsp;&nbsp; if (o == null) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (int index = 0; index &lt; size; index++)<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if (elementData[index] == null) {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; fastRemove(index);<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return true;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; } else {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; for (int index = 0; index &lt; size; index++)<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (o.equals(elementData[index])) {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fastRemove(index);<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return true;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; return false;<br />
}<br />
private void fastRemove(int index) {<br />
&nbsp;&nbsp;&nbsp; modCount++;&nbsp; <span style="color: #ff0000">//只增加了modCount<br />
</span>&nbsp;&nbsp;&nbsp; ....<br />
}<br />
<span style="color: #339966"><br />
<strong style="color: #800000">所以，产生ConcurrentModificationException的原因就是：<br />
执行remove(Object o)方法之后，modCount和expectedModCount不相等了。然后当代码执行到next()方法时，判断了checkForComodification()，发现两个数值不等，就抛出了该Exception。<br />
要避免这个Exception，就应该使用remove()方法。</strong></span><strong><br />
</strong></span>这里我们就不看add(Object o)方法了，也是同样的原因，但没有对应的add()方法。一般嘛，就另建一个List了<br />
<br />
<br />
下面是网上的其他解释，更能从本质上解释原因：<br />
Iterator 是工作在一个独立的线程中，并且拥有一个 mutex 锁。 Iterator 被创建之后会建立一个指向原来对象的单链索引表，当原来的对象数量发生变化时，这个索引表的内容不会同步改变，所以当索引指针往后移动的时候就找不到要迭代的对象，所以按照 fail-fast 原则 Iterator 会马上抛出 java.util.ConcurrentModificationException 异常。<br />
所以 Iterator 在工作的时候是不允许被迭代的对象被改变的。但你可以使用 Iterator 本身的方法 remove() 来删除对象， Iterator.remove() 方法会在删除当前迭代对象的同时维护索引的一致性。<br />
</p>
<img src ="http://www.blogjava.net/gm_jing/aggbug/255878.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/gm_jing/" target="_blank">黎夕</a> 2009-02-20 18:10 <a href="http://www.blogjava.net/gm_jing/articles/255878.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java入门--认识理解Java中native方法</title><link>http://www.blogjava.net/gm_jing/articles/249769.html</link><dc:creator>黎夕</dc:creator><author>黎夕</author><pubDate>Sun, 04 Jan 2009 09:23:00 GMT</pubDate><guid>http://www.blogjava.net/gm_jing/articles/249769.html</guid><wfw:comment>http://www.blogjava.net/gm_jing/comments/249769.html</wfw:comment><comments>http://www.blogjava.net/gm_jing/articles/249769.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/gm_jing/comments/commentRss/249769.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/gm_jing/services/trackbacks/249769.html</trackback:ping><description><![CDATA[【引】http://www.enet.com.cn/article/2007/1029/A20071029886398.shtml<br />
<br />
Java不是完美的，Java的不足除了体现在运行速度上要比传统的C++慢许多之外，Java无法直接访问到操作系统底层（如系统硬件等)，为此Java使用native方法来扩展Java程序的功能。 <br />
<br />
　　可以将native方法比作Java程序同Ｃ程序的接口，其实现步骤： <br />
<br />
　　１、在Java中声明native()方法，然后编译； <br />
<br />
　　２、用javah产生一个.h文件； <br />
<br />
　　３、写一个.cpp文件实现native导出方法，其中需要包含第二步产生的.h文件（注意其中又包含了JDK带的jni.h文件）； <br />
<br />
　　４、将第三步的.cpp文件编译成动态链接库文件； <br />
<br />
　　５、在Java中用System.loadLibrary()方法加载第四步产生的动态链接库文件，这个native()方法就可以在Java中被访问了。 <br />
<br />
　　JAVA本地方法适用的情况 <br />
<br />
　　1.为了使用底层的主机平台的某个特性，而这个特性不能通过JAVA API访问 <br />
<br />
　　2.为了访问一个老的系统或者使用一个已有的库，而这个系统或这个库不是用JAVA编写的 <br />
<br />
　　3.为了加快程序的性能，而将一段时间敏感的代码作为本地方法实现。 <br />
<br />
　　首先写好JAVA文件 <br />
<br />
　　/* <br />
<br />
　　* Created on 2005-12-19 Author shaoqi <br />
<br />
　　*/ <br />
<br />
　　package com.hode.hodeframework.modelupdate; <br />
<br />
　　public class CheckFile <br />
<br />
　　{ <br />
<br />
　　public native void displayHelloWorld(); <br />
<br />
　　static <br />
<br />
　　{ <br />
<br />
　　System.loadLibrary("test"); <br />
<br />
　　} <br />
<br />
　　public static void main(String[] args) { <br />
<br />
　　new CheckFile().displayHelloWorld(); <br />
<br />
　　} <br />
<br />
　　} <br />
<br />
　　然后根据写好的文件编译成CLASS文件 <br />
<br />
　　然后在classes或bin之类的class根目录下执行javah -jni com.hode.hodeframework.modelupdate.CheckFile， <br />
<br />
　　就会在根目录下得到一个com_hode_hodeframework_modelupdate_CheckFile.h的文件 <br />
<br />
　　然后根据头文件的内容编写com_hode_hodeframework_modelupdate_CheckFile.c文件 <br />
<br />
　　#include "CheckFile.h" <br />
<br />
　　#include <br />
<br />
　　#include <br />
<br />
　　JNIEXPORT void JNICALL Java_com_hode_hodeframework_modelupdate_CheckFile_displayHelloWorld(JNIEnv *env, jobject obj) <br />
<br />
　　{ <br />
<br />
　　printf("Hello world!\n"); <br />
<br />
　　return; <br />
<br />
　　} <br />
<br />
　　之后编译生成DLL文件如&#8220;test.dll&#8221;，名称与System.loadLibrary("test")中的名称一致 <br />
<br />
　　 vc的编译方法：cl -I%java_home%\include -I%java_home%\include\win32 -LD com_hode_hodeframework_modelupdate_CheckFile.c -Fetest.dll <br />
<br />
　　最后在运行时加参数-Djava.library.path=[dll存放的路径]<a href="http://www.enet.com.cn/"><img height="11" src="http://images.enet.com.cn/end.gif" width="11" align="absMiddle" border="0" target="_blank"  alt="" /></a><br />
<img src ="http://www.blogjava.net/gm_jing/aggbug/249769.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/gm_jing/" target="_blank">黎夕</a> 2009-01-04 17:23 <a href="http://www.blogjava.net/gm_jing/articles/249769.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java中synchronized的使用方法 </title><link>http://www.blogjava.net/gm_jing/articles/249697.html</link><dc:creator>黎夕</dc:creator><author>黎夕</author><pubDate>Sun, 04 Jan 2009 02:23:00 GMT</pubDate><guid>http://www.blogjava.net/gm_jing/articles/249697.html</guid><wfw:comment>http://www.blogjava.net/gm_jing/comments/249697.html</wfw:comment><comments>http://www.blogjava.net/gm_jing/articles/249697.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/gm_jing/comments/commentRss/249697.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/gm_jing/services/trackbacks/249697.html</trackback:ping><description><![CDATA[<strong>【引用】http://www.blogjava.net/baiyucheng/archive/2008/12/01/243592.html<br />
synchronized的一个简单例子<br />
</strong>
<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 alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" /><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">class</span><span style="color: #000000">&nbsp;TextThread<br />
<img id="Codehighlighter1_26_263_Open_Image" onclick="this.style.display='none'; Codehighlighter1_26_263_Open_Text.style.display='none'; Codehighlighter1_26_263_Closed_Image.style.display='inline'; Codehighlighter1_26_263_Closed_Text.style.display='inline';" alt="" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_26_263_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_26_263_Closed_Text.style.display='none'; Codehighlighter1_26_263_Open_Image.style.display='inline'; Codehighlighter1_26_263_Open_Text.style.display='inline';" alt="" src="http://www.blogjava.net/Images/OutliningIndicators/ContractedBlock.gif" align="top" />　　</span><span id="Codehighlighter1_26_263_Open_Text"><span style="color: #000000">{<br />
<img id="Codehighlighter1_30_53_Open_Image" onclick="this.style.display='none'; Codehighlighter1_30_53_Open_Text.style.display='none'; Codehighlighter1_30_53_Closed_Image.style.display='inline'; Codehighlighter1_30_53_Closed_Text.style.display='inline';" alt="" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_30_53_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_30_53_Closed_Text.style.display='none'; Codehighlighter1_30_53_Open_Image.style.display='inline'; Codehighlighter1_30_53_Open_Text.style.display='inline';" alt="" src="http://www.blogjava.net/Images/OutliningIndicators/ContractedSubBlock.gif" align="top" />　</span><span id="Codehighlighter1_30_53_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">/</span><span id="Codehighlighter1_30_53_Open_Text"><span style="color: #008000">/**</span><span style="color: #008000"><br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align="top" />　　*&nbsp;</span><span style="color: #808080">@param</span><span style="color: #008000">&nbsp;args<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />　　</span><span style="color: #008000">*/</span></span><span style="color: #000000"><br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align="top" />　　</span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">static</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;main(String[]&nbsp;args)<br />
<img id="Codehighlighter1_98_259_Open_Image" onclick="this.style.display='none'; Codehighlighter1_98_259_Open_Text.style.display='none'; Codehighlighter1_98_259_Closed_Image.style.display='inline'; Codehighlighter1_98_259_Closed_Text.style.display='inline';" alt="" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_98_259_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_98_259_Closed_Text.style.display='none'; Codehighlighter1_98_259_Open_Image.style.display='inline'; Codehighlighter1_98_259_Open_Text.style.display='inline';" alt="" src="http://www.blogjava.net/Images/OutliningIndicators/ContractedSubBlock.gif" align="top" />　　</span><span id="Codehighlighter1_98_259_Open_Text"><span style="color: #000000">{<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align="top" />　　</span><span style="color: #008000">//</span><span style="color: #008000">&nbsp;TODO&nbsp;自动生成方法存根</span><span style="color: #008000"><br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align="top" /></span><span style="color: #000000">　　TxtThread&nbsp;tt&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;TxtThread();<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align="top" />　　</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;Thread(tt).start();<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align="top" />　　</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;Thread(tt).start();<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align="top" />　　</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;Thread(tt).start();<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align="top" />　　</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;Thread(tt).start();<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />　　}</span></span><span style="color: #000000"><br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />　　}</span></span><span style="color: #000000"><br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" />　　</span><span style="color: #0000ff">class</span><span style="color: #000000">&nbsp;TxtThread&nbsp;</span><span style="color: #0000ff">implements</span><span style="color: #000000">&nbsp;Runnable<br />
<img id="Codehighlighter1_305_611_Open_Image" onclick="this.style.display='none'; Codehighlighter1_305_611_Open_Text.style.display='none'; Codehighlighter1_305_611_Closed_Image.style.display='inline'; Codehighlighter1_305_611_Closed_Text.style.display='inline';" alt="" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_305_611_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_305_611_Closed_Text.style.display='none'; Codehighlighter1_305_611_Open_Image.style.display='inline'; Codehighlighter1_305_611_Open_Text.style.display='inline';" alt="" src="http://www.blogjava.net/Images/OutliningIndicators/ContractedBlock.gif" align="top" />　　</span><span id="Codehighlighter1_305_611_Open_Text"><span style="color: #000000">{<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align="top" />　　</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;num&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">100</span><span style="color: #000000">;<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align="top" />　　String&nbsp;str&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;String();<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align="top" />　　</span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;run()<br />
<img id="Codehighlighter1_375_607_Open_Image" onclick="this.style.display='none'; Codehighlighter1_375_607_Open_Text.style.display='none'; Codehighlighter1_375_607_Closed_Image.style.display='inline'; Codehighlighter1_375_607_Closed_Text.style.display='inline';" alt="" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_375_607_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_375_607_Closed_Text.style.display='none'; Codehighlighter1_375_607_Open_Image.style.display='inline'; Codehighlighter1_375_607_Open_Text.style.display='inline';" alt="" src="http://www.blogjava.net/Images/OutliningIndicators/ContractedSubBlock.gif" align="top" />　　</span><span id="Codehighlighter1_375_607_Open_Text"><span style="color: #000000">{<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align="top" />　　</span><span style="color: #0000ff">while</span><span style="color: #000000">&nbsp;(</span><span style="color: #0000ff">true</span><span style="color: #000000">)<br />
<img id="Codehighlighter1_394_603_Open_Image" onclick="this.style.display='none'; Codehighlighter1_394_603_Open_Text.style.display='none'; Codehighlighter1_394_603_Closed_Image.style.display='inline'; Codehighlighter1_394_603_Closed_Text.style.display='inline';" alt="" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_394_603_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_394_603_Closed_Text.style.display='none'; Codehighlighter1_394_603_Open_Image.style.display='inline'; Codehighlighter1_394_603_Open_Text.style.display='inline';" alt="" src="http://www.blogjava.net/Images/OutliningIndicators/ContractedSubBlock.gif" align="top" />　　</span><span id="Codehighlighter1_394_603_Open_Text"><span style="color: #000000">{<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align="top" />　　</span><span style="color: #0000ff">synchronized</span><span style="color: #000000">(str)<br />
<img id="Codehighlighter1_418_599_Open_Image" onclick="this.style.display='none'; Codehighlighter1_418_599_Open_Text.style.display='none'; Codehighlighter1_418_599_Closed_Image.style.display='inline'; Codehighlighter1_418_599_Closed_Text.style.display='inline';" alt="" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_418_599_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_418_599_Closed_Text.style.display='none'; Codehighlighter1_418_599_Open_Image.style.display='inline'; Codehighlighter1_418_599_Open_Text.style.display='inline';" alt="" src="http://www.blogjava.net/Images/OutliningIndicators/ContractedSubBlock.gif" align="top" />　　</span><span id="Codehighlighter1_418_599_Open_Text"><span style="color: #000000">{<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align="top" />　　</span><span style="color: #0000ff">if</span><span style="color: #000000">&nbsp;(num</span><span style="color: #000000">&gt;</span><span style="color: #000000">0</span><span style="color: #000000">)<br />
<img id="Codehighlighter1_435_595_Open_Image" onclick="this.style.display='none'; Codehighlighter1_435_595_Open_Text.style.display='none'; Codehighlighter1_435_595_Closed_Image.style.display='inline'; Codehighlighter1_435_595_Closed_Text.style.display='inline';" alt="" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_435_595_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_435_595_Closed_Text.style.display='none'; Codehighlighter1_435_595_Open_Image.style.display='inline'; Codehighlighter1_435_595_Open_Text.style.display='inline';" alt="" src="http://www.blogjava.net/Images/OutliningIndicators/ContractedSubBlock.gif" align="top" />　　</span><span id="Codehighlighter1_435_595_Open_Text"><span style="color: #000000">{<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align="top" />　　</span><span style="color: #0000ff">try</span><span style="color: #000000"><br />
<img id="Codehighlighter1_445_469_Open_Image" onclick="this.style.display='none'; Codehighlighter1_445_469_Open_Text.style.display='none'; Codehighlighter1_445_469_Closed_Image.style.display='inline'; Codehighlighter1_445_469_Closed_Text.style.display='inline';" alt="" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_445_469_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_445_469_Closed_Text.style.display='none'; Codehighlighter1_445_469_Open_Image.style.display='inline'; Codehighlighter1_445_469_Open_Text.style.display='inline';" alt="" src="http://www.blogjava.net/Images/OutliningIndicators/ContractedSubBlock.gif" align="top" />　　</span><span id="Codehighlighter1_445_469_Open_Text"><span style="color: #000000">{<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align="top" />　　Thread.sleep(</span><span style="color: #000000">10</span><span style="color: #000000">);<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />　　}</span></span><span style="color: #000000"><br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align="top" />　　</span><span style="color: #0000ff">catch</span><span style="color: #000000">(Exception&nbsp;e)<br />
<img id="Codehighlighter1_494_516_Open_Image" onclick="this.style.display='none'; Codehighlighter1_494_516_Open_Text.style.display='none'; Codehighlighter1_494_516_Closed_Image.style.display='inline'; Codehighlighter1_494_516_Closed_Text.style.display='inline';" alt="" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_494_516_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_494_516_Closed_Text.style.display='none'; Codehighlighter1_494_516_Open_Image.style.display='inline'; Codehighlighter1_494_516_Open_Text.style.display='inline';" alt="" src="http://www.blogjava.net/Images/OutliningIndicators/ContractedSubBlock.gif" align="top" />　　</span><span id="Codehighlighter1_494_516_Open_Text"><span style="color: #000000">{<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align="top" />　　e.getMessage();<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />　　}</span></span><span style="color: #000000"><br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align="top" />　　System.out.println(Thread.currentThread().getName()</span><span style="color: #000000">+</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">"</span><span style="color: #000000">this&nbsp;is&nbsp;</span><span style="color: #000000">"</span><span style="color: #000000">+</span><span style="color: #000000">&nbsp;num</span><span style="color: #000000">--</span><span style="color: #000000">);<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />　　}</span></span><span style="color: #000000"><br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />　　}</span></span><span style="color: #000000"><br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />　　}</span></span><span style="color: #000000"><br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />　　}</span></span><span style="color: #000000"><br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />　　}</span></span><span style="color: #000000"><br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" /></span></div>
<br />
上面的例子中为了制造一个时间差,也就是出错的机会,使用了Thread.sleep(10)<br />
　　Java对多线程的支持与同步机制深受大家的喜爱，似乎看起来使用了synchronized关键字就可以轻松地解决多线程共享数据同步问题。到底如何？――还得对synchronized关键字的作用进行深入了解才可定论。<br />
　　总的说来，<span style="color: red">synchronized关键字可以作为函数的修饰符，也可作为函数内的语句，也就是平时说的同步方法和同步语句块。如果再细的分类，synchronized可作用于instance变量、object reference（对象引用）、static函数和class literals(类名称字面常量)身上。</span><br />
　　<strong>在进一步阐述之前，我们需要明确几点：<br />
</strong>　　A．无论synchronized关键字加在方法上还是对象上，它取得的锁都是对象，而不是把一段代码或函数当作锁――而且同步方法很可能还会被其他线程的对象访问。<br />
　　B．每个对象只有一个锁（lock）与之相关联。<br />
　　C．实现同步是要很大的系统开销作为代价的，甚至可能造成死锁，所以尽量避免无谓的同步控制。<br />
　　接着来讨论synchronized用到不同地方对代码产生的影响：<br />
　　假设P1、P2是同一个类的不同对象，这个类中定义了以下几种情况的同步块或同步方法，P1、P2就都可以调用它们。<br />
　　<strong>1． 把synchronized当作函数修饰符时，示例代码如下：</strong><br />
　　Public synchronized void methodAAA()<br />
　　{<br />
　　//&#8230;.<br />
　　}<br />
　　这也就是同步方法，那这时synchronized锁定的是哪个对象呢？它锁定的是调用这个同步方法对象。也就是说，当一个对象P1在不同的线程中执行这个同步方法时，它们之间会形成互斥，达到同步的效果。但是这个对象所属的Class所产生的另一对象P2却可以任意调用这个被加了synchronized关键字的方法。<br />
　　上边的示例代码等同于如下代码：<br />
　　public void methodAAA()<br />
　　{<br />
　　synchronized (this) // (1)<br />
　　{<br />
　　//&#8230;..<br />
　　}<br />
　　}<br />
　　(1)处的this指的是什么呢？它指的就是调用这个方法的对象，如P1。可见同步方法实质是将synchronized作用于object reference。――那个拿到了P1对象锁的线程，才可以调用P1的同步方法，而对P2而言，P1这个锁与它毫不相干，程序也可能在这种情形下摆脱同步机制的控制，造成数据混乱．<br />
<br />
<strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2．同步块，示例代码如下：<br />
</strong>　　public void method3(SomeObject so)<br />
　　{<br />
　　synchronized(so)<br />
　　{<br />
　　//&#8230;..<br />
　　}<br />
　　}<br />
　　这时，锁就是so这个对象，谁拿到这个锁谁就可以运行它所控制的那段代码。当有一个明确的对象作为锁时，就可以这样写程序，但当没有明确的对象作为锁，只是想让一段代码同步时，可以创建一个特殊的instance变量（它得是一个对象）来充当锁：<br />
　　class Foo implements Runnable<br />
　　{<br />
　　private byte[] lock = new byte[0]; // 特殊的instance变量<br />
　　Public void methodA()<br />
　　{<br />
　　synchronized(lock) { //&#8230; }<br />
　　}<br />
　　//&#8230;..<br />
　　}<br />
　　注：零长度的byte数组对象创建起来将比任何对象都经济――查看编译后的字节码：生成零长度的byte[]对象只需3条操作码，而Object lock = new Object()则需要7行操作码。<br />
　　<strong>3．将synchronized作用于static 函数，示例代码如下：<br />
</strong>　　Class Foo<br />
　　{<br />
　　public synchronized static void methodAAA() // 同步的static 函数<br />
　　{<br />
　　//&#8230;.<br />
　　}<br />
　　public void methodBBB()<br />
　　{<br />
　　synchronized(Foo.class) // class literal(类名称字面常量)<br />
　　}<br />
　　}<br />
　　代码中的methodBBB()方法是把class literal作为锁的情况，它和同步的static函数产生的效果是一样的，取得的锁很特别，是当前调用这个方法的对象所属的类（Class，而不再是由这个Class产生的某个具体对象了）。<br />
　　记得在《Effective Java》一书中看到过将 Foo.class和 P1.getClass()用于作同步锁还不一样，不能用P1.getClass()来达到锁这个Class的目的。P1指的是由Foo类产生的对象。<br />
　　可以推断：如果一个类中定义了一个synchronized的static函数A，也定义了一个synchronized 的instance函数B，那么这个类的同一对象Obj在多线程中分别访问A和B两个方法时，不会构成同步，因为它们的锁都不一样。A方法的锁是Obj这个对象，而B的锁是Obj所属的那个Class。<br />
　　<strong>小结如下：<br />
</strong>　　搞清楚synchronized锁定的是哪个对象，就能帮助我们设计更安全的多线程程序。<br />
　　<strong>还有一些技巧可以让我们对共享资源的同步访问更加安全：<br />
</strong>　　1． 定义private 的instance变量+它的 get方法，而不要定义public/protected的instance变量。如果将变量定义为public，对象在外界可以绕过同步方法的控制而直接取得它，并改动它。这也是JavaBean的标准实现方式之一。<br />
　　2． 如果instance变量是一个对象，如数组或ArrayList什么的，那上述方法仍然不安全，因为当外界对象通过get方法拿到这个instance对象的引用后，又将其指向另一个对象，那么这个private变量也就变了，岂不是很危险。这个时候就需要将get方法也加上synchronized同步，并且，只返回这个private对象的clone()――这样，调用端得到的就是对象副本的引用了。
<img src ="http://www.blogjava.net/gm_jing/aggbug/249697.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/gm_jing/" target="_blank">黎夕</a> 2009-01-04 10:23 <a href="http://www.blogjava.net/gm_jing/articles/249697.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java中Class.forName的含义</title><link>http://www.blogjava.net/gm_jing/articles/240429.html</link><dc:creator>黎夕</dc:creator><author>黎夕</author><pubDate>Thu, 13 Nov 2008 16:30:00 GMT</pubDate><guid>http://www.blogjava.net/gm_jing/articles/240429.html</guid><wfw:comment>http://www.blogjava.net/gm_jing/comments/240429.html</wfw:comment><comments>http://www.blogjava.net/gm_jing/articles/240429.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/gm_jing/comments/commentRss/240429.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/gm_jing/services/trackbacks/240429.html</trackback:ping><description><![CDATA[<div class="post">
<div class="postcontent">
<div class="con_sample">
<p>Class.forName(xxx.xx.xx) 返回的是一个类, .newInstance() 后才创建一个对象 Class.forName(xxx.xx.xx);的作用是要求JVM查找并加载指定的类，也就是说JVM会执行该类的静态代码段</p>
</div>
<div class="con_all">
<p>
<p>Class aClass = Class.forName(xxx.xx.xx);<br />
Object anInstance = aClass.newInstance();<br />
<br />
<br />
Class.forName("").newInstance()返回的是object<br />
but there is some limit for this method to create instance<br />
that is your class constructor should no contain parameters, and you should cast the instance manually.<br />
<br />
Class Driver{<br />
protected static Driver current;<br />
public static Driver getDriver(){<br />
return current;<br />
}<br />
}<br />
<br />
Class MyDriver extends Driver{<br />
static{<br />
Driver.current=new MyDriver();<br />
}<br />
MyDriver(){}<br />
}<br />
<br />
用时:<br />
Class.forName("MyDriver");<br />
Driver d=Driver.getDriver();<br />
<br />
有的jdbc连接数据库的写法里是Class.forName(xxx.xx.xx);而有一些：Class.forName(xxx.xx.xx).newInstance()，为什么会有这两种写法呢？<br />
<br />
Class.forName(xxx.xx.xx) 返回的是一个类,<br />
.newInstance() 后才创建一个对象<br />
<br />
Class.forName(xxx.xx.xx);的作用是要求JVM查找并加载指定的类，也就是说JVM会执行该类的静态代码段<br />
<br />
在JDBC规范中明确要求这个Driver类必须向DriverManager注册自己，即任何一个JDBC Driver的Driver类的代码都必须类似如下：<br />
public class MyJDBCDriver implements Driver {<br />
static {<br />
DriverManager.registerDriver(new MyJDBCDriver());<br />
}<br />
}<br />
<br />
所以我们在使用JDBC时只需要Class.forName(XXX.XXX);就可以了<br />
</p>
</div>
<br />
下面给一个例子：Class的最大作用就是实现了动态加载类，为多态提供了很好的帮助。<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 alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" /><span style="color: #0000ff">class</span><span style="color: #000000">&nbsp;A<br />
<img id="Codehighlighter1_8_64_Open_Image" onclick="this.style.display='none'; Codehighlighter1_8_64_Open_Text.style.display='none'; Codehighlighter1_8_64_Closed_Image.style.display='inline'; Codehighlighter1_8_64_Closed_Text.style.display='inline';" alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_8_64_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_8_64_Closed_Text.style.display='none'; Codehighlighter1_8_64_Open_Image.style.display='inline'; Codehighlighter1_8_64_Open_Text.style.display='inline';" alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif" align="top" /></span><span id="Codehighlighter1_8_64_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 alt="" src="http://www.cnblogs.com/Images/dot.gif" /></span><span id="Codehighlighter1_8_64_Open_Text"><span style="color: #000000">{<br />
<img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;aa()<br />
<img id="Codehighlighter1_22_59_Open_Image" onclick="this.style.display='none'; Codehighlighter1_22_59_Open_Text.style.display='none'; Codehighlighter1_22_59_Closed_Image.style.display='inline'; Codehighlighter1_22_59_Closed_Text.style.display='inline';" alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_22_59_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_22_59_Closed_Text.style.display='none'; Codehighlighter1_22_59_Open_Image.style.display='inline'; Codehighlighter1_22_59_Open_Text.style.display='inline';" alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span id="Codehighlighter1_22_59_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 alt="" src="http://www.cnblogs.com/Images/dot.gif" /></span><span id="Codehighlighter1_22_59_Open_Text"><span style="color: #000000">{<br />
<img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println&nbsp;(</span><span style="color: #000000">"</span><span style="color: #000000">A里的</span><span style="color: #000000">"</span><span style="color: #000000">);&nbsp;&nbsp;&nbsp;&nbsp;<br />
<img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;<br />
<img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;<br />
<img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span></span><span style="color: #000000"><br />
<img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" /></span><span style="color: #0000ff">class</span><span style="color: #000000">&nbsp;B&nbsp;</span><span style="color: #0000ff">extends</span><span style="color: #000000">&nbsp;A<br />
<img id="Codehighlighter1_84_140_Open_Image" onclick="this.style.display='none'; Codehighlighter1_84_140_Open_Text.style.display='none'; Codehighlighter1_84_140_Closed_Image.style.display='inline'; Codehighlighter1_84_140_Closed_Text.style.display='inline';" alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_84_140_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_84_140_Closed_Text.style.display='none'; Codehighlighter1_84_140_Open_Image.style.display='inline'; Codehighlighter1_84_140_Open_Text.style.display='inline';" alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif" align="top" /></span><span id="Codehighlighter1_84_140_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff"><img alt="" src="http://www.cnblogs.com/Images/dot.gif" /></span><span id="Codehighlighter1_84_140_Open_Text"><span style="color: #000000">{<br />
<img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;aa()<br />
<img id="Codehighlighter1_98_135_Open_Image" onclick="this.style.display='none'; Codehighlighter1_98_135_Open_Text.style.display='none'; Codehighlighter1_98_135_Closed_Image.style.display='inline'; Codehighlighter1_98_135_Closed_Text.style.display='inline';" alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_98_135_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_98_135_Closed_Text.style.display='none'; Codehighlighter1_98_135_Open_Image.style.display='inline'; Codehighlighter1_98_135_Open_Text.style.display='inline';" alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span id="Codehighlighter1_98_135_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 alt="" src="http://www.cnblogs.com/Images/dot.gif" /></span><span id="Codehighlighter1_98_135_Open_Text"><span style="color: #000000">{<br />
<img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println&nbsp;(</span><span style="color: #000000">"</span><span style="color: #000000">B里的</span><span style="color: #000000">"</span><span style="color: #000000">);&nbsp;&nbsp;&nbsp;&nbsp;<br />
<img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;<br />
<img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;<br />
<img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span></span><span style="color: #000000"><br />
<img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" /></span><span style="color: #0000ff">class</span><span style="color: #000000">&nbsp;C&nbsp;</span><span style="color: #0000ff">extends</span><span style="color: #000000">&nbsp;A<br />
<img id="Codehighlighter1_160_216_Open_Image" onclick="this.style.display='none'; Codehighlighter1_160_216_Open_Text.style.display='none'; Codehighlighter1_160_216_Closed_Image.style.display='inline'; Codehighlighter1_160_216_Closed_Text.style.display='inline';" alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_160_216_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_160_216_Closed_Text.style.display='none'; Codehighlighter1_160_216_Open_Image.style.display='inline'; Codehighlighter1_160_216_Open_Text.style.display='inline';" alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif" align="top" /></span><span id="Codehighlighter1_160_216_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 alt="" src="http://www.cnblogs.com/Images/dot.gif" /></span><span id="Codehighlighter1_160_216_Open_Text"><span style="color: #000000">{<br />
<img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;aa()<br />
<img id="Codehighlighter1_174_211_Open_Image" onclick="this.style.display='none'; Codehighlighter1_174_211_Open_Text.style.display='none'; Codehighlighter1_174_211_Closed_Image.style.display='inline'; Codehighlighter1_174_211_Closed_Text.style.display='inline';" alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_174_211_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_174_211_Closed_Text.style.display='none'; Codehighlighter1_174_211_Open_Image.style.display='inline'; Codehighlighter1_174_211_Open_Text.style.display='inline';" alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span id="Codehighlighter1_174_211_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 alt="" src="http://www.cnblogs.com/Images/dot.gif" /></span><span id="Codehighlighter1_174_211_Open_Text"><span style="color: #000000">{<br />
<img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println&nbsp;(</span><span style="color: #000000">"</span><span style="color: #000000">C里的</span><span style="color: #000000">"</span><span style="color: #000000">);&nbsp;&nbsp;&nbsp;&nbsp;<br />
<img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;<br />
<img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;<br />
<img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span></span><span style="color: #000000"><br />
<img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" /><br />
<img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" /><br />
<img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" /></span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">class</span><span style="color: #000000">&nbsp;ClassDemo<br />
<img id="Codehighlighter1_243_511_Open_Image" onclick="this.style.display='none'; Codehighlighter1_243_511_Open_Text.style.display='none'; Codehighlighter1_243_511_Closed_Image.style.display='inline'; Codehighlighter1_243_511_Closed_Text.style.display='inline';" alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_243_511_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_243_511_Closed_Text.style.display='none'; Codehighlighter1_243_511_Open_Image.style.display='inline'; Codehighlighter1_243_511_Open_Text.style.display='inline';" alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif" align="top" /></span><span id="Codehighlighter1_243_511_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 alt="" src="http://www.cnblogs.com/Images/dot.gif" /></span><span id="Codehighlighter1_243_511_Open_Text"><span style="color: #000000">{<br />
<img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;<br />
<img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">static</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;main(String[]&nbsp;args)<br />
<img id="Codehighlighter1_288_337_Open_Image" onclick="this.style.display='none'; Codehighlighter1_288_337_Open_Text.style.display='none'; Codehighlighter1_288_337_Closed_Image.style.display='inline'; Codehighlighter1_288_337_Closed_Text.style.display='inline';" alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_288_337_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_288_337_Closed_Text.style.display='none'; Codehighlighter1_288_337_Open_Image.style.display='inline'; Codehighlighter1_288_337_Open_Text.style.display='inline';" alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span id="Codehighlighter1_288_337_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 alt="" src="http://www.cnblogs.com/Images/dot.gif" /></span><span id="Codehighlighter1_288_337_Open_Text"><span style="color: #000000">{<br />
<img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ClassDemo&nbsp;t</span><span style="color: #000000">=</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;ClassDemo();<br />
<img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;t.show(</span><span style="color: #000000">"</span><span style="color: #000000">C</span><span style="color: #000000">"</span><span style="color: #000000">);<br />
<img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000"><br />
<img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;show(String&nbsp;name)<br />
<img id="Codehighlighter1_364_505_Open_Image" onclick="this.style.display='none'; Codehighlighter1_364_505_Open_Text.style.display='none'; Codehighlighter1_364_505_Closed_Image.style.display='inline'; Codehighlighter1_364_505_Closed_Text.style.display='inline';" alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_364_505_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_364_505_Closed_Text.style.display='none'; Codehighlighter1_364_505_Open_Image.style.display='inline'; Codehighlighter1_364_505_Open_Text.style.display='inline';" alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span id="Codehighlighter1_364_505_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 alt="" src="http://www.cnblogs.com/Images/dot.gif" /></span><span id="Codehighlighter1_364_505_Open_Text"><span style="color: #000000">{<br />
<img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">try</span><span style="color: #000000"><br />
<img id="Codehighlighter1_374_442_Open_Image" onclick="this.style.display='none'; Codehighlighter1_374_442_Open_Text.style.display='none'; Codehighlighter1_374_442_Closed_Image.style.display='inline'; Codehighlighter1_374_442_Closed_Text.style.display='inline';" alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_374_442_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_374_442_Closed_Text.style.display='none'; Codehighlighter1_374_442_Open_Image.style.display='inline'; Codehighlighter1_374_442_Open_Text.style.display='inline';" alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span id="Codehighlighter1_374_442_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 alt="" src="http://www.cnblogs.com/Images/dot.gif" /></span><span id="Codehighlighter1_374_442_Open_Text"><span style="color: #000000">{<br />
<img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;A&nbsp;show</span><span style="color: #000000">=</span><span style="color: #000000">(A)Class.forName(name).newInstance();<br />
<img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;show.aa();<br />
<img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000"><br />
<img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">catch</span><span style="color: #000000">(Exception&nbsp;e)<br />
<img id="Codehighlighter1_465_495_Open_Image" onclick="this.style.display='none'; Codehighlighter1_465_495_Open_Text.style.display='none'; Codehighlighter1_465_495_Closed_Image.style.display='inline'; Codehighlighter1_465_495_Closed_Text.style.display='inline';" alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_465_495_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_465_495_Closed_Text.style.display='none'; Codehighlighter1_465_495_Open_Image.style.display='inline'; Codehighlighter1_465_495_Open_Text.style.display='inline';" alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span id="Codehighlighter1_465_495_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 alt="" src="http://www.cnblogs.com/Images/dot.gif" /></span><span id="Codehighlighter1_465_495_Open_Text"><span style="color: #000000">{<br />
<img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println&nbsp;(e);<br />
<img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000"><br />
<img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000"><br />
<img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;<br />
<img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;<br />
<img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span></span></div>
</div>
</div>
<img src ="http://www.blogjava.net/gm_jing/aggbug/240429.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/gm_jing/" target="_blank">黎夕</a> 2008-11-14 00:30 <a href="http://www.blogjava.net/gm_jing/articles/240429.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> java中的native</title><link>http://www.blogjava.net/gm_jing/articles/126100.html</link><dc:creator>黎夕</dc:creator><author>黎夕</author><pubDate>Mon, 25 Jun 2007 06:29:00 GMT</pubDate><guid>http://www.blogjava.net/gm_jing/articles/126100.html</guid><wfw:comment>http://www.blogjava.net/gm_jing/comments/126100.html</wfw:comment><comments>http://www.blogjava.net/gm_jing/articles/126100.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/gm_jing/comments/commentRss/126100.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/gm_jing/services/trackbacks/126100.html</trackback:ping><description><![CDATA[<h3 align=center><font color=#000000><font size=+2>CONTENTS<a name=CONTENTS></a> </font></font></h3>
<ul>
    <li><a href="http://www.80x86.cn/article.asp?id=1448#WhatIsaNativeMethod"><u><font color=#0000ff>What Is a Native Method?</font></u></a>
    <li><a href="http://www.80x86.cn/article.asp?id=1448#UsesforNativeMethods"><u><font color=#0000ff>Uses for Native Methods</font></u></a>
    <li><a href="http://www.80x86.cn/article.asp?id=1448#BenefitsandTradeOffs"><u><font color=#0000ff>Benefits and Trade-Offs</font></u></a>
    <li><a href="http://www.80x86.cn/article.asp?id=1448#HowDoesThisMagicWork"><u><font color=#0000ff>How Does This Magic Work?</font></u></a>
    <li><a href="http://www.80x86.cn/article.asp?id=1448#Summary"><u><font color=#0000ff>Summary</font></u></a> </li>
</ul>
<hr>
<p>The goal for this chapter is to introduce you to Java's native methods. If you are new to Java, you may not know what native methods are, and even if you are an experienced Java developer, you may not have had a reason to learn more about native methods. At the conclusion of this chapter you should have a better understanding of what native methods are, when and why you may want to use them, and the consequences of using them. You should also have a basic understanding of how native methods work. You will then be more than ready to tackle the next three chapters, which dive into the nitty-gritty details of Java's Native Methods. </p>
<h2><a name=WhatIsaNativeMethod><strong><font color=#ff0000 size=5>What Is a Native Method?</font></strong></a></h2>
<p>Simply put, a native method is the Java interface to non-Java code. It is Java's link to the "outside world." More specifically, a native method is a Java method whose implementation is provided by non-Java code, most likely C (see Figure 30.1). This feature is not special to Java. Most languages provide some mechanism to call routines written in another language. In C++, you must use the <tt>extern "C" </tt><font face=MCPdigital-I size=1>stmt</font> to signal that the C++ compiler is making a call to C functions. It is common to see the qualifier <tt>pascal</tt> in many C compilers to signal that the calling convention should be done in a Pascal convention, rather than a C convention. FORTRAN and Pascal have similar facilities, as do most other languages. </p>
<p><a href="http://www.80x86.cn/f30-1.gif"><u><font color=#0000ff><strong>Figure 30.1 : </strong><em>A native method is a Java method whose implementation is provided by non-java code.</em></font></u></a> </p>
<p>In Java, this is done via native methods. In your Java class, you mark the methods you wish to implement outside of Java with the <tt>native</tt> method modifier-much like you would use the<tt> public</tt> or <tt>static</tt> modifiers. Then, rather than supplying the method's body, you simply place a semicolon in its place. As an example, the following class defines a variety of native methods: </p>
<blockquote><tt>public class IHaveNatives<br>{<br></tt>&nbsp;<tt>&nbsp;native public void Native1( int x ) ;<br>&nbsp;&nbsp;native static public long Native2() ;<br></tt>&nbsp;<tt>&nbsp;native synchronized private float Native3( Object o ) ;<br>&nbsp;&nbsp;native void Native4( int[] ary ) throws Exception ;<br>}</tt> </blockquote>
<p>This sample class shows a number of possible native methods. As you may have noticed, native methods look much like any other Java method, except a single semicolon is in the place of the method body. Naturally, the body of the method is implemented outside of Java. What you basically define is the interface into this <em>external</em> method. This method declaration describes the Java view of some foreign code. </p>
<p>The only thing special about this declaration is that the keyword <tt>native</tt> is used as a modifier. Every other Java method modifier can be used along with <tt>native</tt>, except <tt>abstract</tt>. This is logical, because the <tt>native</tt> modifier implies that an implementation exists, and the <tt>abstract</tt> modifier insists that there is no implementation. Your native methods can be static methods, thus not requiring the creation of an object (or instance of a class). This is often convenient when using native methods to access an existing C-based library. Naturally, native methods can limit their visibility with the <tt>public</tt>, <tt>private</tt>, <tt>private protected</tt>, <tt>protected</tt>, or unspecified <em>default </em>access. Native methods can also be <tt>synchronized</tt> (<a href="http://www.80x86.cn/ch7.htm"><u><font color=#0000ff>see Chapter 7</font></u></a>, "Concurrency and Synchronization"). In the case of a <tt>synchronized</tt> native method, the Java VM will perform the monitor locking prior to entering the native method implementation code. So, as in Java, the developer is not burdened with doing the actual monitor locking and unlocking. </p>
<p>The example uses a variety (although not all) of types. This is because a native method can be passed any Java type. There is no special procedure within the Java code to pass data to the native method. However, the developer of native methods must be careful that his native methods behave properly when manipulating Java datatypes. Native methods do not undergo the same kinds of checking as a Java method, and they can easily corrupt a Java datatype if care is not taken (<a href="http://www.80x86.cn/ch31.htm"><u><font color=#0000ff>see Chapter 31</font></u></a>, "The Native Method Interface"). </p>
<p>A native method can accept and return any of the Java types-including class types. Of course, the power of exception handling is also available to native methods. The implementation of the native method can create and throw exceptions similar to a Java method. When a native method receives complex types, such as class types (such as <tt>Object</tt> in the example) or array types (such as the <tt>int[]</tt> in the example), it has access to the contents of those types. However, the method used to access the contents may vary depending on the Java implementation being used. The major point to remember is that you can access all the Java features from your native implementation code, but it may be implementation-dependent and will surely not be as convenient or easy as it can be done from Java. </p>
<p>The presence of native methods does not affect how other classes call those methods. The caller does not even realize it is calling a native method, so no special code is generated, and the calling convention is the same as for any other method-the calling depends on the method being virtual or static. The Java virtual machine will handle all the details to make the call in the native method implementation. One minor exception may be with the methods marked with the <tt>final</tt> modifier. The Java implementation may take advantage of a <tt>final</tt> method and choose to inline its code. It would be doubtful that this could be achieved with a native <tt>final</tt> method, but this is an optimization issue, not one of functionality. When a class containing native methods is subclassed, the subclass will inherit the native method and also will have the capability of overriding the native method-even with a Java method (that is, the overridden method can be implemented in Java). If a native method is also marked with the <tt>final</tt> modifier, a subclass is still prevented from overriding it. </p>
<p>Native methods are very powerful, because they effectively extend the Java virtual machine. In fact, your Java code already uses native methods. In the current implementation from Sun, native methods are used in many places to interface to the underlying operating system. This enables a Java program to go beyond the confines of the Java Runtime. With native methods, a Java program can virtually do any application level task. </p>
<h2><a name=UsesforNativeMethods><strong><font color=#ff0000 size=5>Uses for Native Methods</font></strong></a></h2>
<p>Java is a wonderful language to use. However, there are times when you either must interface with existing code, can't express the task in Java, or need the absolute best performance. </p>
<h3><strong>Accessing Outside the Java Environment</strong></h3>
<p>There are times where a Java application (or applet) <em>must</em> communicate with the environment outside of Java. This is, perhaps, the main reason for the existence of native methods. For starters, the Java implementation will need to communicate with the underlying system. That underlying system may be an operating system such as Solaris or Win32, or it may be a Web browser, or it may be custom hardware, such as a PDA, Set-top-device, and so forth. Regardless of what is under Java, there must be a mechanism to communicate with that system. At some point in a Java program, there will be that point where Java meets the outside world, an interface between Java and non-Java worlds. Native methods provide a simple clean approach to providing this interface without burdening the rest of the Java application with special knowledge. </p>
<h4><strong>Accessing the Operating System</strong></h4>
<p>The Java virtual machine describes a system that the Java program can rely on to be there. This virtual machine supports the Java Language and its runtime library. It may be composed of an interpreter or can be libraries linked to native code. Regardless of its form, it is not a complete system and often relies on an existing system underneath to provide a lot of support. More than likely, a full-fledged operating system, such as Solaris or Win32, resides beneath it. The use of native methods enables the Java Runtime to be written in Java yet have access to the underlying operating system, or even the parts of the Java virtual machine that may be written in a language such as C. Further, if a Java feature does not encapsulate an operating system feature needed by an application, native methods can be used to access this feature. </p>
<h4><strong>Embedded Java</strong></h4>
<p>It is conceivable to see a Java virtual machine embedded inside another program. Several WWW browsers come to mind. Perhaps this enclosing program is not implemented in Java. The Java Runtime may need to access the enclosing program for services to support the Java environment. Once again, native methods provide a clean interface for this access to the surrounding program. Furthermore, the vendor of the program may wish to expose some features of the program to a Java applet. The vendor would simply need to create a set of Java classes containing native methods, which provide the interface for the Java application into the program. The native method implementation would then be the "glue" between the Java applet and the internals of the enclosing program. </p>
<h4><strong>Custom Hardware</strong></h4>
<p>Another important possible application of native methods being used to access a non-Java world is providing Java programs access to custom hardware. Perhaps a Java virtual machine is running within a PDA or Set-Top-Device. A lot of what would normally be in an operating system may exist in hardware or software embedded in ROM, or other custom chip sets. Another possibility is that a computer may be equipped with a dedicated graphics card. It would be ideal to have Java make use of the graphics hardware. A set of Java classes with native methods defined would provide the Java program access to these features. </p>
<h4><strong>Sun's Java</strong></h4>
<p>In the current implementation from Sun, the Java interpreter is written in C and can thus talk to the outside environment as any normal C program can. A majority of the Java Runtime is written in Java and may make calls into the interpreter or directly to the outside environment, all via native methods. The application deals mostly with the Java Runtime, but it may also talk to the outside environment via native methods. For example in the class <tt>java.lang.Thread</tt> the <tt>setPriority()</tt> method is implemented in Java but calls the method <tt>setPriority0()</tt>, which is a native method in the <tt>Thread</tt> class. This native method is implemented in C and resides within the Java virtual machine itself. On the Windows 95 platform this native method will then call (eventually) the Win32 <tt>SetPriority()</tt> API. This is an example where the native method implementation was provided by the Java virtual machine directly. In most cases the native method implementation resides in an external dynamic link library (discussed in a following section), but the call still goes through the Java virtual machine. </p>
<h3><strong>Performance</strong></h3>
<p>Another major reason for native methods is performance. The Java language trades some performance for features like its dynamic nature, garbage collecting, and safety. Some Java implementations, like the current crop, may be interpreters, which also add extra overhead. The lost performance can be small as the implementation technology for Java systems improve, but until then and even after there may always be a small performance overhead for certain functionality a Java program may need. This functionality can be pushed down into a native method. That native method can then be implemented efficiently at the native lower level of the system on which the Java virtual machine is running. Once at the native implementation level, the developer can use the best-suited language, such as C or even assembler. In this way, maximum performance can be achieved in those specific areas while the bulk of the application is done within the safe and robust Java virtual machine. One area where you may choose to implement some parts of an application in native methods is time-intensive computations, such as graphics rendering, simulation models, and so forth. </p>
<h3><strong>Accessing Existing Libraries</strong></h3>
<p>The fact that Java is targeted at the production of platform-neutral code means that the current implementations may not access system features that you may need. An example is a database engine. If you need to, you can use the native method facility to provide your own interface to such libraries. Further, you may want to use Java to write applications that use existing in-house libraries. Again, the use of native methods enables you to make such an interface. This enables you to leverage off your existing code base as well as gradually introduce Java-based applications among your other applications coded in an older language. </p>
<h2><a name=BenefitsandTradeOffs><strong><font color=#ff0000 size=5>Benefits and Trade-Offs</font></strong></a></h2>
<p>The presense of native methods offers many benefits, the biggest being the extension of Java power. However, there is always a downside to all good things, and native methods definitely have their downsides. Depending on what the goals of your application are, the downsides may not be that terrible. Foremost is the fact that, by definition, the use of native methods defeats several of Java's main goals: platform neutrality, system safety, and security. </p>
<p>Some of Java's attractive features help minimize the downsides, however. The best feature of all is that Java is such a nice language to develop in you won't want to use native methods unless you have to. </p>
<h3><strong>Platform Neutrality</strong></h3>
<p>Because a native method is implemented in a foreign language, the platform neutrality is limited to the language being used. Most likely, native methods are implemented in C or C++. Although those languages have standards, these standards leave a lot of room for implementation-defined attributes (even compilers on the same system may differ), so your mileage may vary. If the native method accesses the underlying system, you are tying your implementation to that system. For example, the file systems of UNIX and Win32 have some differences. There may even be differences between flavors of UNIX and Win32 (Win95 and WinNT are not identical). Once again, you may sacrifice your platform neutrality with your native method. This may cause you to have to support a limited number of platforms (rather than <em>all</em> Java platforms). Further, for each platform you choose to support, you may (probably will) have to implement several flavors of the native method. </p>
<p>The Java language and runtime provide a number of features that make applications more robust and safe. Java's memory management, synchronization features, and lack of address manipulation help prevent common programming mistakes from slipping through the development and testing phases of your product. However, once you drop out of Java into a native method, you are, once again, at the mercy of the language and system in which you are implementing the native method. If your native method implemented in C chooses to manipulate an address directly, you risk corrupting some part of memory, perhaps even the Java virtual machine itself. </p>
<h3><strong>Security Concerns</strong></h3>
<p>Additionally, the Java Language provides features to aid in the writing of secure applications. A Java virtual machine is much more capable of detecting an "evil" Java program than an application in other languages. Once you drop into a native method, the Java virtual machine can no longer verify, catch, or prevent the program from violating the security of the environment in which the Java virtual machine is running. This is the reason a Java-enabled Web browser typically does not allow a nontrusted native method to be called. In today's browsers, a trusted native method must be present on the local system in a certain location to be executed from an <em>arriving</em> applet (in other words, one loaded from a remote site). For more information on security, in general, see Part 6, "Security." For more information on how security applies to native methods, see <a href="http://www.80x86.cn/ch33.htm"><u><font color=#0000ff>Chapter 33</font></u></a>, "Securing Your Native Method Libraries." </p>
<h3><strong>System Safety</strong></h3>
<p>Another potential hazard is the fact that a native method is not isolated. When a native method is entered, it not only accesses the environment outside the Java virtual machine, it also freely accesses the Java virtual machine directly. This is a necessary evil. It gives the native method quite a bit of power and flexibility, because it may need access to information kept within the virtual machine to do its job. This flexibility, however, exposes the internals of the Java virtual machine to the native method. </p>
<h3><strong>Dependence on the Java Implementation</strong></h3>
<p>It should be obvious that the implementation of native methods is also dependent on the Java implementation itself. This means that the native methods you write today for use with the Sun implementation of Java may not work with a Java implementation from another vendor. </p>
<p>The interface used for the Java virtual machine to call out to native methods and the interface that native methods use to access the internal functions and data structures of the Java virtual machine are not, currently, defined by either the Java Language Specification or the Java Virtual Machine Specification. A lot of native methods call back into the Java virtual machine for instantiating new objects, calling Java methods, throwing Java Exceptions, and so forth. Further, the method used to lay out Java types is also not defined. So, although your native method of today knows how to access the fields of an object, this could be different on the Java virtual machine of tomorrow. This oversight can be greatly helped if a standard API is defined for both how a Java program interacts with a native method and how a native method accesses data within the Java virtual machine. Even after such an API, implementation-defined behavior will likely still be present. </p>
<h3><strong>Java to the Rescue!</strong></h3>
<p>Recall that Java helps to minimize the damage of native methods. When you find yourself in the position that you must use native methods, you can take advantage of Java's features to help isolate the usage and perhaps maintain a fair amount of Java's advantages. </p>
<h4><strong>The Java Class System</strong></h4>
<p>Because Java narrows the use of native facilities to within the confines of a method, it does not affect the design of the program. A program is still a collection of classes and all classes still communicate with each other via their defined interface-that is, the classes' methods. Thus the callers of native methods do not know they are calling native methods. Because methods are discrete operations on the data of a specific object, they tend to be small chunks of code. This implies that native methods tend to be conceptually small, easily managed, pieces of code. </p>
<h4><strong>Java Still Works for You</strong></h4>
<p>Java will still perform a variety of duties-such as parameter checking, stack checking, synchronization, and so forth-before entering the actual native code. It greatly aids the developer in writing correct native methods. A native method is capable of creating new objects and calling Java methods, and it can even cause exceptions to be thrown. In the current implementation from Sun, an exception can be created by a native method and registered for throwing. When Java virtual machine gains control back from the native method, usually because of that method returning, the exception will then be thrown. </p>
<p>It's a good idea to make your native methods as small as possible and have them do a specific task. Do the work that needs to be done and pass the information back into the Java method. It's also wise to have your Java classes make the native methods private, then provide a public Java method that will call the private native method. This enables the Java method to perform error checks and other data manipulations, freeing your actual native method implementation to focus on its simple task. </p>
<h2><a name=HowDoesThisMagicWork><strong><font color=#ff0000 size=5>How Does This Magic Work?</font></strong></a></h2>
<p>Much of the magic of making native methods work is provided in the next three chapters. This section provides an introduction, which neglects many of the details but should give you a good frame of reference for understanding the following chapters. If you don't really want to use native methods, but just want a basic understanding this discussion should satisfy your needs. </p>
<h3><strong>Sun's Implementation</strong></h3>
<p>Due to the lack of a well-defined interface between a Java implementation and its surrounding environment, the details of writing native methods will most likely be specific to the implementation of the Java system you are using. The next sections are based on the implementation provided by Sun on the Solaris-Sparc and Win32-Intel platforms. </p>
<h4><strong>Using Dynamic Linking</strong></h4>
<p>Sun's Java implementation interfaces to native methods by using the dynamic linking capabilities of the underlying operation system. The Java virtual machine is a complete program, which is already compiled for its respective platform. The nature of Java enables it easily to absorb a Java class and execute its behavior. However, for a compiled native method, things are not so simple. Somehow, the Java virtual machine must be taught how to call this native method. This is done by relying on the implementation of native methods to reside in a dynamic link library, which the operating system magically loads and links into the process that is running the Java virtual machine. On the Solaris platform, such a library is often called <em>shared objects</em>, or <em>shared libraries</em>, or simply <em>dot-so's (.so's)</em>. On Win32 platforms, they are called <em>dynamic link libraries</em> <em>(DLLs)</em>. This chapter uses DLL to refer to both. </p>
<p>Both Solaris and Win32 provide the necessary capabilities to achieve this dynamic linking. The dynamic linking facilities of both Solaris and Win32 are similar in concept, but differ in their details. This chapter does not attempt to describe the two in detail; however, if you wish to do native method programming, you should understand the mechanism used by your platform. On Solaris, you can begin by viewing the manual page on the <tt>dlopen()</tt> system call, and its relatives. On Win32, start with the help file on <tt>LoadLibrary()</tt> and its relatives. Further, you should understand the calling conventions and linking convention used by your compiler. </p>
<p>Sometime before a native method is invoked, the Java virtual machine must be told to find, load, and link the necessary DLLs, which contain the native method implementations. This is conveniently achieved by using the static method <tt>java.lang.System.loadLibrary( "mystuff" )</tt>. It is worth noting here that the name passed is not the actual filename of the DLL. Java maps the passed name into an expected filename, appropriate for the underlying system, of the DLL. In the call described previously, the string <tt>"mystuff"</tt> is mapped to a DLL named libmystuff.so on Solaris and mystuff.dll on Win32. If you run the Java program under a debugger, Java conveniently maps the same name <tt>"mystuff"</tt> to <tt>libmystuff_g.so</tt> and <tt>mystuff_g.dll</tt>. This enables you to supply two versions of the DLL-one with debug symbols, one without. Java magically finds the right one, dependent on whether you run under a debugger or not. </p>
<h4><strong>Defining the Calling Convention</strong></h4>
<p>In, essence, Sun defines the method its Java virtual machine will use to call external functions. In order to dynamically link and call the implementation of a native method successfully, the Java virtual machine must know several details. It must know the name of the function within the DLL (the implementation of the native method) to locate the symbol and its entry point. It also must know how to call that function (its return type, number of parameters, and types of parameters). The Java virtual machine expects the functions to be coded in C using the calling conventions appropriate for the underlying architecture (and compiler). </p>
<p>In simple terms, this means the actual function calls Java makes into the DLL must be known names; if you are trying to get Java to call into your existing library, unless your functions magically match the names Java expects (unlikely), you will usually have glue code, which sits between Java and your real functions. Java will call the glue functions<em>,</em> which in turn call in your functions. Alternatively, you can modify your functions to use the names and parameters Java expects, thus eliminating this extra call; however, in practice this is not always feasible, especially when calling existing libraries. Figure 30.2 shows the most likely scenarios of how your code will be segmented. </p>
<p><a href="http://www.80x86.cn/f30-2.gif"><u><font color=#0000ff><strong>Figure 30.2 : </strong><em>Java's use of Dynamic Link Libraries.</em></font></u></a> </p>
<p>The Sun JDK provides a tool, named <tt>javah</tt>, to help you create your native method implementation functions. The developer of native methods runs <tt>javah</tt>, passing it the name of a class. <tt>javah</tt> emits both a header file (.h) and a code file (.c) containing information about each native method and relevant type declarations. The .h file will contain the prototypes of the functions Java will call, and thus expect to find in the DLL. The .c file will contain stubs for each function. Thus, the developer needs to fill in only the details of the functions in the c file and build the DLL appropriately. </p>
<h4><strong>How the Virtual Machine Makes It Work</strong></h4>
<p>When a class is first used by Java, its class descriptor is loaded into memory. The <em>class descriptor</em> can be thought of as a directory for all services provided by the class-there is only one class descriptor loaded, regardless of how many instances of that class exist. Among its entries is a list of <em>method descriptors,</em> which contain information specific to methods, including where the code is, what parameters they take, and method modifiers. </p>
<p>If a method descriptor has its native modifier set, the block will include a pointer to the function that implements that native method. This function resides in some DLL but will be loaded into the Java processes address space by the operating system. At the time the class descriptor with native methods is loaded, the associated DLL does not have to be loaded, and thus the function pointer will not be set. Sometime prior to a native method being called, the associated DLL should be loaded. This is done via a call to <tt>java.system.loadLibrary()</tt>. When this call is made, Java will find and load the DLL but will still not resolve symbols; the resolution phase is delayed until the point of use. At the time of a call to a native method, Java will first check to see whether the native method implementation function has already been resolved-that is, its pointer is not <tt>null</tt>. If it has been previously resolved, the call is performed; otherwise, the resolution of the symbols is attempted. The resolution is performed by making an operating system call to see whether the symbol exists in the caller's address space. This includes the Java process and any DLLs loaded on its behalf. On Win32, this is done via a <tt>GetProcAddress()</tt> and on Solaris via a <tt>dlsym()</tt> call. </p>
<p>If the symbols are correctly resolved, the call is performed as if the Java virtual machine was making a standard C call to its own internal functions. If the resolution fails, the exception <tt>java.lang.UnsatisfiedLinkError</tt> will be thrown at the point of the native method call. </p>
<h2><a name=Summary><strong><font color=#ff0000 size=5>Summary</font></strong></a> </h2>
<p>You should now have a basic understanding of how native methods enable a Java program to access the outside environment. Whether that consists of an operating system, a browser, or your own existing libraries, your Java code can reach them. It should now be clear that native methods do not come without some cost. You lose a lot of the benefits of the Java language. When there is no choice, however, native methods are there to be used. With the basic understanding of how native methods work you should be ready to tackle the next chapters, which provide more in-depth examples of native methods in action, as well as more tips and tricks to help you. </p>
<img src ="http://www.blogjava.net/gm_jing/aggbug/126100.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/gm_jing/" target="_blank">黎夕</a> 2007-06-25 14:29 <a href="http://www.blogjava.net/gm_jing/articles/126100.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>assert</title><link>http://www.blogjava.net/gm_jing/articles/124626.html</link><dc:creator>黎夕</dc:creator><author>黎夕</author><pubDate>Sat, 16 Jun 2007 04:07:00 GMT</pubDate><guid>http://www.blogjava.net/gm_jing/articles/124626.html</guid><wfw:comment>http://www.blogjava.net/gm_jing/comments/124626.html</wfw:comment><comments>http://www.blogjava.net/gm_jing/articles/124626.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/gm_jing/comments/commentRss/124626.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/gm_jing/services/trackbacks/124626.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 第一节&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 断言 assert&#167;1.1.1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs...&nbsp;&nbsp;<a href='http://www.blogjava.net/gm_jing/articles/124626.html'>阅读全文</a><img src ="http://www.blogjava.net/gm_jing/aggbug/124626.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/gm_jing/" target="_blank">黎夕</a> 2007-06-16 12:07 <a href="http://www.blogjava.net/gm_jing/articles/124626.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java程序运行的过程</title><link>http://www.blogjava.net/gm_jing/articles/124617.html</link><dc:creator>黎夕</dc:creator><author>黎夕</author><pubDate>Sat, 16 Jun 2007 02:39:00 GMT</pubDate><guid>http://www.blogjava.net/gm_jing/articles/124617.html</guid><wfw:comment>http://www.blogjava.net/gm_jing/comments/124617.html</wfw:comment><comments>http://www.blogjava.net/gm_jing/articles/124617.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/gm_jing/comments/commentRss/124617.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/gm_jing/services/trackbacks/124617.html</trackback:ping><description><![CDATA[Java程序运行的过程是这样的：<br><span style="COLOR: #ff00ff">类加载器（class loader）加载程序运行所需要的所有类，它通过区分本机文件系统的类和网络系统导入的类增加安全性，这可以限制任何的特洛伊木马程序，因为本机类总是先被加载，<span style="COLOR: #3366ff">一旦所有的类被加载完，执行文件的内存划分就固定了，在这个时候特定的内存地址被分配给对应的符号引用，查找表（lookuo table）也被建立，由于内存划分发生在运行时，解释器在受限制的代码区增加保护防止未授权的访问；</span><span style="COLOR: #ff0000">然后字节码校验器（byte code verifier）进行校验，主要执行下面的检查：类符合JVM规范的类文件格式，没有违反访问限制，代码没有造成堆栈的上溢或者下溢，所有操作代码的参数类型都是正确的，没有非法的数据类型转换（例如将整型数转换成对象类型）发生；</span><span style="COLOR: #ff00ff">校验通过的字节码被解释器（interpreter）执行，解释器在必要时通过运行时系统执行对底层硬件的合适调用。</span></span>后三个答案是SL275中的原话 
<img src ="http://www.blogjava.net/gm_jing/aggbug/124617.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/gm_jing/" target="_blank">黎夕</a> 2007-06-16 10:39 <a href="http://www.blogjava.net/gm_jing/articles/124617.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java保留字</title><link>http://www.blogjava.net/gm_jing/articles/124454.html</link><dc:creator>黎夕</dc:creator><author>黎夕</author><pubDate>Fri, 15 Jun 2007 03:47:00 GMT</pubDate><guid>http://www.blogjava.net/gm_jing/articles/124454.html</guid><wfw:comment>http://www.blogjava.net/gm_jing/comments/124454.html</wfw:comment><comments>http://www.blogjava.net/gm_jing/articles/124454.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/gm_jing/comments/commentRss/124454.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/gm_jing/services/trackbacks/124454.html</trackback:ping><description><![CDATA[java保留字:const, goto<br>java关键字：void,super,default,long,throw<br>&nbsp;<br><span style="COLOR: red">注意：关键字都是小写，String不是关键字</span>
<img src ="http://www.blogjava.net/gm_jing/aggbug/124454.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/gm_jing/" target="_blank">黎夕</a> 2007-06-15 11:47 <a href="http://www.blogjava.net/gm_jing/articles/124454.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>基本类型</title><link>http://www.blogjava.net/gm_jing/articles/124448.html</link><dc:creator>黎夕</dc:creator><author>黎夕</author><pubDate>Fri, 15 Jun 2007 03:14:00 GMT</pubDate><guid>http://www.blogjava.net/gm_jing/articles/124448.html</guid><wfw:comment>http://www.blogjava.net/gm_jing/comments/124448.html</wfw:comment><comments>http://www.blogjava.net/gm_jing/articles/124448.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/gm_jing/comments/commentRss/124448.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/gm_jing/services/trackbacks/124448.html</trackback:ping><description><![CDATA[<p>基本类型：<br>&nbsp; - byte的长度是一个字节。<br>&nbsp; - short和char的长度是两个字节，且char是唯一的无符号基本类型。<br>&nbsp; - int和float的长度都是四个字节。<br>&nbsp; - long和double的长度都是八个字节。<br>&nbsp; <br>&nbsp; <br>表达式<br>- 只有boolean，char，int，long，float，double和字符串的表达式；没有byte和short的表达式<br>- 字符（char）表达式：'d'、'\u0c20'（0c20必须是四位的十六进制数字）<br>- 整型（int）表达式：0x3c0是十六进制形式，010是八进制形式（0x:表示十六进制 0表示八进制）<br>- 可使用合法范围内的整型表达式对byte、short和char变量初始化</p>
<p>&nbsp;<br></p>
<img src ="http://www.blogjava.net/gm_jing/aggbug/124448.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/gm_jing/" target="_blank">黎夕</a> 2007-06-15 11:14 <a href="http://www.blogjava.net/gm_jing/articles/124448.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>数组</title><link>http://www.blogjava.net/gm_jing/articles/124434.html</link><dc:creator>黎夕</dc:creator><author>黎夕</author><pubDate>Fri, 15 Jun 2007 01:56:00 GMT</pubDate><guid>http://www.blogjava.net/gm_jing/articles/124434.html</guid><wfw:comment>http://www.blogjava.net/gm_jing/comments/124434.html</wfw:comment><comments>http://www.blogjava.net/gm_jing/articles/124434.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/gm_jing/comments/commentRss/124434.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/gm_jing/services/trackbacks/124434.html</trackback:ping><description><![CDATA[<p>数组</p>
<p><br>* 数组是一个对象 .. 下面的代码创建一个整型数组的引用：<br>&nbsp;&nbsp;&nbsp; int[] ii;<br>&nbsp;&nbsp;&nbsp; int ii[];</p>
<p>* 你可以通过new操作或者显式的初始化创建一个数组对象：<br>&nbsp;&nbsp;&nbsp; ii = new int[3];<br>&nbsp;&nbsp;&nbsp; ii = new int[] { 1,2,3 };<br>&nbsp;&nbsp;&nbsp; int[] ii = { 1,2,3 }; // 只有声明的时候</p>
<p><br>* 小心：你不能象下面这样创建一个数组对象：<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int iA[3];</p>
<p>* 如果你不提供初始值，对象数组的元素总是初始化成null，基本类型数组的元素<br>总是初始化成零</p>
<img src ="http://www.blogjava.net/gm_jing/aggbug/124434.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/gm_jing/" target="_blank">黎夕</a> 2007-06-15 09:56 <a href="http://www.blogjava.net/gm_jing/articles/124434.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Integer&lt;--&gt;int</title><link>http://www.blogjava.net/gm_jing/articles/124363.html</link><dc:creator>黎夕</dc:creator><author>黎夕</author><pubDate>Thu, 14 Jun 2007 09:28:00 GMT</pubDate><guid>http://www.blogjava.net/gm_jing/articles/124363.html</guid><wfw:comment>http://www.blogjava.net/gm_jing/comments/124363.html</wfw:comment><comments>http://www.blogjava.net/gm_jing/articles/124363.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/gm_jing/comments/commentRss/124363.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/gm_jing/services/trackbacks/124363.html</trackback:ping><description><![CDATA[&nbsp;&nbsp; Integer&nbsp;i = new Integer(123);<br>&nbsp;&nbsp; Integer i = new Integer("123");<br>&nbsp;&nbsp; Integer i = Integer.valueOf("123");<br>&nbsp;&nbsp; Integer i = Integer.valueOf(123);<br><br>--------------------------------------------<br>&nbsp; int ii = (new Integer("123")).intvalue();<br>&nbsp; int ii = Integer.parseInt("123"); 
<img src ="http://www.blogjava.net/gm_jing/aggbug/124363.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/gm_jing/" target="_blank">黎夕</a> 2007-06-14 17:28 <a href="http://www.blogjava.net/gm_jing/articles/124363.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>scjp 一些知识总结</title><link>http://www.blogjava.net/gm_jing/articles/124349.html</link><dc:creator>黎夕</dc:creator><author>黎夕</author><pubDate>Thu, 14 Jun 2007 08:52:00 GMT</pubDate><guid>http://www.blogjava.net/gm_jing/articles/124349.html</guid><wfw:comment>http://www.blogjava.net/gm_jing/comments/124349.html</wfw:comment><comments>http://www.blogjava.net/gm_jing/articles/124349.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/gm_jing/comments/commentRss/124349.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/gm_jing/services/trackbacks/124349.html</trackback:ping><description><![CDATA[初始化<br><br>* All class-level (member) variables are initialized before they can<br>&nbsp; be used.<br>&nbsp; All local variables are not initialized until it is done explicitly.<br><br><br>* 所有的主成员在他们使用之前被初始化<br>&nbsp; 所有的局部变量必须通过显式的赋值来初始化<br><br>* An array object (as distinct from reference) is always initialized<br>&nbsp; (with zeroes or nulls)<br><br>* 数组对象总是能够初始化（零或者null）<br><br>* Member initialization with the declaration has exception problems:<br>- cannot call methods that throw a checked exception.<br>- cannot do error recovery from runtime exceptions.<br>- If you need to deal with errors you can put the initialization code<br>&nbsp; along with try/catch statements in either a ctor (for instance fields)<br>&nbsp; or in a static initialization block for static fields. You can also have<br>&nbsp; instance (non-static) initialization blocks but ctors are more<br>&nbsp; recognizable.<br><br>* 需要处理异常的成员初始化<br>- 不能调用会抛出异常的方法<br>- 不能对基本异常做任何处理<br>- 如果你需要处理错误，将初始化的代码放到构造器或者静态初始化块的<br>&nbsp; try/catch块中，当然，你也可以放到非静态的代码块中，但是构造器似乎更为通用。<br><br>------------------------------------------------------------------------<br><br>Strings<br><br>字符串<br><br>* The String class<br>&nbsp; - Because string is an immutable class, its instance methods that<br>&nbsp;&nbsp;&nbsp; look like they would transform the object they are invoked upon,<br>&nbsp;&nbsp;&nbsp; do not alter the object and instead return new String objects.<br>&nbsp; - String has methods concat(String),trim(),replace(char,char)<br>&nbsp; - String has static valueOf methods for a whole bunch of primitives<br>&nbsp;&nbsp;&nbsp; and for Object too (equivalent to Object.toString()).<br>&nbsp; - in substring(int,int), the second arg is exclusive.<br>&nbsp; - indexOf methods returns -1 for 'not found'<br><br>* 类String<br>&nbsp; - 类String是不可变的，即使他的某些方法看起来会改变字符串的内容，但实际<br>&nbsp;&nbsp;&nbsp; 上他们返回的是一个新的字符串，而不是改变原来的字符串<br>&nbsp; - 类String的方法：cancat(String)，trim()，replace(char,char)<br>&nbsp; - 类String的静态方法valueOf能处理所有的基本类型和对象（调用对象的<br>&nbsp;&nbsp;&nbsp; toString()方法）<br>&nbsp; - 在substring(int,int)方法中，第二个参数是"不包括"的（译者注：第一个参<br>&nbsp;&nbsp;&nbsp; 数是"包括"的，例如substring(1,4)将会返回字符串从第二个字符开始（包括<br>&nbsp;&nbsp;&nbsp; 第二个字符），到第五个字符结束（不包括第五个字符）的子字符串）<br>&nbsp; - 如果没有找到，indexOf方法将返回-1<br><br>* String Pool:<br>&nbsp; A JVM has a string pool where it keeps at most one object of any<br>&nbsp; String. String literals always refer to an object in the string<br>&nbsp; pool. String objects created with the new operator do not refer to<br>&nbsp; objects in the string pool but can be made to using String's intern()<br>&nbsp; method. Two String references to 'equal' strings in the string pool<br>&nbsp; will be '=='.<br><br>* 字符串池<br>&nbsp; 虚拟机有一个字符串池，保存着几乎所有的字符串对象。字符串表达式总是指向<br>&nbsp; 字符串池中的一个对象。使用new操作创建的字符串对象不指向字符串池中的对象<br>&nbsp; 但是可以使用intern方法使其指向字符串池中的对象（译者注：如果池中已经有<br>&nbsp; 相同的字符串--使用equals方法确定，则直接返回池中的字符串，否则先将字符串<br>&nbsp; 添加到池中，再返回）。池中两个相等的字符串如果使用'=='来比较将返回真<br><br>* StringBuffer doesn't override equals.<br><br>* 类StringBuffer没有覆盖equals方法<br><br>------------------------------------------------------------------------<br><br>Arrays<br><br>数组<br><br>* Arrays are objects .. the following create a reference for an int array.<br>&nbsp;&nbsp;&nbsp; int[] ii;<br>&nbsp;&nbsp;&nbsp; int ii[];<br><br>* 数组是一个对象 .. 下面的代码创建一个整型数组的引用：<br>&nbsp;&nbsp;&nbsp; int[] ii;<br>&nbsp;&nbsp;&nbsp; int ii[];<br><br>* You can create an array object with new or an explicit initializer:<br>&nbsp;&nbsp;&nbsp; ii = new int[3];<br>&nbsp;&nbsp;&nbsp; ii = new int[] { 1,2,3 };<br>&nbsp;&nbsp;&nbsp; int[] ii = { 1,2,3 ); // only when you declare the reference.<br><br>* 你可以通过new操作或者显式的初始化创建一个数组对象：<br>&nbsp;&nbsp;&nbsp; ii = new int[3];<br>&nbsp;&nbsp;&nbsp; ii = new int[] { 1,2,3 };<br>&nbsp;&nbsp;&nbsp; int[] ii = { 1,2,3 }; // 只有声明的时候<br><br>* CAREFUL: You can't create an array object with:<br>&nbsp;&nbsp;&nbsp; int iA[3];<br><br>* 小心：你不能象下面这样创建一个数组对象：<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int iA[3];<br><br>* If you don't provides values, the elements of obj arrays are<br>&nbsp; always initialized to null and those of primitive arrays are<br><br>* 如果你不提供初始值，对象数组的元素总是初始化成null，基本类型数组的元素<br>总是初始化成零<br><br>------------------------------------------------------------------------<br><br>Primitive Types<br><br>基本类型<br><br>* Primitive types:<br>&nbsp; - short and char are both 2 bytes.<br>&nbsp;&nbsp;&nbsp; int and float are both 4 bytes.<br>&nbsp;&nbsp;&nbsp; long and double are both 8 bytes.<br>&nbsp; - char is the only unsigned primitive type.<br><br>* 基本类型：<br>&nbsp; - short和char的长度是两个字节。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int和float的长度都是四个字节。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; long和double的长度都是八个字节。<br>&nbsp; - char是唯一的无符号基本类型<br><br>* Literals:<br>&nbsp; - You can have boolean, char, int, long, float, double and String<br>&nbsp;&nbsp;&nbsp; literals.<br>&nbsp;&nbsp;&nbsp; You cannot have byte or short literals.<br>&nbsp; - char literals: 'd' '\u0c20' (the 0c20 must be a 4-digit hex number).<br>&nbsp; - int literals: 0x3c0 is hex, 010 is octal(for 8).<br>&nbsp; - You can initialize byte, short and char variables with int literals<br>&nbsp;&nbsp;&nbsp; (or const int expressions) provided the int is in the appropriate range.<br><br>* 表达式<br>- 只有boolean，char，int，long，float，double和字符串的表达式；没有byte<br>&nbsp; 和short的表达式<br>- 字符（char）表达式：'d'、'\u0c20'（0c20必须是四位的十六进制数字）<br>- 整型（int）表达式：0x3c0是十六进制形式，010是八进制形式<br>- 可是使用合法范围内的整型表达式对byte、short和char变量初始化<br><br>* CAREFUL: can't assign a double literal to a float .. float fff = 26.55;<br><br>* 小心：不能将一个double表达式赋给一个float变量 .. float fff = 26.55;<br><br>* The only bit operators allowed for booleans are &amp;^| (cant do ~ or<br><br>* 位运算只有&amp;^|（不能使用~或者移位操作）<br><br>* Primitive wrapper classes<br>&nbsp;&nbsp; - are immutable.<br>&nbsp;&nbsp; - override equals.<br>&nbsp;&nbsp; - the static valueOf(String) methods in primitive wrapper classes return<br>&nbsp;&nbsp;&nbsp;&nbsp; wrapper objects rather than a primitives.<br><br>* 基本类型的包装类<br>&nbsp; - 不可变的<br>&nbsp; - 覆盖equals方法<br>&nbsp; - 静态方法valueOf(String)返回的是包装类而不是基本类型<br><br>------------------------------------------------------------------------<br><br>Conversions and Promotions<br><br>类型转换<br><br>* boolean-&gt;anything but boolean or string is not allowed.<br>* All other primitive conversions are allowed with an explicit cast.<br>* char/byte/short/int/long to float/double is a widening conversion even<br>&nbsp; if some precision is lost (the overall magnitude is always preserved).<br>* Narrowing conversions require an explicit cast.<br>&nbsp; - integral narrowing conversions simply discard high-order bits.<br>&nbsp; - anything to char is a narrowing conversion (inc byte) because its<br>&nbsp;&nbsp;&nbsp; signed to unsigned and negative numbers get messed up<br><br>* boolean不能跟其它的任何类型相互转换，但是boolean-&gt;String是允许的<br>* 所有的基本类型之间可以通过显式的类型转换而转变成其它类型<br>* char/byte/short/int/long到float/double的转换是宽转换，即使有可能丢掉部<br>&nbsp; 分信息<br>* 窄转换需要显式的转换<br>&nbsp; - 整型的窄转换只简单的去掉高位比特<br>&nbsp; - 所有到char的转换都是窄转换（包括byte）因为转换是从有符号数到无符号数<br>&nbsp;&nbsp;&nbsp; 的转换，负数将会得到一个混乱的结果<br><br>* Widening primitive and reference conversions are allowed for assignment<br>&nbsp; and in matching the arguments to a method (or ctor) call.<br><br>* 对象和基本类型的宽转换允许在赋值和匹配的方法调用中（非显式的）使用<br><br>* For assignment (but not method invocation), representable constant<br>&nbsp; int expressions can be converted to byte, char or shorts (eg. char c =<br>&nbsp; 65).<br><br>* 赋值时，合法的整型表达式能被自动转换成byte、char或者short（例如：<br>&nbsp; char c = 65）<br><br>* Unary numeric promotions: byte/short/char to int<br><br>* 一元运算时，byte/short/char将自动转换成int<br><br>* Binary numeric promotions:<br>&nbsp; - both arguments are made (in order of preference)<br>&nbsp;&nbsp;&nbsp; double/float/long/int.<br>&nbsp; - include (in)equality operators.<br><br>* 二进制数据类型转换：<br>&nbsp; - 所有的参数自动转换成（按循序的）double/float/long/int<br>&nbsp; - 包括比较运算<br><br>* char/byte/short are promoted to int for nearly every operator ... be<br>&nbsp; careful not to assign the uncast int return value to a narrower type,<br><br>&nbsp;&nbsp;&nbsp;&nbsp; bytesum = byte1 + byte2; // won't compile without a cast.<br>&nbsp;&nbsp;&nbsp;&nbsp; bytesum += byte2; // is ok.<br>&nbsp; - applies to bitshift operators (as a unary promotion on each arg).<br>&nbsp; - applies to unary + and - (eg. byte b = +anotherByte; needs a cast).<br><br>&nbsp; - there are no promotions for ++, --, += etc.<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; byte b=10;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char c = b++; //explicit cast needed to convert byte to char<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char c = b++ +10; //explicit cast needed to convert int to char<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char c = b++ +10L; //explicit cast needed to convert long to char<br><br>* char/byte/short几乎在所的运算中都被转换成int &#8230; 要当心不要将int类型的<br>&nbsp; 返回值在没有显式转换之前赋给一个更小的类型：<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bytesum = byte1 + byte2; //没有显式的转换不能通过编译<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bytesum += byte2; // 没有问题<br>&nbsp; - 本规则适合于位运算（以及每个一元运算的参数）<br>&nbsp; - 本规则不适用于++，--，+=等操作<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; byte b = 10;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char c = b++; //需要显式的将byte转换成char<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char c = b++ + 10; //需要显式的将int转换成char<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char c = b++ + 10L; //需要显式的将long转换成char<br><br>* A switch argument can be any type that can implicit-cast to an int<br>&nbsp; (byte/char/short/int but not boolean or long).<br>&nbsp; - The argument and cases can also be compile-time constant<br>&nbsp;&nbsp;&nbsp; expressions.<br><br>* switch的参数可以是任何可以自动转换成int型的基本类型（<br>&nbsp; byte/char/short/int是合法的参数，但是boolean和long型是不合法的）<br>&nbsp; - switch的参数和case的参数可以是常量表达式<br><br>* Explicit Casting:<br>&nbsp; - Impossible casts are detected at compile time.<br>&nbsp;&nbsp;&nbsp; Other bad casts cause runtime exceptions rather than messes.<br><br>* 显式的转换<br>&nbsp; - 不可能的转载编译期间就能检测到。其他错误的转换将抛出异常以防止数据的<br>混乱<br><br>* Array casts:<br>&nbsp; - The only implicit conversion for arrays is: Base[] base = new Der[5];<br>&nbsp;&nbsp;&nbsp; - a runtime exception is thrown if you try to add anything but Derived<br>&nbsp; - There are no implicit casts for arrays of primitives.<br>&nbsp; - You can make an explicit array cast:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String[] strs = (String[]) ObjectArray;<br><br><br>* 数组转换：<br>&nbsp; - 对象数组唯一的自动转换的情况是：Base[] base = new Der[5];<br>&nbsp;&nbsp;&nbsp; - 如果你尝试添加Derived以外的对象，将会得到一个运行期异常<br>&nbsp; - 基本类型数组没有自动转换的情况<br>&nbsp; - 可以使用显式的数组类型转换：<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String[] strs = (String[]) ObjectArray;<br><br>------------------------------------------------------------------------<br><br>------------------------------------------------------------------------<br><br>Object-oriented concepts<br><br>面向对象的概念<br><br>* The signature of a method is its name, argument type and argument order.<br>&nbsp; - an overload is legal provided the two methods have different signatures.<br>&nbsp; - an override must have the same signature and return type, throw no new<br>&nbsp;&nbsp;&nbsp; checked exceptions and be at least as accessible as the method it is<br>&nbsp;&nbsp;&nbsp; overriding.<br><br>* 一个方法通过它的名字，参数类型以及顺序来标识<br>&nbsp; - 有不同标识的方法重载是合法的<br>&nbsp; - 方法覆盖必须有相同的标识和返回值，不能抛出新的普通异常，不能比他要覆<br>&nbsp;&nbsp;&nbsp; 盖的方法拥有更少的权限<br><br>* Fields do not act polymorphically:<br>&nbsp; - whenever you access a field from outside the class, the declared type of<br>&nbsp;&nbsp;&nbsp; the reference is used rather than the type of the object it refers to.<br>&nbsp; - regardless of the type of the reference, a method will always access its<br>&nbsp;&nbsp;&nbsp; own fields rather than those of a derived class.<br><br>* 变量成员没有多态性<br>&nbsp; - 当你从类外面引用变量成员时，你总是得到定义的类型，而非实际指向的类型<br><br>&nbsp; - 不管变量成员的类型是什么，方法总是使用类自己的变量成员，而不是其他的<br>&nbsp;&nbsp;&nbsp; 继承过来的变量成员<br><br>* Private method calls are statically bound ... a method will call<br>&nbsp; the private method in the class where it is defined .. even if the<br>&nbsp; calling method is inherited by a derived class and the derived<br>&nbsp; class defines a method with the same signature as the private method.<br><br><br>* 私有方法的调用是静态绑定的 &#8230; 方法可以调用他所在类之内的私有方法 .. 即<br>&nbsp; 使调用的方法的夫类中有与此私有方法标识相同的方法<br><br>* Calls to public and protected methods in the same class are dynamically<br>&nbsp; bound ... even for constructors (and from private methods). This is<br>&nbsp; different to C++.<br><br>* 对公共的和保护的方法的调用是动态绑定的 &#8230; 同样构造函数（不同于私有方法？）<br>&nbsp; 也是动态绑定的。这是与C++不同的地方<br><br>* Re-using a static method's name in a derived class:<br>&nbsp; - A static method cannot be overriden by a non-static method<br>&nbsp; - A static method can be overriden by a static method but does not<br>&nbsp;&nbsp;&nbsp; dynamically bind (therefore static methods can't be abstract)<br>&nbsp; - You can overload a static method with a non-static method.<br>&nbsp; * note also that a static method can be inherited.<br>&nbsp; * note that a static var can be 'overriden' by a non-static var.<br><br>* 重用夫类中的静态方法的名字：<br>&nbsp; - 静态方法不能被非静态的方法覆盖<br>&nbsp; - 静态方法可以被静态方法覆盖，但是不能动态绑定（所以静态方不能是抽象的）<br>&nbsp; - 可以使用非静态的方法重载静态的方法<br>&nbsp; * 注意静态方法是可以继承的<br>&nbsp; * 注意静态的变量可以被非静态的变量"覆盖"<br><br>* It's legal to assign any reference type including an Interface reference<br>&nbsp; to an Object reference .. which makes sense because the interface ref<br>&nbsp; must point to an Object (or null).<br><br>* 讲任何类型的引用包括接口的引用付给一个Object的引用是合法的 .. 应为一个<br>&nbsp; 接口的引用总是指向一个Object（或者null）<br><br>------------------------------------------------------------------------<br><br>Nested classes<br><br>-&gt; from the Java Language Specification<br>-&gt; from Sun's Java Tutorial<br><br>嵌套类<br><br>-&gt; 来自Java语言规范<br>-&gt; 来自Sun的Java教程<br><br>*** A nested class is a class that is defined inside another class.<br><br>*** 嵌套类是定义在另外一个类的内部的类<br><br>* There are two distinct types of nested classes:<br>&nbsp; - static nested classes (or top-level nested classes)<br>&nbsp; - inner classes (which are always associated with an instance of<br>&nbsp;&nbsp;&nbsp; an enclosing class).<br><br>* 有两种截然不同的嵌套类<br>&nbsp; - 静态的嵌套类（或者说顶层的嵌套类）<br>&nbsp; - 内部类（总是定义在其他类的实例里面）<br><br>* (Nested) inner class types:<br>&nbsp; - member classes,<br>&nbsp; - local classes (method or code block),<br>&nbsp; - anonymous classes.<br><br>* （嵌套的）内部类：<br>&nbsp; - 成员类<br>&nbsp; - 局部类（方法或者代码块）<br>&nbsp; - 匿名类<br><br>* Top-level classes (all classes are either top-level or inner)<br>&nbsp; - static nested classes,<br>&nbsp; - package member classes.<br><br>* 顶层类（所有的类不是顶层类就是内部类）<br>&nbsp; - 静态的嵌套类<br>&nbsp; - 包成员类<br><br>* Access to enclosing class:<br>&nbsp; - all outer-class members (inc. private) are accessible to an inner<br>&nbsp;&nbsp;&nbsp; class [Usually without scope modifiers, but if they are hidden by<br>&nbsp;&nbsp;&nbsp; an inner class name, you can use Outer.this.outerVar]<br>&nbsp; - static nested classes cannot acccess instance variables from enclosing<br>&nbsp;&nbsp;&nbsp; classes (there is no instance), but can access their static variables<br>&nbsp;&nbsp;&nbsp; (and classes i would think).<br><br>* 内部类的权限<br>&nbsp; - 外部类所有的成员（比如私有的）都有权限访问内部类 [通常没有任何的权限<br>&nbsp;&nbsp;&nbsp; 修饰，但是如果对内部类是隐藏的，可以通过Outer.this.outerVar来引用]<br>&nbsp; - 静态内部累不可以引用外部类的实例变量（没有实例），但是可以引用外部类<br>&nbsp;&nbsp;&nbsp; 的静态变量（我想，引用静态的类也是允许的）<br><br>* Instantiation:<br>&nbsp; - For accessible inner classes: Outer.Inner i = new Outer().new Inner();<br>&nbsp;&nbsp;&nbsp; Even if you are in Outer's scope, you need to have an Outer instance.<br>&nbsp; - For accessible static nested classes:<br>&nbsp;&nbsp;&nbsp; Outer.Nested nested = new Outer.Nested();<br><br>* 实例化：<br>&nbsp; - 内部类的引用：Outer.Inner i = new Outer().new Inner();<br>&nbsp;&nbsp;&nbsp; 即使在外部类的范围内，你也需要一个外部类的实例<br>&nbsp; - 静态内部类的引用：Outer.Nested nested = new Outer.Nested();<br><br>* Local inner classes cannot access non-final local variables or method<br>&nbsp; arguments.<br><br>* 局部内部类不能引用非最终（final）的局部变量和方法参数<br><br>* Nested classes generally have the same options with regard to<br>&nbsp; modifiers as do variables declared in the same place.<br><br>* 嵌套类可以与同等位置上的变量拥有相同的权限修饰<br><br>* Unlike class-level nested classes, local classes are executed in the<br>&nbsp; method's sequence of execution so you can't create an instance of the<br>&nbsp; local class before it is declared.<br><br>* 与类一级的内部类不同的是，局部类是按次序执行的，所以你不能在定义之前创<br>&nbsp; 建一个类的实例<br><br>* The static keyword marks a top-level construct (class, method or<br>&nbsp; field) and can never be subject to an enclosing instance.<br>&nbsp; - no inner class can have a static member.<br>&nbsp; - no method can have a static member.<br><br>* 关键字static使一个顶层的构造（类，方法或者成员变量）不属于他的外部类实例<br>&nbsp; - 内部类不能有静态成员<br>&nbsp; - 方法不能有静态成员<br><br>* Interfaces automatically attach 'public static final' to field and<br>&nbsp; class members (thus making them top-level nested rather than member<br>&nbsp; inner classes).<br><br>* 接口自动将"public static final"的权限修饰赋予所有的成员变量和方法（这<br>&nbsp; 将保证它们是顶层嵌套的而不是内部成员类）<br><br>* A nested class cannot have the same simple name as any of its<br>&nbsp; enclosing classes (note: there is no similar restriction on method<br>&nbsp; or variable names).<br><br>* 嵌套类不能使用与它的任何外部类的名字相同的名字来命名（注意：方法和变量<br><br>------------------------------------------------------------------------<br><br>------------------------------------------------------------------------<br><br>Threads<br><br>线程<br><br>* Know where the basic thread methods are:<br>&nbsp; - wait, notify and notifyAll are Object instance methods.<br>&nbsp; - start, stop, suspend, resume and interrupt are Thread instance methods.<br>&nbsp; - sleep and yield are Thread static methods<br><br>* 了解基本的线程方法的位置：<br>&nbsp; - wait，notify和notifyAll是Object的实例方法<br>&nbsp; - start，stop，suspend，resume和interrupt是Thread的实例方法<br>&nbsp; - sleep和yield是Thread的静态方法<br><br>* Thread states:<br>&nbsp; - Bruce Eckel lists 4 thread states: new, runnable, blocked, dead.<br><br>* 线程的状态<br>&nbsp; - Bruce Eckel 列出四种线程状态：创建，可运行的，堵塞的，死亡<br><br>* Blocking<br>&nbsp; - There are 5 ways a thread can be blocked - sleep, wait, suspend,<br>&nbsp;&nbsp;&nbsp; synchronization, io blocking.<br>&nbsp; - sleep and suspend do not release locks held by the thread.<br><br>* 堵塞的<br>&nbsp; - 有五种方法可以使一个线程堵塞 - sleep，wait，suspend，同步，io堵塞<br>&nbsp; - sleep和suspend期间线程不释放对象的锁<br><br>* Deprecated methods<br>&nbsp; - stop is unsafe because it releases all locks and may leave objects in<br>&nbsp;&nbsp;&nbsp; an inconsistent state.<br>&nbsp; - suspend is deprecated because its failure to release locks makes it<br>&nbsp;&nbsp;&nbsp; prone to deadlock. Calling wait in a sync block is safer.<br><br>* 不推荐使用的方法<br>&nbsp; - stop方法因为释放所有的锁而导致有可能使线程进入不一致的状态，不安全<br>&nbsp; - suspend不推荐使用是因为它不能释放锁而导致有可能进入死锁状态。在同步<br><br>* The isAlive method returns false for new threads as well as dead threads.<br><br>* isAlive方法在线程创建和死亡的状态下都返回false<br><br>* Threads inherit their priority from the thread that calls their ctor.<br><br>* 线程继承调用他们的构造函数的线程的优先级<br><br>------------------------------------------------------------------------<br><br>Exceptions<br><br>异常<br><br>* Non-runtime exceptions are called checked exceptions.<br><br>* 非运行期异常叫普通异常<br><br>* Even if a method explicitly throws a runtime exception, there is no<br>&nbsp; obligation for the caller to acknowledge the exception. One consequence<br>&nbsp; of this is that the restriction on exceptions thrown by an overriding<br>&nbsp; method only applies to checked exceptions.<br><br>* 如果方法抛出运行期异常，调用者没有必要知道。由此推论出，方法覆盖抛出异<br>常的限制只适用于普通异常<br><br>* A try block's finally clause is called unless the JVM is exited (i think).<br>&nbsp; - a return in try or catch does not prevent finally from being executed.<br><br>* try块的fanally字句总是被执行，除非程序推出虚拟机（我想是这样的）<br>&nbsp; - try或者catch里面的语句不能阻止finally字句的执行<br><br>* A try block's finally statement will be executed (unless the thread dies)<br>&nbsp; before control leaves the try/catch/finally scope. It will be executed<br>&nbsp; before unhandled exceptions (from try or catch) are passed back up the<br>&nbsp; calling stack.<br><br>* try块的finally字句在退出try/catch/finally之前执行（除非线程已经死亡）。<br>&nbsp; 它将会在将没有捕捉的异常（产生于try或者catch）送回调用堆栈之前执行<br><br>* If you return from a try and finally does not return ... 1) the return<br>&nbsp; value is calculated, 2) finally executes and 3) the method returns with<br><br>* 如果你从try字句返回并且finally字句不包含返回 &#8230; 1) 计算返回值，2) 执行<br>&nbsp; finally字句， 3) 方法返回执行finally之前计算的结果<br><br>* If you have a return in both try and finally, the finally's value<br>&nbsp; is always returned.<br><br>* 如果你同时在try和finally中返回，则总是返回finally中的返回值<br><br>* If try/catch excludes continuation following finally, it is a compile<br>&nbsp; error to have any statements there.<br><br>* 在try/catch和finally之间放置任何语句将会导致编译错误<br><br>* Primitive floating point operations do not throw exceptions. They use<br>&nbsp; NaN and infinity instead.<br><br>* 基本的浮点运算不会抛出异常，它们使用NaN和infinity来表示异常的结果<br><br>* A constructor can throw any exception.<br><br><br>------------------------------------------------------------------------<br><br>Streams<br><br>流<br><br>* System.in is an InputStream and out and err are PrintStreams.<br><br>* System.in是一个InputStream，out和err是PrintStream<br><br>* Beware of instances of the abstract OutputStream and InputStream.<br><br>* 慎防实例化抽象的OutputStream和InputStream<br><br>* Some OutputStreams:<br>&nbsp; OutputStream<br>&nbsp;&nbsp;&nbsp; - write(int) writes the eight low-order bits to the underlying stream<br>&nbsp;&nbsp;&nbsp; - write(byte[]) write(byte[],int off,int len)<br>&nbsp;&nbsp;&nbsp; - flush()<br>&nbsp;&nbsp;&nbsp; - close()<br>&nbsp; BufferedOutputStream<br>&nbsp;&nbsp;&nbsp; - has two ctors: (OutputStream) (OutpuStream, int size)<br>&nbsp; DataOutputStream<br>&nbsp;&nbsp;&nbsp; - writes primitives and strings to a byte-based stream.<br>&nbsp; ObjectOutputStream<br>&nbsp;&nbsp;&nbsp; - writes primitives, strings and serializable objects (inc arrays).<br>&nbsp;&nbsp;&nbsp; - is not a FilterOutputStream (seems strange).<br>&nbsp; PrintStream<br>&nbsp;&nbsp;&nbsp; - two ctors: (OutputStream) (OutputStream, boolean autoflush)<br>&nbsp;&nbsp;&nbsp; - never throws IOExceptions (sets internal flag instead)<br>&nbsp;&nbsp;&nbsp; - print and println for primitives and strings.<br>&nbsp;&nbsp;&nbsp; - print(Object) prints Object.toString().<br>&nbsp;&nbsp;&nbsp; - System.out and System.err are printstreams.<br>&nbsp; FileOutputStream<br>&nbsp;&nbsp;&nbsp; - 4 constructors: (File) (FileDescriptor) (String)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (String, boolean append)<br>&nbsp; PipedOutputStream<br>&nbsp;&nbsp;&nbsp; - two ctors: () (PipedInputStream)<br>&nbsp;&nbsp;&nbsp; - method to connect(PipedInputStream)<br>&nbsp; ByteArrayOutputStream<br>&nbsp;&nbsp;&nbsp; - 2 ctors: () (int size)<br><br>* 一些OutputStream：<br>&nbsp; OutputStream<br>&nbsp;&nbsp;&nbsp; - write(int) 将int的低八位写入底层的流<br>&nbsp;&nbsp;&nbsp; - write(byte[]) write(byte[],int off,int len)<br>&nbsp;&nbsp;&nbsp; - flush()<br>&nbsp;&nbsp;&nbsp; - close()<br>&nbsp; BufferedOutputStream<br>&nbsp;&nbsp;&nbsp; - 两个构造函数：(OutputStream) (OutpuStream, int size)<br>&nbsp; DataOutputStream<br>&nbsp;&nbsp;&nbsp; - 将基本类型和字符串写入基于字节的流<br>&nbsp; ObjectOutputStream<br>&nbsp;&nbsp;&nbsp; - 写入基本类型，字符串和串行化的对象（例如数组）<br>&nbsp;&nbsp;&nbsp; - is not a FilterOutputStream (seems strange).<br>&nbsp; PrintStream<br>&nbsp;&nbsp;&nbsp; - 两个构造函数：(OutputStream) (OutputStream, boolean autoflush)<br>&nbsp;&nbsp;&nbsp; - 永远不会抛出IOException（取而代之的是设置某些标记位）<br>&nbsp;&nbsp;&nbsp; - print and println的参数可以是基本类型和字符串<br>&nbsp;&nbsp;&nbsp; - print(Object)打印Object.toString().<br>&nbsp;&nbsp;&nbsp; - System.out和System.err是PrintStream<br>&nbsp; FileOutputStream<br>&nbsp;&nbsp;&nbsp; - 四个构造函数：(File) (FileDescriptor) (String)(String, boolean append)<br>&nbsp; PipedOutputStream<br>&nbsp;&nbsp;&nbsp; - 两个构造函数：() (PipedInputStream)<br>&nbsp;&nbsp;&nbsp; - 方法connect(PipedInputStream)<br>&nbsp; ByteArrayOutputStream<br>&nbsp;&nbsp;&nbsp; - 两个构造函数：() (int size)<br><br>* Some Writers<br>&nbsp; - OutputStreamWriter<br>&nbsp; - StringWriter, CharArrayWriter - like ByteArrayOutputStream<br>&nbsp; - FileWriter, BufferedWriter, PrintWriter, FilterWriter<br>&nbsp; - There is no ObjectWriter, DataWriter.<br>&nbsp; - PrintWriter can be constructed with an OutputStream or Writer.<br><br>* 一些Writer<br>&nbsp; - OutputStreamWriter<br>&nbsp; - StringWriter, CharArrayWriter - 与ByteArrayOutputStream相似<br>&nbsp; - FileWriter, BufferedWriter, PrintWriter, FilterWriter<br>&nbsp; - 没有ObjectWriter, DataWriter.<br>&nbsp; - PrintWriter可以使用OutputStream或者Writer来构造<br><br>* Some Readers:<br>&nbsp; - LineNumberReader doesn't attach numbers, it has getLineNumber().<br>&nbsp; - CharArrayReader is ctd with the char[] that it reads from and<br><br>* 一些Reader：<br>&nbsp; - LineNumberReader并不会附加行号，可以通过getLineNumber()方法取得行号<br>&nbsp; - CharArrayReader使用char[]来构造，从char[]中读取数据，参数int start和<br>&nbsp;&nbsp;&nbsp; length是可选的<br><br>* RandomAccessFile<br>&nbsp; - does not extend File or any type of stream.<br>&nbsp; - two ctors: ( File or String name, String mode="r","rw" )<br>&nbsp; - checks for read/write access at construction (unlike File).<br>&nbsp; - has read/write methods for primitives and strings (and a couple of<br>&nbsp;&nbsp;&nbsp; others).<br>&nbsp; - has a (long//mahachanged fm byte to long) file-pointer: seek(long),<br>&nbsp;&nbsp;&nbsp; long length().<br><br>* RandomAccessFile<br>&nbsp; - 并非继承自File或者任何类型的流<br>&nbsp; - 连个构造函数：( File or String name, String mode="r","rw" )<br>&nbsp; - 在初始化时检查文件的读写权限（不同于File）<br>&nbsp; - 对基本类型和字符串（还有其他的）有专门的读写方法<br>&nbsp; - 有一个long型的文件指针：seek(long), long length().<br><br>* FileDescriptor<br>&nbsp; - just a handle to a sink/source of bytes.<br>&nbsp; - only has two methods: sync() and valid()<br><br>* FileDescriptor<br>&nbsp; - 只是作为字节接收器/源的一个句柄<br>&nbsp; - 只有两个方法：sync() and valid()<br><br>* File<br>&nbsp; - represents an abstract file or dir pathname (file/dir doesnt have<br>&nbsp;&nbsp;&nbsp; to exist).<br>&nbsp; - 3 ctors: (File or String parent, String child) (String pathname)<br><br>* File<br>&nbsp; - 对抽象的文件或者目录的描述（文件/目录不一定存在）<br>&nbsp; - 三个构造函数：(File or String parent, String child) (String pathname)<br><br>------------------------------------------------------------------------<br><br>Collections<br><br><br>* The Collection interface is extended by Set and List (and SortedSet).<br>&nbsp; - a set contains no duplicates.<br>&nbsp; - a list is a sequence and can have duplicates.<br>* The Map interface does not extend Collection and is extended by<br>&nbsp; SortedMap.<br><br>* Set、List和SortedSet继承自Collection<br>&nbsp; - Set不包含重复的元素<br>&nbsp; - List是有序的，可以包含重复的元素<br>* Map并非Collection的子类，SortedMap继承自Map<br><br>* There are abstract classes for each of the main interfaces (Collection,<br>&nbsp; Set, List and Map) and implementations extend these.<br><br>* 主要的接口都有相对应的抽象类，具体的实现从抽象类继承<br><br>* Set implementations<br>&nbsp; - HashSet<br>&nbsp; - TreeSet (implements SortedSet)<br>* List implementations<br>&nbsp; - ArrayList<br>&nbsp; - LinkedList<br>* Map implementations<br>&nbsp; - HashMap<br>&nbsp; - TreeMap (implements SortedMap)<br><br>* 实现Set的类<br>&nbsp; - HashSet<br>&nbsp; - TreeSet（实现SortedSet）<br>* 实现List的类<br>&nbsp; - ArrayList<br>&nbsp; - LinkedList<br>* 实现Map的类<br>&nbsp; - HashMap<br>&nbsp; - TreeMap（实现SortedMap）<br><br>* Vector and Hashtable (extends Dictionary) are older collection classes.<br>&nbsp; - Vector has been made to extend AbstractList and is like a sync'd<br>&nbsp;&nbsp;&nbsp; ArrayList (maha:set)z.<br>&nbsp; - Hashtable still extends Dictionary but it implements Map.<br>&nbsp; - In contrast to other collection types, Vector and Hashtable are<br>&nbsp;&nbsp;&nbsp; synchronized.<br><br>* Vector和Hashtable（继承自Dictionary）是较老的集合类<br>&nbsp; - Vector继承自AbstractList，与同步的ArrayList相像<br>&nbsp; - Hashtable仍然继承自Dictionary但是实现了Map接口<br>&nbsp; - 与其他集合类型相比较，Vector和Hashtable是同步的<br><br>* There are Collections and Arrays classes to provide static methods for<br>&nbsp; general algorithms on collections and arrays.<br><br>* Collection和Array都提供了静态的方法处理集合和数组的运算<br><br>* Stack extends Vector<br>&nbsp; - it has methods push(Object), pop, peek and search(Object).<br>&nbsp; - Push is identical to addElement but also returns the added Object.<br>&nbsp; - The top of a stack is the last element in the vector (and has index 1 as<br>&nbsp;&nbsp;&nbsp; far as the search method is concerned).<br><br>* Stack继承自Vector<br>&nbsp; - 方法：push(Object)，pop，peek和search(Object)<br>&nbsp; - push方法与addElement的效果相似，同时返回刚刚添加过的对象<br>&nbsp; - 栈顶是Vector里面最后一个元素（search方法将返回1）<br><br><br>Math methods<br><br>Math的方法<br><br>* most act on and return double values<br>&nbsp;- note that floor(double), ceil(double) and rint(double) return doubles<br>&nbsp;&nbsp; not ints<br><br>* 大部分的方法都是对double类型数据作处理并返回double型的结果<br>&nbsp; - 注意floor(double)，ceil(double)和rint(double)返回的是double类型而不<br>&nbsp;&nbsp;&nbsp; 是int<br><br>* abs, max and min can take double, float, int or long arguments and the<br>&nbsp; return type matches the argument type.<br><br>* abs，max和min方法可以处理double，float，int或者long型的参数并且返回与<br>&nbsp; 参数类型一样的返回值<br><br>* There are three rounding methods:<br>&nbsp; - int round( float ); // note both are 32-bit<br>&nbsp; - long round( double ); // note both are 64-bit<br>&nbsp; - double rint( double );<br><br>* 三个取整方法：<br>&nbsp; - int round(float); // 注意两者都是32位<br>&nbsp; - long round(double); // 注意两者都是64位<br>&nbsp; - double rint(double);<br><br>* log returns natural log.<br><br>* log方法返回自然对数<br><br>* trig functions take double arguments in radians.<br><br>* trig函数的参数是double型的弧度<br><br>------------------------------------------------------------------------<br><br>------------------------------------------------------------------------<br><br>AWT<br><br><br>* Component is abstract ... Container is not abstract.<br><br>* Component是抽象的 &#8230; Container不是抽象的<br><br>* Checkbox has 5 ctors: no-arg + four with String as first arg and<br>&nbsp; combinations of boolean initialState and CheckboxGroup.<br><br>* Checkbox有五个构造函数：一个没有任何参数，其他四个都以字符串为第一个参<br>&nbsp; 数，以及boolean型的初始化状态、CheckboxGroup<br><br>* CheckboxMenuItem has nothing to do with Checkbox or CheckboxGroup.<br>&nbsp; - i think they generate both Item- and ActionEvents.<br><br>* CheckboxMenuItem与Checkbox和CheckboxGroup没有任何关系<br>&nbsp; - 我想他们都产生ItemEvent和ActionEvent<br><br>* Listeners:<br>&nbsp;- InputEvent (super for MouseEvent and KeyEvent) has a 'long getWhen()'<br>&nbsp;&nbsp; method.<br>&nbsp;- MouseEvent has 'int getX', 'int getY' and 'Point getPoint' methods.<br>&nbsp;- ActionEvent and ItemEvent are not ComponentEvents so have to use<br>&nbsp;&nbsp; getSource().<br>&nbsp;- MenuItems (inc. menus) can produce ActionEvents but not ItemEvents.<br>&nbsp;- ActionListener,Adjustment, ItemListener and TextListener only have<br>&nbsp;&nbsp; one method and therefore don't have Adapters.<br>&nbsp;- KeyListener: Pressed/Released/Typed<br>&nbsp;- FocusListener: Lost/Gained<br>&nbsp;- ComponentListener: Shown/Hidden&nbsp;&nbsp; Moved&nbsp;&nbsp;&nbsp;&nbsp; Resized<br>&nbsp;- ContainerListener: component- Added/Removed<br>&nbsp;- WindowListener: Opened/Closing/Closed<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Activated/Deactivated ... keyboard focus.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Iconifed/Deiconified<br>&nbsp;- MouseListener: Pressed/Released/Clicked<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Entered/Exited<br>&nbsp;- MouseMotionListener: Dragged/Moved<br><br>* 接收器：<br>&nbsp;- InputEvent（MouseEvent和KeyEvent的父类）有方法：long getWhen()<br>&nbsp;- MouseEvent的方法：int getX，int getY，Point getPoint<br>&nbsp;- ActionEvent和ItemEvent不属于ComponentEvent，只能使用getSource()<br>&nbsp;- MenuItem（例如菜单）产生的是ActionEvent而不是ItemEvent<br>&nbsp;- ActionListener，Adjustment，ItemListener和TextListener只定义了一个方法<br>&nbsp;&nbsp; ，所以不需要适配器<br>&nbsp;- KeyListener：键的按下/释放/敲击<br>&nbsp;- FocusListener: 焦点的失去/获得<br>&nbsp;- ComponentListener: 显示/隐藏，移动，改变大小<br>&nbsp;- ContainerListener: 添加/删除组件<br>&nbsp;- WindowListener: 打开/关闭中/已经关闭<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 激活/无效 ... 键盘焦点<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 最小化/恢复<br>&nbsp;- MouseListener: 键的按下/释放/点击<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 鼠标进入/退出<br>&nbsp;- MouseMotionListener: 拖动/移动<br><br>------------------------------------------------------------------------<br><br>Layout<br><br>布局<br><br>* BorderLayout is the default layout for Window/Frame/Dialog.<br>&nbsp; - add( component, BorderLayout.NORTH ) == add( "North", component )<br>&nbsp; - adding a component without an explicit position is identical to<br>&nbsp;&nbsp;&nbsp; adding a component at BorderLayout.CENTER.<br>&nbsp; - if more than one component is added to the same position, the most<br>&nbsp;&nbsp;&nbsp; recently added component is displayed there.<br>&nbsp; - north,south,east and west components only expand on one axis.<br><br>* BorderLayout是Window/Frame/Dialog的默 喜季 管理器<br>&nbsp; - add(component,BorderLayout.NORTH) == add("North",component)<br>&nbsp; - 如果不说明位置，组件将按默认的设置添加到CENTER的位置<br>&nbsp; - 如果超过一个组件添加到一个位置上，最后添加的将被显示<br>&nbsp; - north，south，east和west上的组件只在一个方向上延伸<br><br>* FlowLayout is the default layout for Panels (including Applets).<br>&nbsp; - if the panel is bigger than its components, they are centered<br>&nbsp;&nbsp;&nbsp; horizontally and at the top (ie. north position).<br><br>* Panel（包括Applet）的默 喜季 管理器是FlowLayout<br>&nbsp; - 如果panel比组件大，组件将被水平居中并置于顶端<br><br>* GridLayout with container larger than components expands to fill its<br>&nbsp; container provided that the number of components matches the<br>&nbsp; rows*columns.<br>&nbsp; - Empty rows are given space, while empty cols are not.<br>&nbsp; - If there aren't enough components, it will try to fill its rows first.<br><br>* 当GridLayout的容器比组件大时，组件将被扩充到填满整个容器，需要提供<br>&nbsp; rows*columns个组件<br>&nbsp; - 空行将被分配空间，但时空列不分配空间<br>&nbsp; - 如果组建的数目不够，首先尝试填充所有的行<br><br>* Ctors for BorderFlow- and GridLayout can take int hgap and vgap args.<br>&nbsp; - FlowLayout(int align, hgap, vgap)<br><br>* BorderFlow以及GridLayout的构造函数可以带参数hgap和vgap<br>&nbsp; - FlowLayout(int align, hgap, vgap)<br><br>* Be careful with nested layout questions ... eg Button to panel to frame,<br>&nbsp; the panel fills the whole frame, but the button will be its preferred size<br>&nbsp; at north position in the panel (and thus the frame).<br><br>* 对嵌套的布局管理器要小心 &#8230; 例如一个frame包含一个panel，panel包含一个<br>&nbsp; Button，panel填充整个frame，但是button仍然只有预定的大小，位于frame的<br>&nbsp; 北面<br><br>* GridBagLayout<br>&nbsp; - There are two ways to set the constraints for a component in a gbl:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; container.add( Component c, Object gbc ) or<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; gbl.setConstraints( Component c, GridBagConstraints gbc )<br>&nbsp; - weightx and weighty are doubles (0 to maxDouble, default 0) and determine<br>&nbsp;&nbsp;&nbsp; where extra width or height is added if a row or column is smaller than<br>&nbsp;&nbsp;&nbsp; the container.<br>&nbsp; - gridwidth and gridheight are ints (1 to maxInt) ... RELATIVE, REMAINDER.<br>&nbsp; - gridx and gridy are ints (0 to maxInt) ... RELATIVE<br>&nbsp; - RELATIVE can apply to gridx/gridy (=next) or<br>&nbsp;&nbsp;&nbsp; gridwidth/gridheight (=second last)<br><br>* GridBagLayout<br><br>&nbsp; - 有两种方法可以将一个组件使用constraints添加到GridBagLayout中去：<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; container.add(Component c,Object gbc) 或者<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; gbl.setConstraints(Component c,GridBagConstraints gbc)<br>&nbsp; - weightx和weighty是double类型（0到maxDouble，默认是0）的属性，它们决<br>&nbsp;&nbsp;&nbsp; 定额外的宽度或者高度是否添加到当前的行或者列<br>&nbsp; - gridwidth和gridheight是整型的数据类型（从1到maxInt） &#8230; 相对的，剩余<br>&nbsp;&nbsp;&nbsp; 的<br>&nbsp; - gridx和gridy是整型的（从0到maxInt） &#8230; 相对的<br>&nbsp; - &#8230;<br><br>* A Component added to a null layout won't display unless you set its<br>&nbsp; bounds ... this is the only place where a component can control its<br>&nbsp; parent's layout directly.<br><br>* 如果将一个组件添加到一个空的布局管理器中，只有设置组件的范围才能够显示<br><br>* Illegal arguments (eg. adding a container's parent to the container, adding<br>&nbsp; a window) get through the compiler but throw an exception at runtime.<br><br><br>* 不正确的参数（例如，添加一个容器的容器到自身，添加一个window）可以通过<br>&nbsp; 编译，但是将会在运行期间抛出异常<br><br>------------------------------------------------------------------------<br><br>------------------------------------------------------------------------<br><br>Miscellaneous<br><br>杂锦<br><br>* A class type's name is valid as an identifier, eg. int Boolean = 5;<br>* Modifiers:<br>&nbsp; - Automatic variable = local variable = variable declared in a method.<br>&nbsp; - Transient fields are not written out when a class is serialized.<br>&nbsp; - Transient and Volatile can only be applied to fields.<br>&nbsp; - Native can only be applied to methods.<br>&nbsp; - You can have a static synchronized method .. it is synchronized on the<br>&nbsp;&nbsp;&nbsp; class object.<br>&nbsp; - static transient is legal but doesn't effect anything.<br><br>* 一个类的名称是合法的标识名，例如：int Boolean = 5;<br>* 修饰符：<br>&nbsp; - &#8230;<br>&nbsp; - 当序列化一个类时，以transient修饰的字段不会写进数据流<br>&nbsp; - transient和volatile只能修饰字段<br>&nbsp; - native修饰符只能用于方法<br>&nbsp; - 可以有同步的静态方法，它使用类对象作为同步锁<br>&nbsp; - static transient是合法的，但是并不去起作用<br><br>* The right-hand-side of an assignment can be a reference to null.<br>&nbsp;&nbsp; - You can println a null reference (and add it to another string).<br>&nbsp;&nbsp; - What you can't do with a null reference is ... nullRef.aMethod();<br><br><br>* 赋值操作的右侧可以是null<br>&nbsp; - 可是打印空的引用（还可以赋给一个字符串变量）<br>&nbsp; - 你不能做的是 &#8230; nullRef.aMethod();<br><br>*<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ++,--,unary +,unary -,~,!,()<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *,/,%<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; +,-<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &gt;&gt;, &gt;&gt;&gt;, &lt;&lt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &gt;, &gt;=, &lt;, &lt;=, instanceof<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 6.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; == , !=<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 7.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 8.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ^<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 9.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 10&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;&amp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 11&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ||<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 12&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ? :<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 13&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; =,+=,-=,*=,/=,%=, &amp;=,^=,|=, &gt;&gt;= ,&lt;&lt;= ,&gt;&gt;&gt;=<br>* Order of Operation<br>&nbsp; - arithmetic before &amp;^|<br>&nbsp; - &amp; then ^ then |<br><br>* 运算顺序<br>&nbsp; - 先数学运算，后&amp;^|<br>&nbsp; - 先&amp;然后^最后|<br><br>* Garbage Collection<br>&nbsp; - unreachable objects can become reachable (if their finalize method<br>&nbsp;&nbsp;&nbsp; causes another object to have a reference to them) .. but i think<br>&nbsp;&nbsp;&nbsp; finalize if guaranteed to not run again.<br>&nbsp; - objects referenced by block-level variables are probably not available<br>&nbsp;&nbsp;&nbsp; for garbage collection until their enclosing method's scope is exited.<br><br>* 内存回收<br>&nbsp; - &#8230;<br>&nbsp; - &#8230;<br><br>* The compiler never object to creating a local instance of the<br>&nbsp; the class being constructed in its constructor. If the call produces<br>&nbsp; an infinite loop, a runtime error will occur.<br><br>* 编译器从不反对在构造函数中创建一个本类的实例，但是如果这导致无限的循环<br>，一个运行期间的错误将会被抛出<br><br>* Labelled break and continue statements:<br>&nbsp; - The label referred to by a labelled break statement is attached to<br>&nbsp;&nbsp;&nbsp; a statement block, which could be a loop or switch but doesnt have<br>&nbsp;&nbsp;&nbsp; to be.<br>&nbsp; - The label referred to by a labelled continue statement must be<br>&nbsp;&nbsp;&nbsp; attached to a loop.(A "continue" statement must be enclosed in a "while",<br>&nbsp;&nbsp;&nbsp; "do" or "for" statement.)<br><br>* 带标号的break和continue声明<br>&nbsp; - 带标号的break可用于标识循环和开关语句，但不是必须的<br>&nbsp; - 带标号的continue只能用于循环语句（continue必须出现在while、do或者<br>&nbsp;&nbsp;&nbsp; for子句中）<br><br>------------------------------------------------------------------------<br><br>------------------------------------------------------------------------<br><br>Things to look out for<br><br>*** Read the answers before going through code samples.<br><br><br>****** WHEN YOU FINISH THE EXAM GO BACK AND CHECK FOR NON-STATIC<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; METHODS/VARS FROM MAIN AND OTHER STATIC METHODS<br><br>* if (...)<br>&nbsp;&nbsp;&nbsp; statement1;<br>&nbsp;&nbsp;&nbsp; statement2; //...always executed<br><br>* Beware of an otherwise legal override having a more restrictive<br>&nbsp; access modifier.<br><br><br>* Beware of missing return statements.<br><br>* Look for static modifiers and make sure they don't contain refs to<br>&nbsp; instance vars.<br><br>* Beware of standard methods (eg. main, paint, run) with the wrong<br>&nbsp; args or return type.<br><br>* With array declarations, look out for "int intArray[5] = ..."<br><br>* Beware of adding a primitive to a Vector.<br>&nbsp; - more generally, you can't use a primitive where an Object is<br>&nbsp;&nbsp;&nbsp; required (eg. the equals method).<br><br>* System.out.println( aReferenceToNull ); // is fine<br><br>* Beware of local vars from a try block used in its catch block<br>&nbsp; (out of scope).<br><br>需要留意的<br><br>*** 先读答案在看代码段<br><br>****** 寻找在main中调用的非静态的变量和方法<br><br>****** 当你完成考试时，回头检查main和其他静态方法中的非静态变量和方法调用<br><br>* if (...)<br>&nbsp;&nbsp;&nbsp; statement1;<br>&nbsp;&nbsp;&nbsp; statement2; //...总是运行<br><br><br>* 留意没有返回值的方法<br><br>* 保证静态代码不能引用类实例变量<br><br><br>* 留意标准方法（例如，main，print和run）的不正确的参数类型和返回值<br><br>* 数组声明，留意形如"int intArray[5] = ..."的语句<br><br>* 小心不要将基本类型添加到Vector中<br>&nbsp; - 更普遍的情况，当需要用Object的时候不要用基本类型（例如equals方法）<br><br>* System.out.println( aReferenceToNull ); // 代码将运行得很好<br><br>* 小心不要在catch中使用try中定义的局部变量（超出范围）<br><br>--<br>&nbsp; -= HOVER =-<br>
<img src ="http://www.blogjava.net/gm_jing/aggbug/124349.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/gm_jing/" target="_blank">黎夕</a> 2007-06-14 16:52 <a href="http://www.blogjava.net/gm_jing/articles/124349.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>大话编码</title><link>http://www.blogjava.net/gm_jing/articles/107870.html</link><dc:creator>黎夕</dc:creator><author>黎夕</author><pubDate>Mon, 02 Apr 2007 01:30:00 GMT</pubDate><guid>http://www.blogjava.net/gm_jing/articles/107870.html</guid><wfw:comment>http://www.blogjava.net/gm_jing/comments/107870.html</wfw:comment><comments>http://www.blogjava.net/gm_jing/articles/107870.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/gm_jing/comments/commentRss/107870.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/gm_jing/services/trackbacks/107870.html</trackback:ping><description><![CDATA[<h1 class=xspace-title>从 ASCII 到 UTF-8 : 大话编码（无心收获却获益颇多呀！）</h1>
<p class=xspace-smalltxt>2006-01-19 10:16:59 </p>
<div class=xspace-itemmessage id=xspace-showmessage>从 ASCII 到 UTF-8 : 大话编码<br>话说当年,老美搞出了ASCII编码,用8个bit表示一个字符,<br>解决了计算机存储人类语言的问题.<br><br>要说当时那帮人真是有点小家子气,只顾解决英语,数字和一些简单符号<br>的存储问题,压根就没想过中文啊,拉丁文啊,藏文啊啥的怎么存储的问题.<br><br>随着计算机越来越普及,这个问题也就越来越尖锐了,总不能让全世界人民<br>都使用英语吧?于是,有这么两个组织,一个曰ISO,一个曰unicode组织,就开始<br>想办法了...<br><br>unicode想的办法比较简单,不是1个byte不够嘛?咱用两个byte存,大概够了吧?<br>这就是unicode 1.0 的实现.<br><br>要说人家ISO就是大气,也可能决策者们没过过几十K内存的苦日子,<br>大笔一挥,不就是1个byte不够吗?用4个byte够了吧?再用个几百年也够了吧?<br>这就是 ucs-4 的雏型.<br><br>随着一些稀奇古怪的文字需要并入unicode,unicode的决策者有点冒汗了,<br>咱有这么多稀奇古怪的字母呢? 要不再加点, 用 2byte + 4 bit 来存吧..<br>那4bit做为头,这下就又能表示很多奇怪的文字了....<br>这就是 unicode 2.0 的雏型<br><br>现在有了两套风格迥异的编码方式, 到底该用那个呢?<br>于是 unicode 组织 和 ISO 组织 达成了协议,就是你中有我,我中有你,<br>ucs-4 尽管有 32 bit 编码空间,只用 20 bit ,和 unicode 保持统一,unicode不作修改<br>这就是 ucs-4 和 unicode 2.0 了,狼狈为奸的结果 :)<br><br>后来在 2000 年 8 月 ,unicode 的工作人员为了显得自己不是吃白食的,<br>就小小修改了一下 unicode 2.0 的文档,做为unicode 3.0 发布了.没加一个新字符啊!!!!!!<br>(实际上, 有大约12种当前语言 和 数十种古代语言,如雅玛语,古希腊B类线形文字,<br>古波斯碶型文字还没有得到支持)<br><br><br>至此,编码方案算是统一了,接下来,咬牙切齿骂街的就变成程序员们了.<br>程序员的愤怒是有道理的,比如输入一篇100字的英文文章,如果用ASCII<br>编码,仅需要 100 byte ,而如果出现了哪怕一个古怪的字符而不得不用ucs-4 ,<br>就需要 400 byte ! 这对早期的程序员来说简直是灾难...就算对带宽有限得今天,<br>这也是个很重要得问题..<br><br>于是IETF推出了 UTF- 8 和 UTF-16 两种解决方案 (utf32用的太少,忽略)<br><br>utf 8 实际上是最聪明的编码方式,简单说,规则有三条<br>(1) ASCII 编码不变, 用 1 个byte 表示<br>(2) 一个 byte 不够 ,就用两个 byte<br>(3)两个还不够,就用三个byte,什么?还不够?<br>不可能,3个byte已经超过unicode 的表示极限了..你是外星人吗?<br><br>它带来了如下两大好处:<br>(1)平台无关性,windows下用UTF-8写的小说,别人在unix下照样能看..<br>(2)有标记位,一个字读不出来,不影响其他字.<br><br>utf 16 则是给笨一点的程序员准备的,简单说,规则有两条<br>(1) unicode 1.0 中的字符完全照搬 ,用2个byte<br>(2) unicode 2.0 继续照搬, &nbsp; 需要用 20 bit 表示的字符,用 2byte + 4bit 处理.<br><br>这下带来的可不是一点两点的坏处,<br>(1)由于是变长,且不按计算机字长(8bit)来变长,所以用utf16编码的<br>东东的解码就和CPU,操作系统的处理方式相关了,不利于交流<br>(2)一些本来具有特殊意义的字符无法被计算机正常处理<br>(3)以上两条就可以判它死刑了...其他害处不一一列举,<br><br>但是utf16最省空间倒是真的.毕竟是紧凑编码的,没有大段大段的000000000出现....<br><br>实际上,IETF比较希望UTF-8成为事实标准(RFC2279),<br>而UTF-16,也就是卖ISO和unicode个面子,实现一下而已(RFC2781)<br><br><br>而现实中,由于UTF-8的优异性能,得到了广泛的认可和使用.<br>比如现在大红大紫的XML,在XML1.0第二版规范中明确指出,<br>当用户没有指定XML文档的 encoding 属性的时候,自动使用<br>UTF-8编解码<br>(尽管我强烈建议大家注明 encoding 属性)<br><br><br>OK,大话结束!各位可以把西红柿,鸡蛋啥的扔上来了 :)<br></div>
<img src ="http://www.blogjava.net/gm_jing/aggbug/107870.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/gm_jing/" target="_blank">黎夕</a> 2007-04-02 09:30 <a href="http://www.blogjava.net/gm_jing/articles/107870.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>进程与线程</title><link>http://www.blogjava.net/gm_jing/articles/105275.html</link><dc:creator>黎夕</dc:creator><author>黎夕</author><pubDate>Wed, 21 Mar 2007 07:13:00 GMT</pubDate><guid>http://www.blogjava.net/gm_jing/articles/105275.html</guid><wfw:comment>http://www.blogjava.net/gm_jing/comments/105275.html</wfw:comment><comments>http://www.blogjava.net/gm_jing/articles/105275.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/gm_jing/comments/commentRss/105275.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/gm_jing/services/trackbacks/105275.html</trackback:ping><description><![CDATA[<p>进程：可并发执行的程序在一个数据集合上的运行过程。</p>
<p>线程：比进程更小的能独立运行的基本单位。&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;<br>&nbsp; 一个进程通常对应于一个程序（但程序是一个静态的概念，进程是动态的）。而一个进程可以由多个不同的线程做成！&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;进程为一个数据结构及能在其上进行的一次操作，它有两个基本特征，一个是进程是可用有资源的独立单位，第二个是进程同时又是一个可以独立调度和分派的基本单位，这两个基本属性使之能够独立运行，也能够并发运行。但是在并发运行的时候，系统还需要执行一系列操作：1、需要创建进程，并为之分配其所必需的资源。2、撤销进程，对资源进行回收。3、进程切换，它需要保留当前进程的CPU环境和设置新选中进程的CPU环境，为此需要花费不少处理时间。正因为进程拥有资源，所以在并发执行进程的时候，在创建、撤销和切换种，系统需要付出较大的开销，因此，系统中设置的进程不能太多，进程切换的频率也不能过高，这就限制了并发程度的提高。&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;线程是进程中的一个实体，它的基本思想是将程序的执行和资源分开，只拥有一点必不可少的资源。一个进程可用有多个线程，但它可以和同属于同一进程的其他线程共享进程所拥有的所有的资源，同一进程中的线程之间可以并发执行。这样的话，并发程度可以获得显著的提高。线程也具有许多进程所具有的特征，因此被称为轻型进程。<br><br><br><br>---------------------------------------------------------------------------------------------------<br>Class Test extends Thread{<br>&nbsp;&nbsp;&nbsp;&nbsp;private Thread t1 = new Thread() {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void run() {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ...<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;private Thread t2 = new Thread() {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void run() {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ...<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; }&nbsp;<br><br>&nbsp; public void start() {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; t1.start();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; t2.start();<br>&nbsp; }<br>&nbsp; public void run() {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while(true) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;}<br><br><br>}<br><br><font color=#ff1493><strong><font color=#000000>当对象Test的一个Thread进入运行时候，其他Thread处于等待状态</font><font color=#000000>，</font>所以锁对象（Test），不是锁Thread（t1,t2）</strong><br></font><br><br><br>&nbsp;&nbsp;&nbsp; sleep()方法，是Thread的方法，是使线程停止一段时间的方法。在sleep&nbsp;&nbsp; 时间间隔期满后，线程不一定立即恢复执行。这是因为在那个时刻，其它线程可能正在运行而且没有被调度为放弃执行，除非(a)&#8220;醒来&#8221;的线程具有更高的优先级，(b)正在运行的线程因为其它原因而阻塞。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;wait()方法，是Object的方法，是线程交互时，如果线程对一个同步对象x&nbsp;&nbsp; 发出一个wait()调用，该线程会暂停执行，被调对象进入等待状态，直到被唤醒或等待时间到。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br></p>
<p>wait()/notify()：调用任意对象的 wait() 方法导致线程阻塞，并且该对象上的锁被释放。而调用 任意对象的notify()方法则导致因调用该对象的 wait() 方法而阻塞的线程中随机选择的一个解除阻塞（但要等到获得锁后才真正可执行）。</p>
<p><font color=#cc0000><br>synchronized和wait()、notify()的关系</font>:</p>
<p>1.有synchronized的地方不一定有wait,notify</p>
<p>2.有wait,notify的地方必有synchronized.这是因为wait和notify不是属于线程类，而是每一个对象都具有的方法，而且，这两个方法都和对象锁有关，有锁的地方，必有synchronized。<br><br><br><br></p>
<hr>
<br>一个程序调用fork函数，系统为一个新的进程准备了数据段,堆栈段,代码段，<br>首先,新进程与旧进程使用同一个代码段，因为它们的程序是相同的，<br>对于数据段和堆栈段，系统则复制一份给新的进程，<br>这样，父进程的所有数据都可以留给子进程，但是，子进程一旦开始运行，<br>虽然它继承了父进程的一切数据，但实际上数据却已经分开，<br>相互之间不再有影响了，也就是说，它们之间不再共享任何数据了。<br><font color=#ff1493>两个进程要共享数据的话，只能使用共享内存与消息队列等来操作。</font><br><br>如果数据段和堆栈都很大，一次fork就要复制一次，那么fork的开销岂不是很大？<br>其实一般CPU都是以&#8220;页&#8221;为单位分配空间的，<br>fork函数复制这两个段，只是&#8220;逻辑&#8221;上的，并非&#8220;物理&#8221;上的，也就是说，<br>实际执行fork时，物理空间上两个进程的绝大部分数据段和堆栈段都还是共享着的，<br>只有一个进程写了某个数据时，这时两个进程之间的数据才有了区别，<br>系统只将有区别的&#8220;页&#8221;从物理上也分开。系统在空间上的开销就可以达到最小。<br><br>要方便的使用共享变量，最好使用线程方式，但是需要考虑变量的保护问题，而<br>使用进程的共享内存与消息队列，就不需要用户来保护变量，因为它们已经提供了<br>保护。 
<img src ="http://www.blogjava.net/gm_jing/aggbug/105275.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/gm_jing/" target="_blank">黎夕</a> 2007-03-21 15:13 <a href="http://www.blogjava.net/gm_jing/articles/105275.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>对象的序列化</title><link>http://www.blogjava.net/gm_jing/articles/105264.html</link><dc:creator>黎夕</dc:creator><author>黎夕</author><pubDate>Wed, 21 Mar 2007 06:43:00 GMT</pubDate><guid>http://www.blogjava.net/gm_jing/articles/105264.html</guid><wfw:comment>http://www.blogjava.net/gm_jing/comments/105264.html</wfw:comment><comments>http://www.blogjava.net/gm_jing/articles/105264.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/gm_jing/comments/commentRss/105264.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/gm_jing/services/trackbacks/105264.html</trackback:ping><description><![CDATA[
		<strong>
				<br />对象的序列化用途：<br /></strong>　　Java 序列化技术可以使你将一个对象的状态写入一个Byte 流里，并且可以从其它地方<br />把该Byte 流里的数据读出来。重新构造一个相同的对象。这种机制允许你将对象通过网络<br />进行传播，并可以随时把对象持久化到数据库、文件等系统里。Java的序列化机制是RMI、<br />EJB、JNNI等技术的技术基础。<br /><br /><br /><br /><br /><strong>序列化的特点：<br /></strong>（1）如果某个类能够被序列化，其子类也可以被序列化。<br />（2）声明为static和transient类型的成员数据不能被序列化。因为static代表类的状态，transient代表对象的临时数据。<br />（3）相关的类和接口：在java.io包中提供如下涉及对象的序列化的类与接口ObjectOutput接口、ObjectOutputStream类、ObjectInput接口、ObjectInputStream类<br /><br /><br /><p>private void writeObject(java.io.ObjectOutputStream out)<br />     throws IOException<br /> private void readObject(java.io.ObjectInputStream in)<br />     throws IOException, ClassNotFoundException;<br /><br /><br /><br /><br /><br /></p><hr /><h2 class="diaryTitle">如何正确的使用Java序列化技术- -</h2><p class="diaryTitle">[转]http://blog.csdn.net/yethyeth/archive/2006/05/21/747933.aspx</p><p>http://publishblog.blogchina.com/blog/tb.b?diaryID=279864                                        </p><p> </p><p>摘要：本文比较全面的介绍了Java 序列化技术方方面面的知识，从序列化技术的基础谈起，<br />介绍了Java 序列化技术的机制和序列化技术的原理。并在随后的部分详细探讨了序列化的<br />高级主题－如何精确的控制序列化机制。通过阅读该文章，你可以了解如何使用Java 序列<br />化机制的方式和正确使用的方法，避免实际编程中对该技术的误用。并能掌握如何高效使用<br />该技术来完成特殊的功能。</p><p>关键字：序列化（Serialize）、反序列化（DeSerialize）、类加载（ClassLoad）、指纹技术<br />（fingerprint）<br /><br /></p><p><br /></p><p>1 Java 序列化技术概述<br />Java 序列化技术可以使你将一个对象的状态写入一个Byte 流里，并且可以从其它地方<br />把该Byte 流里的数据读出来。重新构造一个相同的对象。这种机制允许你将对象通过网络<br />进行传播，并可以随时把对象持久化到数据库、文件等系统里。Java的序列化机制是RMI、<br />EJB、JNNI等技术的技术基础。<br />1.1 序列化技术基础<br />并非所有的Java 类都可以序列化，为了使你指定的类可以实现序列化，你必须使该类<br />实现如下接口：<br />java.io.Serializable<br />需要注意的是，该接口什么方法也没有。实现该类只是简单的标记你的类准备支持序列<br />化功能。我们来看如下的代码：<br />/**<br />* 抽象基本类，完成一些基本的定义<br />*/<br />public abstract class Humanoid<br />{<br />protected int noOfHeads;<br />private static int totalHeads;<br />public Humanoid()<br />{<br />this(1);<br />}<br />public Humanoid(int noOfHeads)<br />{<br />如何正确的使用Java序列化技术 技术研究系列<br />if (noOfHeads &gt; 10)<br />throw new Error("Be serious. More than 10 heads?!");<br />this.noOfHeads = noOfHeads;<br />synchronized (Humanoid.class)<br />{<br />totalHeads += noOfHeads;<br />}<br />}<br />public int getHeadCount()<br />{<br />return totalHeads;<br />}<br />}<br />该类的一个子类如下：<br />/**<br />* Humanoid的实现类，实现了序列化接口<br />*/<br />import java.io.*;<br />public class Person extends Humanoid<br />implements java.io.Serializable<br />{<br />private String lastName;<br />private String firstName;<br />private transient Thread workerThread;<br />private static int population;<br />public Person(String lastName, String firstName)<br />{<br />this.lastName = lastName;<br />this.firstName = firstName;<br />synchronized (Person.class)<br />{<br />population++;<br />}<br />}<br />public String toString()<br />{<br />return "Person " + firstName + " " + lastName;<br />}<br />static synchronized public int getPopulation()<br />{<br />return population;<br />}<br />}<br />1.2 对象的序列化及反序列化<br />上面的类Person 类实现了Serializable 接口，因此是可以序列化的。我们如果要把一个<br />可以序列化的对象序列化到文件里或者数据库里，需要下面的类的支持：<br />java.io.ObjectOutputStream<br />如何正确的使用Java序列化技术 技术研究系列<br />下面的代码负责完成Person类的序列化操作：<br />/**<br />* Person的序列化类，通过该类把Person写入文件系统里。<br />*/<br />import java.io.*;<br />public class WriteInstance<br />{<br />public static void main(String [] args) throws Exception<br />{<br />if (args.length != 1)<br />{<br />System.out.println("usage: java WriteInstance file");<br />System.exit(-1);<br />}<br />FileOutputStream fos = new FileOutputStream(args[0]);<br />ObjectOutputStream oos = new ObjectOutputStream(fos);<br />Person p = new Person("gaoyanbing", "haiger");<br />oos.writeObject(p);<br />}<br />}<br />如果我们要序列化的类其实是不能序列化的，则对其进行序列化时会抛出下面的异常：<br />java.io.NotSerializableException<br />当我们把Person 序列化到一个文件里以后，如果需要从文件中恢复Person 这个对象，<br />我们需要借助如下的类：<br />java.io.ObjectInputStream<br />从文件里把Person类反序列化的代码实现如下：<br />/**<br />* Person的反序列化类，通过该类从文件系统中读出序列化的数据，并构造一个<br />* Person对象。<br />*/<br />import java.io.*;<br />public class ReadInstance<br />{<br />public static void main(String [] args) throws Exception<br />{<br />if (args.length != 1)<br />{<br />System.out.println("usage: java ReadInstance filename");<br />System.exit(-1);<br />}<br />FileInputStream fis = new FileInputStream(args[0]);<br />ObjectInputStream ois = new ObjectInputStream(fis);<br />Object o = ois.readObject();<br />如何正确的使用Java序列化技术 技术研究系列<br />System.out.println("read object " + o);<br />}<br />}<br />1.3 序列化对类的处理原则<br />并不是一个实现了序列化接口的类的所有字段及属性都是可以序列化的。我们分为以下<br />几个部分来说明：<br />u 如果该类有父类，则分两种情况来考虑，如果该父类已经实现了可序列化接口。则<br />其父类的相应字段及属性的处理和该类相同；如果该类的父类没有实现可序列化接<br />口，则该类的父类所有的字段属性将不会序列化。<br />u 如果该类的某个属性标识为static类型的，则该属性不能序列化；<br />u 如果该类的某个属性采用transient关键字标识，则该属性不能序列化；<br />需要注意的是，在我们标注一个类可以序列化的时候，其以下属性应该设置为transient<br />来避免序列化：<br />u 线程相关的属性；<br />u 需要访问IO、本地资源、网络资源等的属性；<br />u 没有实现可序列化接口的属性；（注：如果一个属性没有实现可序列化，而我们又<br />没有将其用transient 标识， 则在对象序列化的时候， 会抛出<br />java.io.NotSerializableException 异常）。<br />1.4 构造函数和序列化<br />对于父类的处理，如果父类没有实现序列化接口，则其必须有默认的构造函数（即没有<br />参数的构造函数）。为什么要这样规定呢？我们来看实际的例子。仍然采用上面的Humanoid<br />和Person 类。我们在其构造函数里分别加上输出语句：<br />/**<br />* 抽象基本类，完成一些基本的定义<br />*/<br />public abstract class Humanoid<br />{<br />protected int noOfHeads;<br />private static int totalHeads;<br />public Humanoid()<br />{<br />this(1);<br />System.out.println("Human's default constructor is invoked");<br />}<br />public Humanoid(int noOfHeads)<br />{<br />if (noOfHeads &gt; 10)<br />throw new Error("Be serious. More than 10 heads?!");<br />如何正确的使用Java序列化技术 技术研究系列<br />this.noOfHeads = noOfHeads;<br />synchronized (Humanoid.class)<br />{<br />totalHeads += noOfHeads;<br />}<br />}<br />public int getHeadCount()<br />{<br />return totalHeads;<br />}<br />}<br />/**<br />* Humanoid的实现类，实现了序列化接口<br />*/<br />import java.io.*;<br />public class Person extends Humanoid<br />implements java.io.Serializable<br />{<br />private String lastName;<br />private String firstName;<br />private transient Thread workerThread;<br />private static int population;<br />public Person(String lastName, String firstName)<br />{<br />this.lastName = lastName;<br />this.firstName = firstName;<br />synchronized (Person.class)<br />{<br />population++;<br />}<br />System.out.println("Person's constructor is invoked");<br />}<br />public String toString()<br />{<br />return "Person " + firstName + " " + lastName;<br />}<br />static synchronized public int getPopulation()<br />{<br />return population;<br />}<br />}<br />在命令行运行其序列化程序和反序列化程序的结果为：<br />如何正确的使用Java序列化技术 技术研究系列<br />可以看到，在从流中读出数据构造Person对象的时候，Person 的父类Humanoid的默认<br />构造函数被调用了。当然，这点完全不用担心，如果你没有给父类一个默认构造函数，则编<br />译的时候就会报错。<br />这里，我们把父类Humanoid做如下的修改：<br />/**<br />* 抽象基本类，完成一些基本的定义<br />*/<br />public class Humanoid implements java.io.Serializable<br />{<br />protected int noOfHeads;<br />private static int totalHeads;<br />public Humanoid()<br />{<br />this(1);<br />System.out.println("Human's default constructor is invoked");<br />}<br />public Humanoid(int noOfHeads)<br />{<br />if (noOfHeads &gt; 10)<br />throw new Error("Be serious. More than 10 heads?!");<br />this.noOfHeads = noOfHeads;<br />synchronized (Humanoid.class)<br />{<br />totalHeads += noOfHeads;<br />}<br />}<br />public int getHeadCount()<br />{<br />return totalHeads;<br />}<br />}<br />我们把父类标记为可以序列化， 再来看运行的结果：<br />如何正确的使用Java序列化技术 技术研究系列<br />可以看到，在反序列化的时候，如果父类也是可序列化的话，则其默认构造函数也不会<br />调用。这是为什么呢？<br />这是因为Java 对序列化的对象进行反序列化的时候，直接从流里获取其对象数据来生<br />成一个对象实例，而不是通过其构造函数来完成，毕竟我们的可序列化的类可能有多个构造<br />函数，如果我们的可序列化的类没有默认的构造函数，反序列化机制并不知道要调用哪个构<br />造函数才是正确的。<br />1.5 序列化带来的问题<br />我们可以看到上面的例子，在Person 类里，其字段population 很明显是想跟踪在一个<br />JVM里Person类有多少实例，这个字段在其构造函数里完成赋值，当我们在同一个JVM 里<br />序列化Person 并反序列化时，因为反序列化的时候Person 的构造函数并没有被调用，所以<br />这种机制并不能保证正确获取Person在一个JVM的实例个数，在后面的部分我们将要详细<br />探讨这个问题及给出比较好的解决方案。<br />2 控制序列化技术<br />2.1 使用readObject 和writeObject方法<br />由于我们对于对象的序列化是采用如下的类来实现具体的序列化过程：<br />java.io.ObjectOutputStream<br />而该类主要是通过其writeObject 方法来实现对象的序列化过程，改类同时也提供了一<br />种机制来实现用户自定义writeObject 的功能。方法就是在我们的需要序列化的类里实现一<br />如何正确的使用Java序列化技术 技术研究系列<br />个writeObject方法，这个方法在ObjectOutputStream序列化该对象的时候就会自动的回调它。<br />从而完成我们自定义的序列化功能。<br />同样的，反序列化的类也实现了同样的回调机制，我们通过扩展其readObject来实现自<br />定义的反序列化机制。<br />通过这种灵活的回调机制就解决了上面提出的序列化带来的问题，针对上面的Person<br />的问题，我们编写如下的readObject方法就可以彻底避免population计数不准确的问题：<br />private void readObject(ObjectInputStream ois)<br />throws IOException, ClassNotFoundException<br />{<br />ois.defaultReadObject();<br />synchronized (Person.class)<br />{<br />population++;<br />}<br />System.out.println("Adjusting population in readObject");<br />}<br />2.2 序列化过程的类版本控制<br />本节讨论以下问题：<br />u 在对象反序列化过程中如何寻找对象的类；<br />u 如果序列化和反序列化两边的类不是同一个版本，如何控制；<br />2.2.1 序列化类的寻找机制<br />在对象的反序列化过程中，是一定需要被反序列化的类能被ClassLoader 找到的，否则<br />在反序列化过程中就会抛出java.lang.ClassNotFoundException 异常。关于ClassLoader 如何<br />寻找类，这里就不多说了，可以参考我的另一篇讨论ClassLoader 的文章《在非管理环境下<br />如何实现热部署》。我们这里只是关心该序列化对象对应的类是被哪个ClassLoader 给Load<br />的。为此，我们修改上面的<br />/**<br />* 修改后的反序列化类<br />*/<br />import java.io.*;<br />public class ReadInstance<br />{<br />public void readPerson(String filename)<br />{<br />如何正确的使用Java序列化技术 技术研究系列<br />try{<br />FileInputStream fis = new FileInputStream(filename);<br />ObjectInputStream ois = new ObjectInputStream(fis);<br />Object o = ois.readObject();<br />System.out.println("read object " + o);<br />System.out.println(this.getClass().getClassLoader());<br />Person person = (Person)o;<br />System.out.println(person.getClass().getClassLoader());<br />}catch(java.io.IOException ie)<br />{<br />ie.printStackTrace();<br />}catch(ClassNotFoundException ce)<br />{<br />ce.printStackTrace();<br />}<br />}<br />public static void main(String [] args) throws Exception<br />{<br />if (args.length != 1)<br />{<br />System.out.println("usage: java ReadInstance filename");<br />System.exit(-1);<br />}<br />ReadInstance readInstance = new ReadInstance();<br />readInstance.readPerson(args[0]);<br />}<br />我们主要通过背景为黄色的两行代码查看其类加载器，运行结果如下：<br />由此可以看出，序列化类的类加载器正式其反序列化实现类的类加载器。这样的话我们<br />就可以通过使最新的Person 类的版本发布为只有该反序列化器的ClassLoader可见。而较旧<br />的版本则不为该ClassLoader 可见的方法来避免在反序列化过程中类的多重版本的问题。当<br />然，下面就类的版本问题我们还要做专门的探讨。<br />如何正确的使用Java序列化技术 技术研究系列<br />2.2.2 序列化类多重版本的控制<br />如果在反序列化的JVM 里出现了该类的不同时期的版本，那么反序列化机制是如何处<br />理的呢？<br />为了避免这种问题，Java的序列化机制提供了一种指纹技术，不同的类带有不同版本的<br />指纹信息，通过其指纹就可以辨别出当前JVM 里的类是不是和将要反序列化后的对象对应<br />的类是相同的版本。该指纹实现为一个64bit的long 类型。通过安全的Hash算法（SHA-1）<br />来将序列化的类的基本信息（包括类名称、类的编辑者、类的父接口及各种属性等信息）处<br />理为该64bit的指纹。我们可以通过JDK自带的命令serialver来打印某个可序列化类的指纹<br />信息。如下：<br />当我们的两边的类版本不一致的时候，反序列化就会报错：<br />如何正确的使用Java序列化技术 技术研究系列<br />解决之道：从上面的输出可以看出，该指纹是通过如下的内部变量来提供的：<br />private static final long serialVersionUID;<br />如果我们在类里提供对该属性的控制，就可以实现对类的序列化指纹的自定义控制。为<br />此，我们在Person 类里定义该变量：<br />private static final long serialVersionUID= 6921661392987334380L;<br />则当我们修改了Person 类，发布不同的版本到反序列化端的JVM，也不会有版本冲突<br />的问题了。需要注意的是，serialVersionUID 的值是需要通过serialver 命令来取得。而不能<br />自己随便设置，否则可能有重合的。<br />需要注意的是，手动设置serialVersionUID 有时候会带来一些问题，比如我们可能对类<br />做了关键性的更改。引起两边类的版本产生实质性的不兼容。为了避免这种失败，我们需要<br />知道什么样的更改会引起实质性的不兼容，下面的表格列出了会引起实质性不兼容和可以忽<br />略（兼容）的更改：<br />更改类型 例子<br />兼容的更改<br />u 添加属性（Adding fields）<br />u 添加/删除类（adding/removing classes）<br />u 添加/删除writeObject/readObject方法（adding/removing<br />writeObject/readObject）<br />u 添加序列化标志（adding Serializable）<br />u 改变访问修改者(changing access modifier)<br />u 删除静态/不可序列化属性（removing static/transient from<br />a field）<br />不兼容的更改<br />u 删除属性（Deleting fields）<br />u 在一个继承或者实现层次里删除类（removing classes in a<br />hierarchy）<br />u 添加静态/不可序列化字段（adding static/transient to a<br />field）<br />u 修改简单变量类型（changing type of a primitive）<br />u switching between Serializable or Externalizable<br />u 删除序列化标志（removing Serializable/Externalizable）<br />u 改变readObject/writeObject对默认属性值的控制（changing<br />whether readObject/writeObject handles default field<br />data）<br />u adding writeReplace or readResolve that produces<br />objects incompatible with older versions<br />另外，从Java 的序列化规范里并没有指出当我们对类做了实质性的不兼容修改后反序<br />列化会有什么后果。并不是所有的不兼容修改都会引起反序列化的失败。比如，如果我们删<br />除了一个属性，则在反序列化的时候，反序列化机制只是简单的将该属性的数据丢弃。从<br />JDK 的参考里，我们可以得到一些不兼容的修改引起的后果如下表：<br />如何正确的使用Java序列化技术 技术研究系列<br />不兼容的修改 引起的反序列化结果<br />删除属性<br />（Deleting a field） Silently ignored<br />在一个继承或者实现层次里删除类<br />（Moving classes in inheritance<br />hierarchy）<br />Exception<br />添加静态/不可序列化属性<br />（Adding static/transient）<br />Silently ignored<br />修改基本属性类型<br />（Changing primitive type）<br />Exception<br />改变对默认属性值的使用<br />（Changing use of default field data）<br />Exception<br />在序列化和非序列化及内外部类之间切换<br />（Switching Serializable and<br />Externalizable）<br />Exception<br />删除Serializable或者Externalizable标志<br />（Removing Serializable or<br />Externalizable）<br />Exception<br />返回不兼容的类<br />（Returning incompatible class）<br />Depends on incompatibility<br />2.3 显示的控制对属性的序列化过程<br />在默认的Java 序列化机制里，有关对象属性到byte 流里的属性的对应映射关系都是自<br />动而透明的完成的。在序列化的时候，对象的属性的名称默认作为byte 流里的名称。当该<br />对象反序列化的时候，就是根据byte 流里的名称来对应映射到新生成的对象的属性里去的。<br />举个例子来说。在我们的一个Person对象序列化的时候，Person的一个属性firstName就作<br />为byte 流里该属性默认的名称。当该Person 对象反序列化的时候，序列化机制就把从byte<br />流里得到的firstName 的值赋值给新的Person 实例里的名叫firstName的属性。<br />Java的序列化机制提供了相关的钩子函数给我们使用，通过这些钩子函数我们可以精确<br />的控制上述的序列化及反序列化过程。ObjectInputStream的内部类GetField提供了对把属性<br />数据从流中取出来的控制，而ObjectOutputStream的内部类PutField则提供了把属性数据放<br />入流中的控制机制。就ObjectInputStream来讲，我们需要在readObject方法里来完成从流中<br />读取相应的属性数据。比如我们现在把Person 类的版本从下面的表一更新到表二：<br />/**<br />* 修改前的老版本Person类，为了简化，我们删除了所有无关的代码<br />*/<br />import java.io.*;<br />public class Person extends Humanoid<br />implements java.io.Serializable<br />{<br />private String lastName;<br />如何正确的使用Java序列化技术 技术研究系列<br />private String firstName;<br />private static final long serialVersionUID =6921661392987334380L;<br />private Person()<br />{<br />}<br />public Person(String lastName, String firstName)<br />{<br />this.lastName = lastName;<br />this.firstName = firstName;<br />}<br />public String toString()<br />{<br />return "Person " + firstName + " " + lastName;<br />}<br />}<br />修改后的Person为：<br />/**<br />* 修改后的Person类，我们将firstName和lastName变成了fullName<br />*/<br />import java.io.*;<br />public class Person extends Humanoid<br />implements java.io.Serializable<br />{<br />private String fullName;<br />private static final long serialVersionUID =6921661392987334380L;<br />private Person()<br />{<br />}<br />public Person(String fullName)<br />{<br />this.lastName = fullName;<br />}<br />public String toString()<br />{<br />return "Person " + fullName;<br />}<br />}<br />为此，我们需要编写Person类的readObject方法如下：<br />private void readObject(ObjectInputStream ois)<br />throws IOException,ClassNotFoundException<br />{<br />ObjectInputStream.GetField gf = ois.readFields();<br />fullName = (String) gf.get("fullName", null);<br />if (fullName == null)<br />{<br />String lastName = (String) gf.get("lastName", null);<br />如何正确的使用Java序列化技术 技术研究系列<br />String firstName = (String) gf.get("firstName", null);<br />if ( (lastName == null) || (firstName == null))<br />{<br />throw new InvalidClassException("invalid Person");<br />}<br />fullName = firstName + " " + lastName;<br />}<br />}<br />我们的执行顺序是：<br />1) 编译老的Person及所有类；<br />2) 将老的Person序列化到文件里；<br />3) 修改为新版本的Person类；<br />4) 编译新的Person类；<br />5) 反序列化Person；<br />执行结果非常顺利，修改后的反序列化机制仍然正确的从流中获取了旧版本Person 的<br />属性信息并完成对新版本的Person的属性赋值。<br />使用ObjectInputStream的readObject 来处理反序列化的属性时，有两点需要注意：<br />u 一旦采用自己控制属性的反序列化，则必须完成所有属性的反序列化（即要给所有<br />属性赋值）；<br />u 在使用内部类GetField 的get 方法的时候需要注意，如果get 的是一个既不在老版<br />本出现的属性，有没有在新版本出现的属性，则该方法会抛出异常：<br />IllegalArgumentException: no such field，所以我们应该在一个try块里<br />来使用该方法。<br />同理，我们可以通过writeObject 方法来控制对象属性的序列化过程。这里就不再一一<br />举例了，如果你有兴趣的话，可以自己实现Person 类的writeObject 方法，并且使用<br />ObjectOutputStream的内部类PutField来完成属性的手动序列化操作。<br />3 总结<br />Java 序列化机制提供了强大的处理能力。一般来讲，为了尽量利用Java 提供的自动化<br />机制，我们不需要对序列化的过程做任何的干扰。但是在某些时候我们需要实现一些特殊的<br />功能，比如类的多版本的控制，特殊字段的序列化控制等。我们可以通过多种方式来实现这<br />些功能：<br />u 利用序列化机制提供的钩子函数readObject和writeObject；<br />u 覆盖序列化类的metaData 信息；<br />如何正确的使用Java序列化技术 技术研究系列<br />u 使类实现Externalizable 接口而不是实现Serializable接口。<br />关于Externalizable 接口更多的介绍，可以参考JDK 的帮助提供的详细文档，同时也可<br />以快速参考《Thinking in Java》这本书第十章－Java IO系统的介绍。<br />参考资料：<br />1、 SUN关于Java 的虚拟机规范《The Java Virtual Machine Specification》；<br />2、 《Thinking in Java》；<br />3、 《基于Java平台的组件化开发技术》。</p><p> </p><img src ="http://www.blogjava.net/gm_jing/aggbug/105264.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/gm_jing/" target="_blank">黎夕</a> 2007-03-21 14:43 <a href="http://www.blogjava.net/gm_jing/articles/105264.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>hashCode</title><link>http://www.blogjava.net/gm_jing/articles/105261.html</link><dc:creator>黎夕</dc:creator><author>黎夕</author><pubDate>Wed, 21 Mar 2007 06:31:00 GMT</pubDate><guid>http://www.blogjava.net/gm_jing/articles/105261.html</guid><wfw:comment>http://www.blogjava.net/gm_jing/comments/105261.html</wfw:comment><comments>http://www.blogjava.net/gm_jing/articles/105261.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/gm_jing/comments/commentRss/105261.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/gm_jing/services/trackbacks/105261.html</trackback:ping><description><![CDATA[
		<p>
				<br />1、因为cpu是32位的，所以每次最多加载2^32=4G的数据，所以hashcode返回int（32位）是正好的</p>
		<p>2、一个字符串在多个应用对应的hashcode不是固定的，都是在应用是唯一的。（应用：an execution of a Java application）<br />“HashCode并不是要保证所有字符串的唯一性，它只是保证在当前系统的应用上是唯一的”，这里的应用指的是在运行当中的程序。</p>
		<p> </p>
		<p>参考：<br />Whenever it is invoked on the same object more than once during an execution of a Java application, <br />the hashCode method must consistently return the same integer, provided no information used in equals <br />comparisons on the object is modified. This integer need not remain consistent from one execution of <br />an application to another execution of the same application. </p>
<img src ="http://www.blogjava.net/gm_jing/aggbug/105261.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/gm_jing/" target="_blank">黎夕</a> 2007-03-21 14:31 <a href="http://www.blogjava.net/gm_jing/articles/105261.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java面试笔试题大汇总</title><link>http://www.blogjava.net/gm_jing/articles/101912.html</link><dc:creator>黎夕</dc:creator><author>黎夕</author><pubDate>Mon, 05 Mar 2007 06:39:00 GMT</pubDate><guid>http://www.blogjava.net/gm_jing/articles/101912.html</guid><wfw:comment>http://www.blogjava.net/gm_jing/comments/101912.html</wfw:comment><comments>http://www.blogjava.net/gm_jing/articles/101912.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/gm_jing/comments/commentRss/101912.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/gm_jing/services/trackbacks/101912.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: java面试笔试题大汇总 及c/c++面试试题转载														java						面试笔试题大汇总						(1) [						转						]JAVA						相关基础知识														1						、面向对象的特征有哪些方面						   1.						抽象：														...&nbsp;&nbsp;<a href='http://www.blogjava.net/gm_jing/articles/101912.html'>阅读全文</a><img src ="http://www.blogjava.net/gm_jing/aggbug/101912.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/gm_jing/" target="_blank">黎夕</a> 2007-03-05 14:39 <a href="http://www.blogjava.net/gm_jing/articles/101912.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>exception</title><link>http://www.blogjava.net/gm_jing/articles/101786.html</link><dc:creator>黎夕</dc:creator><author>黎夕</author><pubDate>Sun, 04 Mar 2007 14:11:00 GMT</pubDate><guid>http://www.blogjava.net/gm_jing/articles/101786.html</guid><wfw:comment>http://www.blogjava.net/gm_jing/comments/101786.html</wfw:comment><comments>http://www.blogjava.net/gm_jing/articles/101786.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/gm_jing/comments/commentRss/101786.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/gm_jing/services/trackbacks/101786.html</trackback:ping><description><![CDATA[<pre>				<strong>
* Runtime exceptions：<br />
在定义方法时不需要声明会抛出runtime exception； 在调用这个方法时不需要捕获这个runtime exception； <br />
runtime exception是从java.lang.RuntimeException或java.lang.Error类衍生出来的。<br />
* Checked exceptions：<br />
定义方法时必须声明所有可能会抛出的checked exception； 在调用这个方法时，必须捕获它的checked exception，<br />
不然就得把它的exception传递下去； checked exception是从java.lang.Exception类衍生出来的。<br />
<br />
<br />
<br />
<br />
<br />
从逻辑的角度来说，checked exceptions和runtime exception是有不同的使用目的的。<br />
checked exception用来指示一种调用方能够直接处理的异常情况。而runtime exception则用来指示一种调用方本身无法处理或恢复的程序错误。<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<hr />
<br />
java.lang.RuntimeException</strong> (程序默认抛出的异常，不需要捕获)<br />
<a title="class in java.nio" href="mk:@MSITStore:F:\tools\help\jdk150.chm::/jdk150/api/java/nio/BufferOverflowException.html">BufferOverflowException</a>,<a title="class in java.lang" href="mk:@MSITStore:F:\tools\help\jdk150.chm::/jdk150/api/java/lang/ClassCastException.html">ClassCastException</a>, <br />
<a title="class in org.w3c.dom" href="mk:@MSITStore:F:\tools\help\jdk150.chm::/jdk150/api/org/w3c/dom/DOMException.html">DOMException</a>,<a title="class in java.lang" href="mk:@MSITStore:F:\tools\help\jdk150.chm::/jdk150/api/java/lang/IndexOutOfBoundsException.html">IndexOutOfBoundsException</a>,<br />
<a title="class in java.lang" href="mk:@MSITStore:F:\tools\help\jdk150.chm::/jdk150/api/java/lang/NullPointerException.html">NullPointerException</a><a title="class in java.lang" href="mk:@MSITStore:F:\tools\help\jdk150.chm::/jdk150/api/java/lang/TypeNotPresentException.html"><br />
</a><strong>javax.management.modelmbean.XMLParseException<br />
</strong><strong>java.sql.SQLException</strong>
...</pre>
<img src ="http://www.blogjava.net/gm_jing/aggbug/101786.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/gm_jing/" target="_blank">黎夕</a> 2007-03-04 22:11 <a href="http://www.blogjava.net/gm_jing/articles/101786.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java内部类</title><link>http://www.blogjava.net/gm_jing/articles/101777.html</link><dc:creator>黎夕</dc:creator><author>黎夕</author><pubDate>Sun, 04 Mar 2007 12:25:00 GMT</pubDate><guid>http://www.blogjava.net/gm_jing/articles/101777.html</guid><wfw:comment>http://www.blogjava.net/gm_jing/comments/101777.html</wfw:comment><comments>http://www.blogjava.net/gm_jing/articles/101777.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/gm_jing/comments/commentRss/101777.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/gm_jing/services/trackbacks/101777.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: Java内部类 （嵌套的）内部类：&nbsp; - 成员类&nbsp; - 局部类（方法或者代码块）&nbsp; - 匿名类内部类的权限&nbsp; - 外部类所有的成员（比如私有的）都有权限访问内部类 [通常没有任何的权限&nbsp;&nbsp;&nbsp; 修饰，但是如果对内部类是隐藏的，可以通过Outer.this.outerVar来引用]&nbsp; - 静态内部类不可以引用外...&nbsp;&nbsp;<a href='http://www.blogjava.net/gm_jing/articles/101777.html'>阅读全文</a><img src ="http://www.blogjava.net/gm_jing/aggbug/101777.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/gm_jing/" target="_blank">黎夕</a> 2007-03-04 20:25 <a href="http://www.blogjava.net/gm_jing/articles/101777.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java 代码规范 </title><link>http://www.blogjava.net/gm_jing/articles/90750.html</link><dc:creator>黎夕</dc:creator><author>黎夕</author><pubDate>Fri, 29 Dec 2006 07:34:00 GMT</pubDate><guid>http://www.blogjava.net/gm_jing/articles/90750.html</guid><wfw:comment>http://www.blogjava.net/gm_jing/comments/90750.html</wfw:comment><comments>http://www.blogjava.net/gm_jing/articles/90750.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/gm_jing/comments/commentRss/90750.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/gm_jing/services/trackbacks/90750.html</trackback:ping><description><![CDATA[
		<p>
				<br />
				<br />【引用】<a href="/calvin/archive/2006/12/15/87903.html">http://www.blogjava.net/calvin/archive/2006/12/15/87903.html</a></p>
<img src ="http://www.blogjava.net/gm_jing/aggbug/90750.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/gm_jing/" target="_blank">黎夕</a> 2006-12-29 15:34 <a href="http://www.blogjava.net/gm_jing/articles/90750.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于clob</title><link>http://www.blogjava.net/gm_jing/articles/69158.html</link><dc:creator>黎夕</dc:creator><author>黎夕</author><pubDate>Tue, 12 Sep 2006 06:58:00 GMT</pubDate><guid>http://www.blogjava.net/gm_jing/articles/69158.html</guid><wfw:comment>http://www.blogjava.net/gm_jing/comments/69158.html</wfw:comment><comments>http://www.blogjava.net/gm_jing/articles/69158.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/gm_jing/comments/commentRss/69158.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/gm_jing/services/trackbacks/69158.html</trackback:ping><description><![CDATA[
		<p style="TEXT-INDENT: 2em">
				<br />import java.sql.*; <br />import java.io.*; <br />import oracle.jdbc.driver.OracleResultSet; <br />import oracle.sql.CLOB;<br /><br />public class TestOracleClob implements Serializable{ <br /><br />public static void main(String[] args) { <br /><br />//create table test (id integer,content clob); <br />System.out.println("-------------------insert -----------------"); 
</p>
		<p style="TEXT-INDENT: 2em">
				<br />try{ <br />Class.forName("oracle.jdbc.driver.OracleDriver"); <br />Connection con=DriverManager.getConnection("jdbc:oracle:thin:@fangm:1521:LICSFC","SFC","SFC"); 
</p>
		<p style="TEXT-INDENT: 2em">
				<br />//con.setAutoCommit(false); <br />//Ok 1 <br />String sql="insert into test values(1,empty_clob())"; <br />Statement stmt=con.createStatement(); <br />ResultSet rs=stmt.executeQuery(sql); <br />String sqll="select content from test where id=1 for update"; <br />ResultSet rss=stmt.executeQuery(sqll); 
</p>
		<p style="TEXT-INDENT: 2em">
				<br />if(rss.next()){ <br />         CLOB clob = ((OracleResultSet)rss).getCLOB(1); <br />        clob.putString(1,"ddddddddddddddddddddddddddddddddddd"); <br />        sql="update test set content=? where id=1"; <br />         PreparedStatement pstmt=con.prepareStatement(sql); <br />         pstmt.setClob(1,clob); <br />         pstmt.executeUpdate(); <br />         pstmt.close(); <br />} 
</p>
		<p style="TEXT-INDENT: 2em">
				<br />//Ok 2 <br />//String sql1="insert into test values(2,empty_clob())"; <br />//ResultSet rs3=stmt.executeQuery(sql1); <br />String sql12="insert into test values(?,?)"; <br />PreparedStatement pstmt1=con.prepareStatement(sql12); <br />pstmt1.setInt(1,2); <br />pstmt1.setClob(2,oracle.sql.CLOB.empty_lob()); <br />pstmt1.executeUpdate(); <br />String sqll2="select content from test where id=2 for update"; <br />ResultSet rss2=stmt.executeQuery(sqll2); <br />if(rss2.next()){ <br />CLOB clob = ((OracleResultSet)rss2).getCLOB(1); <br />clob.putString(1,"affffffffffdfdfdfdddddddffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdddfff"); <br />String sql1="update test set content=? where id=2"; <br />PreparedStatement pstmt=con.prepareStatement(sql1); <br />pstmt.setClob(1,clob); <br />pstmt.executeUpdate(); <br />pstmt.close(); <br />} <br />//con.commit(); 
</p>
		<p style="TEXT-INDENT: 2em">
				<br />rss.close(); <br />rss2.close(); <br />pstmt1.close(); <br />rs.close(); <br />stmt.close(); <br />con.close(); <br />System.out.println("-------------insert ok-------------"); <br />}catch(Exception e){ <br />System.out.println("insert:"+e); <br />} 
</p>
		<p style="TEXT-INDENT: 2em">
				<br />System.out.println("-------------------query -----------------"); <br />try{ <br />String content=""; <br />Class.forName("oracle.jdbc.driver.OracleDriver"); <br />Connection con=DriverManager.getConnection("jdbc:oracle:thin:@fangm:1521:LICSFC","SFC","SFC"); <br />Statement stmt=con.createStatement(); <br />String sql="select content from test where id=1"; <br />ResultSet rs=stmt.executeQuery(sql); <br />if(rs.next()){ <br />CLOB clob = ((OracleResultSet)rs).getCLOB(1); <br />if(clob!=null){ <br />Reader is=clob.getCharacterStream(); <br />BufferedReader br=new BufferedReader(is); <br />String s=br.readLine(); <br />while(s!=null){ <br />content+=s+","; <br />s=br.readLine(); <br />} <br />}<br />} 
</p>
		<p style="TEXT-INDENT: 2em">
				<br />rs.close(); 
</p>
		<p style="TEXT-INDENT: 2em">
				<br />stmt.close(); <br />con.close(); <br />System.out.println("clob:"+content); <br />System.out.println("-------------query ok-------------"); <br />}catch(Exception ee){ <br />System.out.println("query:"+ee); <br />} <br /><br />} <br />} </p>
		<br />
		<br />【注】<br />1.insert 可以直接插入字符串，但是有个数限制。<br />   如果开始插入empty_clob()，后面再update，则没有了限制。<br /><br /><br />2.如果后面有update，则在select时候必须lock（for update）<br /><img src ="http://www.blogjava.net/gm_jing/aggbug/69158.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/gm_jing/" target="_blank">黎夕</a> 2006-09-12 14:58 <a href="http://www.blogjava.net/gm_jing/articles/69158.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>乱码问题</title><link>http://www.blogjava.net/gm_jing/articles/64116.html</link><dc:creator>黎夕</dc:creator><author>黎夕</author><pubDate>Thu, 17 Aug 2006 06:08:00 GMT</pubDate><guid>http://www.blogjava.net/gm_jing/articles/64116.html</guid><wfw:comment>http://www.blogjava.net/gm_jing/comments/64116.html</wfw:comment><comments>http://www.blogjava.net/gm_jing/articles/64116.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/gm_jing/comments/commentRss/64116.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/gm_jing/services/trackbacks/64116.html</trackback:ping><description><![CDATA[<p>1、尽量使用统一的编码，如果你是重头开发一个系统，特别是Java开发的，推荐从页面到数据库再到配置文件都使用UTF-8进行编码，安全第一。<br />
<br />
2、采用三种方式<br />
1）入门方法，在所有的servlet和jsp中堆设定用的代码。<br />
2）中级方法，对web伺服器进行配置。<br />
3）高级方法，编写filter过滤器，对&#8220;POST&#8221;和&#8220;GET&#8221;独立过滤处理。<br />
上面的注意对post和get的分别处理<br />
<br />
3、数据库的乱码<br />
a.设置数据库的编码<br />
b.创建connection时候，在url中传递编码<br />
jdbc:mysql://localhost:3306/hibernateTest?useUnicode=true&amp;amp;characterEncoding=GBK<br />
c.当传递的数据和数据库不一致，只能重新new string<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
【参考】http://www.javaeye.com/topic/31742<br />
乱码对于使用非英语文字程序员基本上是一直缠绕在身边的麻烦事，这个谁也避免不了。下面是我解决乱码时候的一点小经验。欢迎指正<br />
&nbsp; <br />
一、避免乱码的一些注意点：<br />
1.尽量使用统一的编码，如果你是重头开发一个系统，特别是Java开发的，推荐从页面到数据库再到配置文件都使用UTF-8进行编码，安全第一。<br />
2.SetCharacterEncodingFilter的使用，这个东西不是万能的，但是没有它就会很麻烦，如果是基于Servlet开发的东西，能用的就给它用上，省心。不过有一个注意的地方，这个Filter只是对POST请求有效，GET一律忽略，不信你可以debug一下，看看它怎么做的，至于为什么不过滤get请求，好象是它对GET请求是无能为力的。<br />
3.就如上面所说，GET请求有问题，尽量使用POST请求，这个也是Web开发的一个基本要领：<br />
Web Health Warning:Put All Destructive Actions Behind a POST method(from Agile Web Development with Rails)<br />
有点扯远了，不过少用GET，是会有回报滴。<br />
4.JavaScript和Ajax乱码的避免，注意JavaScript默认是ISO8859的编码，避免JS/AJAX乱码和GET一样，不要在URL里面使用中文，实在避免不了，就只能在生成链接的时候转码，绝对不能想当然的认为SetCharacterEncodingFilter会帮你做什么事情。<br />
5.尽早统一开发环境，早点模拟真实环境测试，这个好像也有跑题的嫌疑，但凡软件开发都是这么干的，但仍然值得注意。我这出现过一次状况，程序是在Win下编译的，拿去Linux上测试没问题，等实际部署的时候代码是在Linux下编译，结果乱码，秋后算帐总觉得有点晚。<br />
<br />
二、乱码发生的情况和应对措施<br />
1.开发环境乱码<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 由于Java默认使用UTF-8编码，而且网上很多人都建议Struts开发的时候应尽量选用UTF-8做为默认编码，而非GBK。IDE使 用Eclipse，在第一次使用Eclipse的时候应将default text editor改为UTF-8编码，免得日后后悔再改就惨了，我本次开发的时候就忽视了这一点，刚开始没注意，结果到快交工时乱码问题无法解决，导致将所有 的文件全部修改一遍，呜&#8230;&#8230;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 自打使用Ubuntu，我就开心的笑阿，再也不用为搞这些乱码问题而烦恼^^(Ubuntu公益广告）<br />
2.POST请求的过滤<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这个是最基本的了，每个Servlet系统基本都会用到这个东西。不过只对POST请求有效，这个挺关键的。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 使用SetCharacterEncodingFilter，这个很基础的一套过滤器，将所有来自页面的POST请求全部过滤为UTF-8编码。<br />
3. JSP ,HTML页面乱码<br />
&nbsp;&nbsp;&nbsp;&nbsp; 将JSP页面全部改为charset=UTF-8，这样可以保证与后台交互的时候都是UTF-8编码，一般应用做了以上工作就基本可以应付了。<br />
4.资源文件中汉字转化UTF-8字符问题<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 国际化问题，在使用资源文件的时候，由于中文在properties文件中无法被程序所识别，需要将其进行转码，我在资源文件下面制作了一个很简单的 bat文件，每次修改资源文件的时候都是在一个临时文件中修改，然后执行这个bat文件，将其转化并保存为所需要的资源文件，这个动作挺烦的，也有项目组 成员使用一些插件，但是那些东西都是直接写UTF-8码的，有时候反倒不方便，不过以后任务量巨大的时候可能会考虑使用。Bat文件内容:&nbsp;&nbsp; set path=%path%;%JAVA_HOME%/bin/,native2ascii -encoding UTF-8 ApplicationResources_bk.txt &gt; ApplicationResources_zh.properties<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp; PS:上面的方法好老了，实际操作起来相当麻烦，现在基本都是使用Eclipse插件，Eclipse3.1时使用PropertyEditor，但是这 个项目看上去好像停摆了，到Eclipse3.2时改用了ResourseBundle，相当的强劲的一个插件，推荐使用。<br />
5. GET请求乱码<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如果在本项目中采用了get方式提交请求并附加参数，结果导致编码乱码，原因是Tomcat默认请求编码是ISO8859，需要在Tomcat的配置文件 server.xml添加一个参数，URIEncoding=&#8221;UTF-8&#8221;,这样请求中附件的参数就会以UTF-8来进行编码。<br />
6.Ajax请求乱码<br />
&nbsp;&nbsp;&nbsp; 使用Ajax，JS也是默认使用ISO8859编码，所以在进行请求时遇到中文参数需要进行编码，如：var url = "GetSelectListAction.do?queryData=subTrade" + "&amp;queryId=" + encodeURI(obj.value) + "&amp;r=" + Math.random();&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; 这里有两个地方需要注意：第一个地方是encodeURI()，方法，可以将参数进行转码，默认是转化为UTF-8，如果需要转为其他码制，需要在方法中添加第二个参数。<br />
&nbsp;&nbsp;&nbsp;&nbsp; 第二个地方是Math.random()，由于Ajax有缓存机制，在接受请求的时候第一时间先判断该请求的地址是否被访问过，如果被访问过则 直接使用缓存中的内容返回，这个东西很讨厌，客户在访问过一次出错后以后每次出现的都是这个错误，所以在请求中给其增加一个时间戳，只要可以随机生成一个 不同的字串就可以，保证Ajax每次都去访问服务器。<br />
7. GET方法的另一个乱码问题<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在项目即将交工的时候突然又出现乱码问题，发现对于超长的汉字做为参数传递仍然会出现乱码问题，解决方法是采用java.net.URLEncoder的 Encode方法强制转码，缺点是会使JSP页面代码相当的长，但是目前还没有其他好的解决办法，我想最好的办法就是不用中文做为参数传递 ：P，写法如：&lt;a href="TestAction.do?name=&lt;%= java.net.URLEncoder.encode("你好","UTF-8")%&gt;<br />
<br />
8.乱码仍然是偶们的心病，一直牵动着大家的心，最近一位朋友说连接MSSQL数据库有乱码，使用了很多办法，都没解决，后来重新下了个新的驱动搞定&#8230;&#8230;<br />
数据库乱码其实也很讨厌的，一般来说驱动问题比较常见，所以一旦碰到比较难缠的乱码可以先考虑下换换驱动。也有如MySQL这种，直接连接的时候就需要显示进行编码转化的，这个就要不同情况区别对待了。<br />
<br />
//2007年11月30日添加<br />
9.WebService乱码，由于对WebService不怎么熟悉，使用的是Weblogic提供的WebService支持，乱码再次出现搞得手忙脚乱，而且无从下手，在自己系统上跑都没有问题，结果跑到服务器上就全乱套，又无法调试，愁人。<br />
&nbsp;&nbsp;&nbsp; 反复尝试的过程就不说了，绝对比普通的Web开发麻烦的多。最终解决方法：<br />
&nbsp;&nbsp;&nbsp; A.为WebService服务也加上一个filter，WebService也是走HTTP协议的，这个东西同样有用，先得加上。<br />
&nbsp;&nbsp;&nbsp; B.修改服务器上的环境变量，LANG=zh_CN.UTF-8，改成这个是为什么我仍然说的不是很清楚，不过当时开发人员就是在Win下开发的，我在自己的Ubuntu上测试没问题，拿到Redhat服务器上就不行，因为服务器上默认的是LANG＝en_US.UTF-8，这个明显是不支持汉字的。<br />
&nbsp;&nbsp;&nbsp; 经过这两个步骤WebService乱码总算得到抑制，它主要的麻烦在于所有与协议有关的东西都被Weblogic包办，里面做什么事情我们不好控制，所以只能采取这种比较笨的办法，虽然解燃煤之急但无法寻根溯源的搞定它，说不定哪天又会出来搞鬼。果然又一次出现乱码问题，经过比较环境变量发现服务器上的LC_CTYPE被修改了，所以强制改成LC_CTYPE=zh_CN。修改环境变量的方法不到万不得已不推荐使用。 <br />
<br />
<br />
<br />
</p>
<h2>【参考】<a id="AjaxHolder_ctl01_TitleUrl" href="http://www.cnblogs.com/pony/archive/2008/08/05/1260925.html">Java开发，表单提交中发生中文乱码的问题。</a> </h2>
<div class="postText">
<p>Web开发的中文问题一直困惑大家，尤其是对于初上手者。这次有机会彻底解决研究了一下中文乱码的原因和解决方案，做个总结。<br />
为什么会有中文乱码？<br />
因为在默认情况下，HTTP的包都是以&#8220;8859_1&#8221;来编码的（没办法，谁叫这些标准都是老美定的）。&#8220;8859_1&#8221;是西文编码方式，对于英文字母没有任何问题，但是对于中文就不行了。所以，如果不做任何设定，直接将中文用&#8220;8859_1&#8221;来编码传递，那结果必然是乱码。<br />
解决思路是什么？<br />
好在老美还是有国际化眼光的，HTTP包的编码方式可以由用户指定。因此，只要事先指定好用相对应的编码方式来对传递内容（比如表单提交的中文等）进行编码，就可以顺利解决乱码的问题。<br />
两个基本概念<br />
在进入具体的解决方法之前，首先要对两个基本概念作一下解释。对于由表单提交的内容，HTTP有两种传递方式，分别是&#8220;GET&#8221;方式和&#8220;POST&#8221;方式。<br />
&#8220;GET&#8221;方式就是将各参数直接通过HTTP的包头（head）来传递，简而言之就是直接通过我们所熟悉的网址（URL）来传递，所以我们经常能看到的在一个网址后面跟着许多复杂的由&#8220;?&#8221;和&#8220;&amp;&#8221;构成的字符串，其实这就是需要传递的参数了。<br />
&#8220;POST&#8221;方式则是将所需传递的参数包在HTTP的正文（body）中来传递。因此通过&#8220;POST&#8221;方式来进行传递，在浏览器的网址上面什么都看不见。<br />
因此，相比较而言，&#8220;POST&#8221;隐蔽性较好；而&#8220;GET&#8221;方式使用起来比较容易，直接写URL就可以了。<br />
综上所述，不难发现，解决中文乱码问题实际上就变为对这两种HTTP传递的编码方式进行适当的设定。当然，从解决问题的难易以及对系统架构的完美性角度着手，又分为以下三个层次：<br />
1）入门方法，在所有的servlet和jsp中堆设定用的代码。<br />
2）中级方法，对web伺服器进行配置。<br />
3）高级方法，编写filter过滤器，对&#8220;POST&#8221;和&#8220;GET&#8221;独立过滤处理。<br />
下面就具体描述各解决方法：<br />
1）入门方法，在所有的servlet和jsp中&#8220;堆&#8221;写设定用的代码。<br />
所谓入门方法，那就是现实十分简单，当然效果也是很好的。只是必须在每个相应的文件中写相同的设定代码，代码的重复性就比较大。<br />
由前面所述，由于&#8220;POST&#8221;和&#8220;GET&#8221;方式的不同，因此对应着两种的设定方式也不同。<br />
&#8220;POST&#8221;的情况下，如果服务器端脚本是一个servlet，那只要在doPost()方法里面插入一句
<p>request.setCharacterEncode("GB2312");
<p>需要注意的是，这句设定必须在所有从request对象做提取操作之前执行，如果类似于request.getParameter()的操作在前，那么系统将使用默认的&#8220;8859_1&#8221;编码方式，而忽略后面的设定代码。<br />
如果服务器端是一个jsp脚本，那只要在该脚本的jsp申明部分做好设定即可：
<p>&lt;%@ page language="java" contentType="text/html; charset=gb2312" pageEncoding="gb2312"%&gt;
<p>如果是&#8220;GET&#8221;方式，也就是想通过URL来传递中文的话，稍微要麻烦些，首先因为浏览器地址栏是不支持中文的，也就是如果直接将中文放置在超级连接里面是无效的。因此需要在发送端对中文内容进行编码，比如：
<p>URLEncoder.encoder("http://localhost/submit?name=张三","UTF-8");
<p>&#8220;UTF-8&#8221;表示用这种编码方式对原字符串进行编码，编码好之后看到的结果是
<p>http://localhost/submit?name=%D5%C5%C8%FD
<p>所以我们经常看到在浏览器里面有众多的类似与&#8220;%D5%C5%C8%FD&#8221;这样的字符串，就是表明被UTF-8编码过了。由于UTF-8是跨各种平台的通用编码方式，因此比较常用于各种语言文字的传输载体。<br />
相对应的，在接受方需要进行反向的解码即可，代码如下：
<p>new String( request.getParameter("name").getBytes("8859_1"), "gb2312" );
<p>这里可能会有一些疑问，为什么用&#8220;8859_1&#8221;来解码。事实上，我在第一次尝试的时候也曾使用&#8220;UTF-8&#8221;来尝试解码，结果出现乱码失败。究其原因，尽管&#8220;张三&#8221;被编码成了&#8220;%D5%C5%C8%FD&#8221;来传输，但是在传输过程中，&#8220;%D5%C5%C8%FD&#8221;仍旧需要由&#8220;8859_1&#8221;来编码打包成HTTP，因此，在接收端，自然先需要由&#8220;8859_1&#8221;来还原到&#8220;%D5%C5%C8%FD&#8221;的&#8220;UTF-8&#8221;格式，然后再由&#8220;UTF-8&#8221;还原到&#8220;GB2312&#8221;。<br />
所以这样也不难理解为什么所谓&#8220;浏览器地址栏是不支持中文&#8221;，不能直接用中文而要用&#8220;UTF-8&#8221;来通过&#8220;8859_1&#8221;来打包了，原因就是&#8220;%D5%C5%C8%FD&#8221;这串类似于密码般的字符串本身就是西文字符，用&#8220;8859_1&#8221;编解码没有任何问题。而中文由于是2byte一个汉字，直接用西文方式来编解码自然就会出现问题。这也就是为什么称&#8220;UTF-8&#8221;为&#8220;跨各种平台的通用编码方式&#8221;了。<br />
背景小资料：<br />
由于&#8220;UTF-8&#8221;是通用编码方式，因此所有的语言格式均可以转换为&#8220;UTF-8&#8221;，在日益国际的今天，多语言的系统要求越来越多，因此强烈建议使用&#8220;UTF-8&#8221;来做为系统统一的编解码方式，从而彻底解决中文乱码的问题。<br />
&#8220;UTF-8&#8221;为了能做到兼容所有语言的编解码，因此每一个字符均用2个byte来编码。这样就造成了存西文字符时需要多一倍的空间。这也算是为了通用而付出的代价了。 <br />
2）中级方法，对web伺服器进行配置<br />
可想而知，相对于&#8220;堆&#8221;写大量代码，配置一下web伺服器config文件来解决中文乱码问题就显得优雅许多。但是由于各种web伺服器的情况不同，其配置方法也不尽相同。因此，其兼容性是个比较大的问题。<br />
这里列举一下，如何通过修改Tomcat的conf配置文件来解决中文乱码的问题。<br />
找到Tomcat的配置文件server.xml中的Connector这一行，为其添加一个如下的属性
<p>tomcat4 中 get 与 post 的编码是一样的，所以只要在过滤器中通过 request.setCharacterEncoding 设定一次就可以解决 get 与 post 的问题。<br />
然而，在 tomcat5 中，get 与 post 的处理是分开进行的，对get的处理通过 前面的URIEncoding进行处理，对post的内容依然通过 request.setCharacterEncoding 处理，为了保持兼容，就有了这个设定(useBodyEncodingForURI="true" 使用与 Body 一样的编码来处理 URI, 这个设定是为了与 tomcat4保持兼容)。<br />
<span style="color: red"><br />
<br />
<br />
<br />
</span>3）高级方法，编写filter过滤器，对&#8220;POST&#8221;和&#8220;GET&#8221;独立过滤处理。<br />
高级方法，顾名思义，就是可以脱离于任何平台，同时又免去冗余的队旗代码工作的解决方案——编写过滤器，Filter。<br />
首先编写一个过滤器SetCharacterEncodingFilter
<p>public class SetCharacterEncodingFilter implements Filter {<br />
/**<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* The default character encoding to set for requests that pass through<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* this filter.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/<br />
protected String encoding = null;<br />
/**<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* The filter configuration object we are associated with. &nbsp;If this value<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* is null, this filter instance is not currently configured.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/<br />
&nbsp;&nbsp;&nbsp;protected FilterConfig filterConfig = null;<br />
&nbsp;&nbsp;&nbsp;/**<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* Should a character encoding specified by the client be ignored?<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/ &nbsp;&nbsp;&nbsp;<br />
protected boolean ignore = true;<br />
&nbsp;// --------------------------------------------------------- Public Methods<br />
&nbsp;&nbsp;&nbsp;/**<br />
&nbsp;&nbsp;&nbsp;&nbsp;* Take this filter out of service.<br />
&nbsp;&nbsp;&nbsp;&nbsp;*/<br />
&nbsp;&nbsp;&nbsp;public void destroy() {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.encoding = null;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.filterConfig = null;<br />
&nbsp;&nbsp;&nbsp;}<br />
/**<br />
&nbsp;&nbsp;&nbsp;&nbsp;* Select and set (if specified) the character encoding to be used to<br />
&nbsp;&nbsp;&nbsp;&nbsp;* interpret request parameters for this request.<br />
&nbsp;&nbsp;&nbsp;&nbsp;*<br />
&nbsp;&nbsp;&nbsp;&nbsp;* @param request The servlet request we are processing<br />
&nbsp;&nbsp;&nbsp;&nbsp;* @param result The servlet response we are creating<br />
&nbsp;&nbsp;&nbsp;&nbsp;* @param chain The filter chain we are processing<br />
&nbsp;&nbsp;&nbsp;&nbsp;*<br />
&nbsp;&nbsp;&nbsp;&nbsp;* @exception IOException if an input/output error occurs<br />
&nbsp;&nbsp;&nbsp;&nbsp;* @exception ServletException if a servlet error occurs<br />
&nbsp;&nbsp;&nbsp;&nbsp;*/<br />
&nbsp;&nbsp;&nbsp;public void doFilter(ServletRequest request, ServletResponse response,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FilterChain chain)<br />
&nbsp;&nbsp;&nbsp;throws IOException, ServletException {<br />
&nbsp;// Conditionally select and set the character encoding to be used<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (ignore || (request.getCharacterEncoding() == null)) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String encoding = selectEncoding(request);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(encoding != null){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;HttpServletRequest httpServletRequest = (HttpServletRequest) request;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(httpServletRequest.getMethod().toLowerCase().equals("post")){<br />
&nbsp;&nbsp;&nbsp;//如果是POST方法<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;request.setCharacterEncoding(encoding);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//如果是GET方法<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//非常抱歉，我还有没有找到很好的对应get方法的代码<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//一旦完成了这部分代码，马上添加在这里。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//！&#183;#￥%&#8230;&#8230;—*（）——+|<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;// Pass control on to the next filter<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;chain.doFilter(request, response);<br />
&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;/**<br />
&nbsp;&nbsp;&nbsp;&nbsp;* Place this filter into service.<br />
&nbsp;&nbsp;&nbsp;&nbsp;*<br />
&nbsp;&nbsp;&nbsp;&nbsp;* @param filterConfig The filter configuration object<br />
&nbsp;&nbsp;&nbsp;&nbsp;*/<br />
&nbsp;&nbsp;&nbsp;public void init(FilterConfig filterConfig) throws ServletException {<br />
&nbsp;&nbsp;&nbsp;this.filterConfig = filterConfig;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.encoding = filterConfig.getInitParameter("encoding");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String value = filterConfig.getInitParameter("ignore");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (value == null)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.ignore = true;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else if (value.equalsIgnoreCase("true"))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.ignore = true;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else if (value.equalsIgnoreCase("yes"))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.ignore = true;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.ignore = false;<br />
&nbsp;&nbsp;&nbsp;}<br />
&nbsp;// ------------------------------------------------------ Protected Methods<br />
&nbsp;&nbsp;&nbsp;/**<br />
&nbsp;&nbsp;&nbsp;&nbsp;* Select an appropriate character encoding to be used, based on the<br />
&nbsp;&nbsp;&nbsp;&nbsp;* characteristics of the current request and/or filter initialization<br />
&nbsp;&nbsp;&nbsp;&nbsp;* parameters. &nbsp;If no character encoding should be set, return<br />
&nbsp;&nbsp;&nbsp;&nbsp;* &lt;code&gt;null&lt;/code&gt;.<br />
&nbsp;&nbsp;&nbsp;&nbsp;* &lt;p&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;* The default implementation unconditionally returns the value configured<br />
&nbsp;&nbsp;&nbsp;&nbsp;* by the &lt;strong&gt;encoding&lt;/strong&gt; initialization parameter for this<br />
&nbsp;&nbsp;&nbsp;&nbsp;* filter.<br />
&nbsp;&nbsp;&nbsp;&nbsp;*<br />
&nbsp;&nbsp;&nbsp;&nbsp;* @param request The servlet request we are processing<br />
&nbsp;&nbsp;&nbsp;&nbsp;*/<br />
&nbsp;&nbsp;&nbsp;protected String selectEncoding(ServletRequest request) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return (this.encoding);<br />
&nbsp;&nbsp;&nbsp;}<br />
}
<p>编写完过滤器以后，需要对其进行部署，也就是在web.xml中做个配置：<br />
在&lt;display-name&gt;标签之后，添加：
<p>&nbsp;&nbsp;&nbsp;&lt;filter&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;filter-name&gt;Set Character Encoding&lt;/filter-name&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;filter-class&gt;com.zavax.utility.filters.SetCharacterEncodingFilter&lt;/filter-class&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;init-param&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;param-name&gt;encoding&lt;/param-name&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;param-value&gt;UTF8&lt;/param-value&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/init-param&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;init-param&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;param-name&gt;ignore&lt;/param-name&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;param-value&gt;true&lt;/param-value&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/init-param&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/filter&gt;<br />
&nbsp;&nbsp;&nbsp;&lt;filter-mapping&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;filter-name&gt;Set Character Encoding&lt;/filter-name&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;url-pattern&gt;/*&lt;/url-pattern&gt;<br />
&nbsp;&nbsp;&nbsp;&lt;/filter-mapping&gt;</p>
</div>
<img src ="http://www.blogjava.net/gm_jing/aggbug/64116.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/gm_jing/" target="_blank">黎夕</a> 2006-08-17 14:08 <a href="http://www.blogjava.net/gm_jing/articles/64116.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java中的Time处理</title><link>http://www.blogjava.net/gm_jing/articles/64115.html</link><dc:creator>黎夕</dc:creator><author>黎夕</author><pubDate>Thu, 17 Aug 2006 06:08:00 GMT</pubDate><guid>http://www.blogjava.net/gm_jing/articles/64115.html</guid><wfw:comment>http://www.blogjava.net/gm_jing/comments/64115.html</wfw:comment><comments>http://www.blogjava.net/gm_jing/articles/64115.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/gm_jing/comments/commentRss/64115.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/gm_jing/services/trackbacks/64115.html</trackback:ping><description><![CDATA[
		<p>得到当前时间<br />1.  Calendar.getInstance().getTime();<br />2.  new Timestamp(System.currentTimeMillis());<br />3.  new Timestamp((Calendar.getInstance().getTime()).getTime());<br />                   --------------------------------<br />                                |<br />                               date</p>
		<p> </p>
		<p>------------------------------------------------------</p>
		<p>  SimpleDateFormat df = new SimpleDateFormat("MM/dd/yyyy HH:mm");<br />  <br />  //Calendar<br />  Date date = Calendar.getInstance().getTime();<br />  System.out.println(df.format(date));<br />  <br />  //Timestamp<br />  System.out.println(df.format(new Timestamp(System.currentTimeMillis())));<br />              System.out.println(df.format(new Timestamp(date.getTime())));</p>
		<p>
				<br />------------------------------------------------------<br />    rs.getTimestamp("ORIGINAL_RESPONSE_DATETIME");</p>
		<p>  Calendar c = Calendar.getInstance();<br />  c.setLenient(false);<br />  c.set(year, month-1, day, hour, minutes, 0);<br />  c.set(Calendar.MILLISECOND, 0); <br />  c.setTime(date);<br />         c.add(Calendar.MONTH, n);  //在日期上增加数个整月    <br />  new Timestamp(c.getTime().getTime());<br /></p>
<img src ="http://www.blogjava.net/gm_jing/aggbug/64115.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/gm_jing/" target="_blank">黎夕</a> 2006-08-17 14:08 <a href="http://www.blogjava.net/gm_jing/articles/64115.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>io流</title><link>http://www.blogjava.net/gm_jing/articles/63686.html</link><dc:creator>黎夕</dc:creator><author>黎夕</author><pubDate>Tue, 15 Aug 2006 07:28:00 GMT</pubDate><guid>http://www.blogjava.net/gm_jing/articles/63686.html</guid><wfw:comment>http://www.blogjava.net/gm_jing/comments/63686.html</wfw:comment><comments>http://www.blogjava.net/gm_jing/articles/63686.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/gm_jing/comments/commentRss/63686.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/gm_jing/services/trackbacks/63686.html</trackback:ping><description><![CDATA[<p>&nbsp;基本的io流主要是java.io.OutputStream，java.io.InputStream，Writer,Reader</p>
<p><br>1、从字节流向字符流转化中Reader的 InputStreamReader和OutputStreamReader起着重要的作用。<br>&nbsp;另外 Reader reader = (new InputSource(InputStream input)).getCharacterStream();</p>
<p>2、从字符流向字节流转化&nbsp; <br>InputStream is&nbsp;= (new InputSource(Reader<font face="Courier New"> reader</font>)).getByteStream();</p>
<p><br></p>
<p>
<hr>
<p>&#160;</p>
<p>java.io.Reader<br>&nbsp;&nbsp; BufferedReader&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //new BufferedReader(new FileReader(filePath))<br>&nbsp;&nbsp; InputStreamReader&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //InputStreamReader(InputStream in) ,InputStreamReader(InputStream in, CharsetDecoder dec) </p>
<p>&nbsp;</p>
<p>java.io.Writer<br>&nbsp;&nbsp; BufferedWriter&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //new BufferedWriter(new FilterWriter(filePath))<br>&nbsp;&nbsp; OutputStreamWriter<br>&nbsp;&nbsp; PrintWriter&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //PrintWriter(OutputStream out), PrintWriter(Writer out, boolean autoFlush) <br><br><br><br><br><br><br><br><br>【注】</p>
<table cellSpacing=0 cellPadding=3 width="100%" summary="" border=1>
    <tbody>
        <tr class=TableRowColor bgColor=white>
            <td><code><strong><a href="mk:@MSITStore:F:\help\jdk142.chm::/jdk142/api/org/xml/sax/InputSource.html#InputSource(java.io.InputStream)"><font color=#002c99>InputSource</font></a></strong>(<a title="class in java.io" href="mk:@MSITStore:F:\help\jdk142.chm::/jdk142/api/java/io/InputStream.html"><font color=#002c99>InputStream</font></a>&nbsp;byteStream)</code><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Create a new input source with a byte stream.</td>
        </tr>
        <tr class=TableRowColor bgColor=white>
            <td><code><strong><a href="mk:@MSITStore:F:\help\jdk142.chm::/jdk142/api/org/xml/sax/InputSource.html#InputSource(java.io.Reader)"><font color=#002c99>InputSource</font></a></strong>(<a title="class in java.io" href="mk:@MSITStore:F:\help\jdk142.chm::/jdk142/api/java/io/Reader.html"><font color=#002c99>Reader</font></a>&nbsp;characterStream)</code><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Create a new input source with a character stream.</td>
        </tr>
        <tr class=TableRowColor bgColor=white>
            <td><code><strong><a href="mk:@MSITStore:F:\help\jdk142.chm::/jdk142/api/org/xml/sax/InputSource.html#InputSource(java.lang.String)"><font color=#002c99>InputSource</font></a></strong>(<a title="class in java.lang" href="mk:@MSITStore:F:\help\jdk142.chm::/jdk142/api/java/lang/String.html"><font color=#002c99>String</font></a>&nbsp;systemId)</code><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Create a new input source with a system identifier.</td>
        </tr>
    </tbody>
</table>
&nbsp; <!-- ========== METHOD SUMMARY =========== --><a title=InputSource name=HTML_TO_HH_97278></a><a name=method_summary><!-- --></a>
<table cellSpacing=0 cellPadding=3 width="100%" summary="" border=1>
    <tbody>
        <tr class=TableHeadingColor bgColor=#ccccff>
            <td colSpan=2><font size=+2><strong>Method Summary</strong></font></td>
        </tr>
        <tr class=TableRowColor bgColor=white>
            <td vAlign=top noWrap align=right><font size=-1><code>&nbsp;<a href="mk:@MSITStore:F:\help\jdk142.chm::/jdk142/api/org/xml/sax/InputSource.html#InputSource(java.io.InputStream)"><font color=#002c99 size=3><strong>InputSource</strong></font></a></code></font></td>
            <td><code><strong><a href="mk:@MSITStore:F:\help\jdk142.chm::/jdk142/api/org/xml/sax/InputSource.html#getByteStream()"><font color=#002c99>getByteStream</font></a></strong>()</code><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Get the byte stream for this input source.</td>
        </tr>
        <tr class=TableRowColor bgColor=white>
            <td vAlign=top noWrap align=right><font size=-1><code>&nbsp;<a title="class in java.io" href="mk:@MSITStore:F:\help\jdk142.chm::/jdk142/api/java/io/Reader.html"><font color=#002c99 size=3>Reader</font></a></code></font></td>
            <td><code><strong><a href="mk:@MSITStore:F:\help\jdk142.chm::/jdk142/api/org/xml/sax/InputSource.html#getCharacterStream()"><font color=#002c99>getCharacterStream</font></a></strong>()</code><br></td>
        </tr>
    </tbody>
</table>
<img src ="http://www.blogjava.net/gm_jing/aggbug/63686.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/gm_jing/" target="_blank">黎夕</a> 2006-08-15 15:28 <a href="http://www.blogjava.net/gm_jing/articles/63686.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Properties 文件的操作</title><link>http://www.blogjava.net/gm_jing/articles/63453.html</link><dc:creator>黎夕</dc:creator><author>黎夕</author><pubDate>Mon, 14 Aug 2006 05:15:00 GMT</pubDate><guid>http://www.blogjava.net/gm_jing/articles/63453.html</guid><wfw:comment>http://www.blogjava.net/gm_jing/comments/63453.html</wfw:comment><comments>http://www.blogjava.net/gm_jing/articles/63453.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/gm_jing/comments/commentRss/63453.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/gm_jing/services/trackbacks/63453.html</trackback:ping><description><![CDATA[1.<br /><a title="class in java.lang" href="mk:@MSITStore:F:\help\jdk142.chm::/jdk142/api/java/lang/Object.html">java.lang.Object</a><br />  <img alt="extended by" src="mk:@MSITStore:F:\help\jdk142.chm::/jdk142/api/resources/inherit.gif" /><a title="class in java.util" href="mk:@MSITStore:F:\help\jdk142.chm::/jdk142/api/java/util/Dictionary.html">java.util.Dictionary</a><br />      <img alt="extended by" src="mk:@MSITStore:F:\help\jdk142.chm::/jdk142/api/resources/inherit.gif" /><a title="class in java.util" href="mk:@MSITStore:F:\help\jdk142.chm::/jdk142/api/java/util/Hashtable.html">java.util.Hashtable</a><br />          <img alt="extended by" src="mk:@MSITStore:F:\help\jdk142.chm::/jdk142/api/resources/inherit.gif" /><b>java.util.Properties</b><br /><br /><br /><br />2. <br />    InputStream propInput = ReportGenerator.class.getResourceAsStream(templatePropName);<br />    Properties prop = new Properties();<br />    prop.load(propInput);<br /><br />   <br /><br /><br />3.和Hashtable操作一样<br />String val= prop.getProperty(key)<br />prop.put("mail.smtp.debug", "true");<br /><br /><br /><img src ="http://www.blogjava.net/gm_jing/aggbug/63453.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/gm_jing/" target="_blank">黎夕</a> 2006-08-14 13:15 <a href="http://www.blogjava.net/gm_jing/articles/63453.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>