﻿<?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-Tinysun-随笔分类-J2SE</title><link>http://www.blogjava.net/tinysun/category/37793.html</link><description /><language>zh-cn</language><lastBuildDate>Sat, 11 Sep 2010 09:44:41 GMT</lastBuildDate><pubDate>Sat, 11 Sep 2010 09:44:41 GMT</pubDate><ttl>60</ttl><item><title>线程中释放锁的方式</title><link>http://www.blogjava.net/tinysun/archive/2010/09/10/331658.html</link><dc:creator>何克勤</dc:creator><author>何克勤</author><pubDate>Fri, 10 Sep 2010 05:51:00 GMT</pubDate><guid>http://www.blogjava.net/tinysun/archive/2010/09/10/331658.html</guid><wfw:comment>http://www.blogjava.net/tinysun/comments/331658.html</wfw:comment><comments>http://www.blogjava.net/tinysun/archive/2010/09/10/331658.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/tinysun/comments/commentRss/331658.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/tinysun/services/trackbacks/331658.html</trackback:ping><description><![CDATA[#&nbsp;调用obj的wait(),&nbsp;notify()方法前，必须获得obj锁，也就是必须写在synchronized(obj)&nbsp;{...}&nbsp;代码段内。<br />
<br />
#&nbsp;<strong>调用obj.wait()后，线程A就释放了obj的锁，</strong>否则线程B无法获得obj锁，也就无法在synchronized(obj)&nbsp;{...}&nbsp;代码段内唤醒A。<br />
<br />
#&nbsp;当obj.wait()方法返回后，线程A需要再次获得obj锁，才能继续执行。<br />
<br />
#&nbsp;如果A1,A2,A3都在obj.wait()，则B调用obj.notify()只能唤醒A1,A2,A3中的一个（具体哪一个由JVM决定）。<br />
<br />
#&nbsp;obj.notifyAll()则能全部唤醒A1,A2,A3，但是要继续执行obj.wait()的下一条语句，必须获得obj锁，因此，A1,A2,A3只有一个有机会获得锁继续执行，例如A1，其余的需要等待A1释放obj锁之后才能继续执行。<br />
<br />
#&nbsp;当B调用obj.notify/notifyAll的时候，B正持有obj锁，因此，A1,A2,A3虽被唤醒，但是仍无法获得obj锁。直到B退出synchronized块，释放obj锁后，A1,A2,A3中的一个才有机会获得锁继续执行。<br />
<br />
wait()/sleep()的区别<br />
<br />
前面讲了wait/notify机制，Thread还有一个sleep()静态方法，它也能使线程暂停一段时间。<strong>sleep与wait的不同点是：sleep并不释放锁，并且sleep的暂停和wait暂停是不一样的。obj.wait会使线程进入obj对象的等待集合中并等待唤醒。<br />
</strong>　　<br />
<strong>但是wait()和sleep()都可以通过interrupt()方法打断线程的暂停状态，从而使线程立刻抛出InterruptedException。<br />
</strong>　　<br />
如果线程A希望立即结束线程B，则可以对线程B对应的Thread实例调用interrupt方法。如果此刻线程B正在wait/sleep
/join，则线程B会立刻抛出InterruptedException，在catch()&nbsp;{}&nbsp;中直接return即可安全地结束线程。<br />
<br />
需要注意的是，InterruptedException是线程自己从内部抛出的，并不是interrupt()方法抛出的。对某一线程调用
interrupt()时，如果该线程正在执行普通的代码，那么该线程根本就不会抛出InterruptedException。但是，一旦该线程进入到
wait()/sleep()/join()后，就会立刻抛出InterruptedException。
<img src ="http://www.blogjava.net/tinysun/aggbug/331658.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/tinysun/" target="_blank">何克勤</a> 2010-09-10 13:51 <a href="http://www.blogjava.net/tinysun/archive/2010/09/10/331658.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java线程</title><link>http://www.blogjava.net/tinysun/archive/2010/09/10/331651.html</link><dc:creator>何克勤</dc:creator><author>何克勤</author><pubDate>Fri, 10 Sep 2010 05:42:00 GMT</pubDate><guid>http://www.blogjava.net/tinysun/archive/2010/09/10/331651.html</guid><wfw:comment>http://www.blogjava.net/tinysun/comments/331651.html</wfw:comment><comments>http://www.blogjava.net/tinysun/archive/2010/09/10/331651.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/tinysun/comments/commentRss/331651.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/tinysun/services/trackbacks/331651.html</trackback:ping><description><![CDATA[<div id="sina_keyword_ad_area2" class="articalContent">
<p><font style="font-size: 18px;"><strong>1》：</strong>精炼的Java线程Sleep,yield,wait,notify,Synchronized</font></p>
<p>&nbsp;<wbr></p>
<p><font size="3">多线程<br />
线程：是指进程中的一个执行流程。<br />
线程与进程的区别：每个进程都需要操作系统为其分配独立的内存地址空间，而同一进程中的所有线程在同一块地址空间中工作，这些线程可以共享同一块内存和系
统资源。<br />
<br />
<br />
如何创建一个线程？<br />
<br />
创建线程有两种方式，如下：<br />
1、 扩展java.lang.Thread类<br />
2、 实现Runnable接口<br />
Thread类代表线程类，它的两个最主要的方法是：<br />
run()——包含线程运行时所执行的代码<br />
Start()——用于启动线程<br />
<br />
一个线程只能被启动一次。第二次启动时将会抛出java.lang.IllegalThreadExcetpion异常<br />
<br />
线程间状态的转换（如图示）<br />
<br />
新建状态：用new语句创建的线程对象处于新建状态，此时它和其它的java对象一样，仅仅在堆中被分配了内存<br />
就绪状态：当一个线程创建了以后，其他的线程调用了它的start()方法，该线程就进入了就绪状态。处于这个状态的线程位于可运行池中，等待获得CPU
的使用权<br />
运行状态：处于这个状态的线程占用CPU,执行程序的代码<br />
阻塞状态：当线程处于阻塞状态时，java虚拟机不会给线程分配CPU，直到线程重新进入就绪状态，它才有机会转到运行状态。<br />
阻塞状态分为三种情况：<br />
1、
位于对象等待池中的阻塞状态：当线程运行时，如果执行了某个对象的wait()方法，java虚拟机就回把线程放到这个对象的等待池中<br />
2、
位于对象锁中的阻塞状态，当线程处于运行状态时，试图获得某个对象的同步锁时，如果该对象的同步锁已经被其他的线程占用，JVM就会把这个线程放到这个对
象的琐池中。<br />
3、
其它的阻塞状态：当前线程执行了sleep()方法，或者调用了其它线程的join()方法，或者发出了I/O请求时，就会进入这个状态中。<br />
<br />
死亡状态：当线程退出了run()方法，就进入了死亡状态，该线程结束了生命周期。<br />
或者正常退出<br />
或者遇到异常退出<br />
Thread类的isAlive()方法判断一个线程是否活着，当线程处于死亡状态或者新建状态时，该方法返回false,在其余的状态下，该方法返回
true.<br />
<br />
线程调度<br />
线程调度模型：分时调度模型和抢占式调度模型<br />
JVM采用抢占式调度模型。<br />
所谓的多线程的并发运行，其实是指宏观上看，各个线程轮流获得CPU的使用权，分别执行各自的任务。<br />
（线程的调度不是跨平台，它不仅取决于java虚拟机，它还依赖于操作系统）<br />
<br />
如果希望明确地让一个线程给另外一个线程运行的机会，可以采取以下的办法之一<br />
1、 调整各个线程的优先级<br />
2、 让处于运行状态的线程调用Thread.sleep()方法<br />
3、 让处于运行状态的线程调用Thread.yield()方法<br />
4、 让处于运行状态的线程调用另一个线程的join()方法<br />
<br />
调整各个线程的优先级<br />
Thread类的setPriority(int)和getPriority()方法分别用来设置优先级和读取优先级。<br />
如果希望程序能够移值到各个操作系统中，应该确保在设置线程的优先级时，只使用MAX_PRIORITY、NORM_PRIORITY、
MIN_PRIORITY这3个优先级。<br />
<br />
线程睡眠：当线程在运行中执行了sleep()方法时，它就会放弃CPU，转到阻塞状态。<br />
线程让步：当线程在运行中执行了Thread类的yield()静态方法时，如果此时具有相同优先级的其它线程处于就绪状态，那么yield()方法将把
当前运行的线程放到运行池中并使另一个线程运行。如果没有相同优先级的可运行线程，则yield()方法什么也不做。<br />
Sleep()方法和yield()方法都是Thread类的静态方法，都会使当前处于运行状态的线程放弃CPU，把运行机会让给别的线程，两者的区别在
于：<br />
1、sleep()方法会给其他线程运行的机会，而不考虑其他线程的优先级，因此会给较低线程一个运行的机会；yield()方法只会给相同优先级或者更
高优先级的线程一个运行的机会。<br />
2、当线程执行了sleep(long
millis)方法后，将转到阻塞状态，参数millis指定睡眠时间；当线程执行了yield()方法后，将转到就绪状态。<br />
3、sleep()方法声明抛出InterruptedException异常，而yield()方法没有声明抛出任何异常<br />
4、sleep()方法比yield()方法具有更好的移植性<br />
<br />
等待其它线程的结束：join()<br />
当前运行的线程可以调用另一个线程的 join()方法，当前运行的线程将转到阻塞状态，直到另一个线程运行结束，它才恢复运行。<br />
<br />
定时器Timer:在JDK的java.util包中提供了一个实用类Timer, 它能够定时执行特定的任务。<br />
<br />
线程的同步<br />
原子操作：根据Java规范，对于基本类型的赋值或者返回值操作，是原子操作。但这里的基本数据类型不包括long和double,
因为JVM看到的基本存储单位是32位，而long 和double都要用64位来表示。所以无法在一个时钟周期内完成。<br />
<br />
自增操作（++）不是原子操作，因为它涉及到一次读和一次写。<br />
<br />
原子操作：由一组相关的操作完成，这些操作可能会操纵与其它的线程共享的资源，为了保证得到正确的运算结果，一个线程在执行原子操作其间，应该采取其他的
措施使得其他的线程不能操纵共享资源。<br />
<br />
同步代码块：为了保证每个线程能够正常执行原子操作，Java引入了同步机制，具体的做法是在代表原子操作的程序代码前加上synchronized标
记，这样的代码被称为同步代码块。<br />
<br />
同步锁：每个JAVA对象都有且只有一个同步锁，在任何时刻，最多只允许一个线程拥有这把锁。<br />
<br />
当一个线程试图访问带有synchronized(this)标记的代码块时，必须获得
this关键字引用的对象的锁，在以下的两种情况下，本线程有着不同的命运。<br />
1、
假如这个锁已经被其它的线程占用，JVM就会把这个线程放到本对象的锁池中。本线程进入阻塞状态。锁池中可能有很多的线程，等到其他的线程释放了
锁，JVM就会从锁池中随机取出一个线程，使这个线程拥有锁，并且转到就绪状态。<br />
2、 假如这个锁没有被其他线程占用，本线程会获得这把锁，开始执行同步代码块。<br />
（一般情况下在执行同步代码块时不会释放同步锁，但也有特殊情况会释放对象锁<br />
如在执行同步代码块时，遇到异常而导致线程终止，锁会被释放；在执行代码块时，执行了锁所属对象的wait()方法，这个线程会释放对象锁，进入对象的等
待池中）<br />
<br />
线程同步的特征：<br />
1、
如果一个同步代码块和非同步代码块同时操作共享资源，仍然会造成对共享资源的竞争。因为当一个线程执行一个对象的同步代码块时，其他的线程仍然可以执行对
象的非同步代码块。（所谓的线程之间保持同步，是指不同的线程在执行同一个对象的同步代码块时，因为要获得对象的同步锁而互相牵制）<br />
2、 每个对象都有唯一的同步锁<br />
3、 在静态方法前面可以使用synchronized修饰符。<br />
4、
当一个线程开始执行同步代码块时，并不意味着必须以不间断的方式运行，进入同步代码块的线程可以执行Thread.sleep()或者执行
Thread.yield()方法，此时它并不释放对象锁，只是把运行的机会让给其他的线程。<br />
5、
Synchronized声明不会被继承，如果一个用synchronized修饰的方法被子类覆盖，那么子类中这个方法不在保持同步，除非用
synchronized修饰。<br />
<br />
线程安全的类：<br />
1、 这个类的对象可以同时被多个线程安全的访问。<br />
2、 每个线程都能正常的执行原子操作，得到正确的结果。<br />
3、 在每个线程的原子操作都完成后，对象处于逻辑上合理的状态。<br />
<br />
释放对象的锁：<br />
1、 执行完同步代码块就会释放对象的锁<br />
2、 在执行同步代码块的过程中，遇到异常而导致线程终止，锁也会被释放<br />
3、 在执行同步代码块的过程中，执行了锁所属对象的wait()方法，这个线程会释放对象锁，进入对象的等待池。<br />
<br />
死锁<br />
当一个线程等待由另一个线程持有的锁，而后者正在等待已被第一个线程持有的锁时，就会发生死锁。JVM不监测也不试图避免这种情况，因此保证不发生死锁就
成了程序员的责任。<br />
<br />
如何避免死锁<br />
一个通用的经验法则是：当几个线程都要访问共享资源A、B、C 时，保证每个线程都按照同样的顺序去访问他们。<br />
<br />
线程通信<br />
Java.lang.Object类中提供了两个用于线程通信的方法<br />
1、 wait():执行了该方法的线程释放对象的锁，JVM会把该线程放到对象的等待池中。该线程等待其它线程唤醒<br />
2、
notify():执行该方法的线程唤醒在对象的等待池中等待的一个线程，JVM从对象的等待池中随机选择一个线程，把它转到对象的锁池中。</font></p>
<p>&nbsp;<wbr></p>
<p>&nbsp;<wbr></p>
<p>&nbsp;<wbr></p>
<p><strong><em><font style="font-size: 16px;">２》：线程同步</font></em></strong></p>
<p>我们可以在计算机上运行各种计算机软件程序。每一个运行的程序可能包括多个独立运行的线程（Thread）。<br />
线程（Thread）是一份独立运行的程序，有自己专用的运行栈。线程有可能和其他线程共享一些资源，比如，内存，文件，数据库等。<br />
当多个线程同时读写同一份共享资源的时候，可能会引起冲突。这时候，我们需要引入线程&#8220;同步&#8221;机制，即各位线程之间要有个先来后到，不能一窝蜂挤上去抢作一团。<br />
同步这个词是从英文synchronize（使同时发生）翻译过来的。我也不明白为什么要用这个很容易引起误解的词。既然大家都这么用，咱们也就只好这么将就。<br />
线程同步的真实意思和字面意思恰好相反。线程同步的真实意思，其实是&#8220;排队&#8221;：几个线程之间要排队，一个一个对共享资源进行操作，而不是同时进行操作。<br />
<br />
因此，关于线程同步，需要牢牢记住的第一点是：线程同步就是线程排队。同步就是排队。线程同步的目的就是避免线程&#8220;同步&#8221;执行。这可真是个无聊的绕口令。<br />
关于线程同步，需要牢牢记住的第二点是
&#8220;共享&#8221;这两个字。只有共享资源的读写访问才需要同步。如果不是共享资源，那么就根本没有同步的必要。<br />
关于线程同步，需要牢牢记住的第三点是，只有&#8220;变量&#8221;才需要同步访问。如果共享的资源是固定不变的，那么就相当于&#8220;常量&#8221;，线程同时读取常量也不需要同步。至少一个线程修改共享资源，这样的情况下，线程之间就需要同步。<br />
关于线程同步，需要牢牢记住的第四点是：多个线程访问共享资源的代码有可能是同一份代码，也有可能是不同的代码；无论是否执行同一份代码，只要这些线程的代码访问同一份可变的共享资源，这些线程之间就需要同步。<br />
<br />
为了加深理解，下面举几个例子。<br />
有两个采购员，他们的工作内容是相同的，都是遵循如下的步骤：<br />
（1）到市场上去，寻找并购买有潜力的样品。<br />
（2）回到公司，写报告。<br />
这两个人的工作内容虽然一样，他们都需要购买样品，他们可能买到同样种类的样品，但是他们绝对不会购买到同一件样品，他们之间没有任何共享资源。所以，他们可以各自进行自己的工作，互不干扰。<br />
这两个采购员就相当于两个线程；两个采购员遵循相同的工作步骤，相当于这两个线程执行同一段代码。<br />
<br />
下面给这两个采购员增加一个工作步骤。采购员需要根据公司的&#8220;布告栏&#8221;上面公布的信息，安排自己的工作计划。<br />
这两个采购员有可能同时走到布告栏的前面，同时观看布告栏上的信息。这一点问题都没有。因为布告栏是只读的，这两个采购员谁都不会去修改布告栏上写的信息。<br />
<br />
下面增加一个角色。一个办公室行政人员这个时候，也走到了布告栏前面，准备修改布告栏上的信息。<br />
如果行政人员先到达布告栏，并且正在修改布告栏的内容。两个采购员这个时候，恰好也到了。这两个采购员就必须等待行政人员完成修改之后，才能观看修改后的信息。<br />
如果行政人员到达的时候，两个采购员已经在观看布告栏了。那么行政人员需要等待两个采购员把当前信息记录下来之后，才能够写上新的信息。<br />
上述这两种情况，行政人员和采购员对布告栏的访问就需要进行同步。因为其中一个线程（行政人员）修改了共享资源（布告栏）。而且我们可以看到，行政人员的
工作流程和采购员的工作流程（执行代码）完全不同，但是由于他们访问了同一份可变共享资源（布告栏），所以他们之间需要同步。<br />
<br />
同步锁<br />
<br />
前面讲了为什么要线程同步，下面我们就来看如何才能线程同步。<br />
线程同步的基本实现思路还是比较容易理解的。我们可以给共享资源加一把锁，这把锁只有一把钥匙。哪个线程获取了这把钥匙，才有权利访问该共享资源。<br />
生活中，我们也可能会遇到这样的例子。一些超市的外面提供了一些自动储物箱。每个储物箱都有一把锁，一把钥匙。人们可以使用那些带有钥匙的储物箱，把东西
放到储物箱里面，把储物箱锁上，然后把钥匙拿走。这样，该储物箱就被锁住了，其他人不能再访问这个储物箱。（当然，真实的储物箱钥匙是可以被人拿走复制
的，所以不要把贵重物品放在超市的储物箱里面。于是很多超市都采用了电子密码锁。）<br />
线程同步锁这个模型看起来很直观。但是，还有一个严峻的问题没有解决，这个同步锁应该加在哪里？<br />
当然是加在共享资源上了。反应快的读者一定会抢先回答。<br />
没错，如果可能，我们当然尽量把同步锁加在共享资源上。一些比较完善的共享资源，比如，文件系统，数据库系统等，自身都提供了比较完善的同步锁机制。我们不用另外给这些资源加锁，这些资源自己就有锁。<br />
但是，大部分情况下，我们在代码中访问的共享资源都是比较简单的共享对象。这些对象里面没有地方让我们加锁。<br />
读者可能会提出建议：为什么不在每一个对象内部都增加一个新的区域，专门用来加锁呢？这种设计理论上当然也是可行的。问题在于，线程同步的情况并不是很普遍。如果因为这小概率事件，在所有对象内部都开辟一块锁空间，将会带来极大的空间浪费。得不偿失。<br />
于是，现代的编程语言的设计思路都是把同步锁加在代码段上。确切的说，是把同步锁加在&#8220;访问共享资源的代码段&#8221;上。这一点一定要记住，同步锁是加在代码段上的。<br />
同步锁加在代码段上，就很好地解决了上述的空间浪费问题。但是却增加了模型的复杂度，也增加了我们的理解难度。<br />
现在我们就来仔细分析&#8220;同步锁加在代码段上&#8221;的线程同步模型。<br />
首先，我们已经解决了同步锁加在哪里的问题。我们已经确定，同步锁不是加在共享资源上，而是加在访问共享资源的代码段上。<br />
其次，我们要解决的问题是，我们应该在代码段上加什么样的锁。这个问题是重点中的重点。这是我们尤其要注意的问题：访问同一份共享资源的不同代码段，应该加上同一个同步锁；如果加的是不同的同步锁，那么根本就起不到同步的作用，没有任何意义。<br />
这就是说，同步锁本身也一定是多个线程之间的共享对象。<br />
<br />
Java语言的synchronized关键字<br />
<br />
为了加深理解，举几个代码段同步的例子。<br />
不同语言的同步锁模型都是一样的。只是表达方式有些不同。这里我们以当前最流行的Java语言为例。Java语言里面用synchronized关键字给代码段加锁。整个语法形式表现为<br />
synchronized(同步锁) {<br />
&nbsp;<wbr> // 访问共享资源，需要同步的代码段<br />
}<br />
<br />
这里尤其要注意的就是，同步锁本身一定要是共享的对象。<br />
<br />
&#8230; f1() {<br />
<br />
Object lock1 = new Object(); // 产生一个同步锁<br />
<br />
synchronized(lock1){<br />
&nbsp;<wbr> // 代码段 A<br />
// 访问共享资源 resource1<br />
// 需要同步<br />
}<br />
}<br />
<br />
上面这段代码没有任何意义。因为那个同步锁是在函数体内部产生的。每个线程调用这段代码的时候，都会产生一个新的同步锁。那么多个线程之间，使用的是不同的同步锁。根本达不到同步的目的。<br />
同步代码一定要写成如下的形式，才有意义。<br />
<br />
public static final Object lock1 = new Object();<br />
<br />
&#8230; f1() {<br />
<br />
synchronized(lock1){ // lock1 是公用同步锁<br />
&nbsp;<wbr> // 代码段 A<br />
// 访问共享资源 resource1<br />
// 需要同步<br />
}<br />
<br />
你不一定要把同步锁声明为static或者public，但是你一定要保证相关的同步代码之间，一定要使用同一个同步锁。<br />
讲到这里，你一定会好奇，这个同步锁到底是个什么东西。为什么随便声明一个Object对象，就可以作为同步锁？<br />
在Java里面，同步锁的概念就是这样的。任何一个Object Reference都可以作为同步锁。我们可以把Object
Reference理解为对象在内存分配系统中的内存地址。因此，要保证同步代码段之间使用的是同一个同步锁，我们就要保证这些同步代码段的synchronized关键字使用的是同一个Object
Reference，同一个内存地址。这也是为什么我在前面的代码中声明lock1的时候，使用了final关键字，这就是为了保证lock1的Object
Reference在整个系统运行过程中都保持不变。<br />
一些求知欲强的读者可能想要继续深入了解synchronzied(同步锁)的实际运行机制。Java虚拟机规范中（你可以在google用&#8220;JVM
Spec&#8221;等关键字进行搜索），有对synchronized关键字的详细解释。synchronized会编译成 monitor
enter, &#8230; monitor exit之类的指令对。Monitor就是实际上的同步锁。每一个Object
Reference在概念上都对应一个monitor。<br />
这些实现细节问题，并不是理解同步锁模型的关键。我们继续看几个例子，加深对同步锁模型的理解。<br />
<br />
public static final Object lock1 = new Object();<br />
<br />
&#8230; f1() {<br />
<br />
synchronized(lock1){ // lock1 是公用同步锁<br />
&nbsp;<wbr> // 代码段 A<br />
// 访问共享资源 resource1<br />
// 需要同步<br />
}<br />
}<br />
<br />
&#8230; f2() {<br />
<br />
synchronized(lock1){ // lock1 是公用同步锁<br />
&nbsp;<wbr> // 代码段 B<br />
// 访问共享资源 resource1<br />
// 需要同步<br />
}<br />
}<br />
<br />
上述的代码中，代码段A和代码段B就是同步的。因为它们使用的是同一个同步锁lock1。<br />
如果有10个线程同时执行代码段A，同时还有20个线程同时执行代码段B，那么这30个线程之间都是要进行同步的。<br />
这30个线程都要竞争一个同步锁lock1。同一时刻，只有一个线程能够获得lock1的所有权，只有一个线程可以执行代码段A或者代码段B。其他竞争失败的线程只能暂停运行，进入到该同步锁的就绪（Ready）队列。<br />
每一个同步锁下面都挂了几个线程队列，包括就绪（Ready）队列，待召（Waiting）队列等。比如，lock1对应的就绪队列就可以叫做lock1
- ready queue。每个队列里面都可能有多个暂停运行的线程。<br />
注意，竞争同步锁失败的线程进入的是该同步锁的就绪（Ready）队列，而不是后面要讲述的待召队列（Waiting
Queue，也可以翻译为等待队列）。就绪队列里面的线程总是时刻准备着竞争同步锁，时刻准备着运行。而待召队列里面的线程则只能一直等待，直到等到某个信号的通知之后，才能够转移到就绪队列中，准备运行。<br />
成功获取同步锁的线程，执行完同步代码段之后，会释放同步锁。该同步锁的就绪队列中的其他线程就继续下一轮同步锁的竞争。成功者就可以继续运行，失败者还是要乖乖地待在就绪队列中。<br />
因此，线程同步是非常耗费资源的一种操作。我们要尽量控制线程同步的代码段范围。同步的代码段范围越小越好。我们用一个名词&#8220;同步粒度&#8221;来表示同步代码段的范围。<br />
同步粒度<br />
在Java语言里面，我们可以直接把synchronized关键字直接加在函数的定义上。<br />
比如。<br />
&#8230; synchronized &#8230; f1() {<br />
&nbsp;<wbr> // f1 代码段<br />
}<br />
<br />
这段代码就等价于<br />
&#8230; f1() {<br />
&nbsp;<wbr> synchronized(this){ // 同步锁就是对象本身<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> // f1
代码段<br />
&nbsp;<wbr> }<br />
}<br />
<br />
同样的原则适用于静态（static）函数<br />
比如。<br />
&#8230; static synchronized &#8230; f1() {<br />
&nbsp;<wbr> // f1 代码段<br />
}<br />
<br />
这段代码就等价于<br />
&#8230;static &#8230; f1() {<br />
&nbsp;<wbr> synchronized(Class.forName(&#8230;)){ //
同步锁是类定义本身<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> // f1
代码段<br />
&nbsp;<wbr> }<br />
}<br />
<br />
但是，我们要尽量避免这种直接把synchronized加在函数定义上的偷懒做法。因为我们要控制同步粒度。同步的代码段越小越好。synchronized控制的范围越小越好。<br />
我们不仅要在缩小同步代码段的长度上下功夫，我们同时还要注意细分同步锁。<br />
比如，下面的代码<br />
<br />
public static final Object lock1 = new Object();<br />
<br />
&#8230; f1() {<br />
<br />
synchronized(lock1){ // lock1 是公用同步锁<br />
&nbsp;<wbr> // 代码段 A<br />
// 访问共享资源 resource1<br />
// 需要同步<br />
}<br />
}<br />
<br />
&#8230; f2() {<br />
<br />
synchronized(lock1){ // lock1 是公用同步锁<br />
&nbsp;<wbr> // 代码段 B<br />
// 访问共享资源 resource1<br />
// 需要同步<br />
}<br />
}<br />
<br />
&#8230; f3() {<br />
<br />
synchronized(lock1){ // lock1 是公用同步锁<br />
&nbsp;<wbr> // 代码段 C<br />
// 访问共享资源 resource2<br />
// 需要同步<br />
}<br />
}<br />
<br />
&#8230; f4() {<br />
<br />
synchronized(lock1){ // lock1 是公用同步锁<br />
&nbsp;<wbr> // 代码段 D<br />
// 访问共享资源 resource2<br />
// 需要同步<br />
}<br />
}<br />
<br />
上述的4段同步代码，使用同一个同步锁lock1。所有调用4段代码中任何一段代码的线程，都需要竞争同一个同步锁lock1。<br />
我们仔细分析一下，发现这是没有必要的。<br />
因为f1()的代码段A和f2()的代码段B访问的共享资源是resource1，f3()的代码段C和f4()的代码段D访问的共享资源是
resource2，它们没有必要都竞争同一个同步锁lock1。我们可以增加一个同步锁lock2。f3()和f4()的代码可以修改为：<br />
public static final Object lock2 = new Object();<br />
<br />
&#8230; f3() {<br />
<br />
synchronized(lock2){ // lock2 是公用同步锁<br />
&nbsp;<wbr> // 代码段 C<br />
// 访问共享资源 resource2<br />
// 需要同步<br />
}<br />
}<br />
<br />
&#8230; f4() {<br />
<br />
synchronized(lock2){ // lock2 是公用同步锁<br />
&nbsp;<wbr> // 代码段 D<br />
// 访问共享资源 resource2<br />
// 需要同步<br />
}<br />
}<br />
<br />
这样，f1()和f2()就会竞争lock1，而f3()和f4()就会竞争lock2。这样，分开来分别竞争两个锁，就可以大大较少同步锁竞争的概率，从而减少系统的开销。<br />
<br />
信号量<br />
<br />
同步锁模型只是最简单的同步模型。同一时刻，只有一个线程能够运行同步代码。<br />
有的时候，我们希望处理更加复杂的同步模型，比如生产者/消费者模型、读写同步模型等。这种情况下，同步锁模型就不够用了。我们需要一个新的模型。这就是我们要讲述的信号量模型。<br />
信号量模型的工作方式如下：线程在运行的过程中，可以主动停下来，等待某个信号量的通知；这时候，该线程就进入到该信号量的待召（Waiting）队列当中；等到通知之后，再继续运行。<br />
很多语言里面，同步锁都由专门的对象表示，对象名通常叫Monitor。<br />
同样，在很多语言中，信号量通常也有专门的对象名来表示，比如，Mutex，Semphore。<br />
信号量模型要比同步锁模型复杂许多。一些系统中，信号量甚至可以跨进程进行同步。另外一些信号量甚至还有计数功能，能够控制同时运行的线程数。<br />
我们没有必要考虑那么复杂的模型。所有那些复杂的模型，都是最基本的模型衍生出来的。只要掌握了最基本的信号量模型——&#8220;等待/通知&#8221;模型，复杂模型也就迎刃而解了。<br />
我们还是以Java语言为例。Java语言里面的同步锁和信号量概念都非常模糊，没有专门的对象名词来表示同步锁和信号量，只有两个同步锁相关的关键字——volatile和synchronized。<br />
这种模糊虽然导致概念不清，但同时也避免了Monitor、Mutex、Semphore等名词带来的种种误解。我们不必执着于名词之争，可以专注于理解实际的运行原理。<br />
在Java语言里面，任何一个Object Reference都可以作为同步锁。同样的道理，任何一个Object
Reference也可以作为信号量。<br />
Object对象的wait()方法就是等待通知，Object对象的notify()方法就是发出通知。<br />
具体调用方法为<br />
（1）等待某个信号量的通知<br />
public static final Object signal = new Object();<br />
<br />
&#8230; f1() {<br />
synchronized(singal) { // 首先我们要获取这个信号量。这个信号量同时也是一个同步锁<br />
<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> //
只有成功获取了signal这个信号量兼同步锁之后，我们才可能进入这段代码<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>
signal.wait(); // 这里要放弃信号量。本线程要进入signal信号量的待召（Waiting）队列<br />
<br />
// 可怜。辛辛苦苦争取到手的信号量，就这么被放弃了<br />
<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> //
等到通知之后，从待召（Waiting）队列转到就绪（Ready）队列里面<br />
// 转到了就绪队列中，离CPU核心近了一步，就有机会继续执行下面的代码了。<br />
// 仍然需要把signal同步锁竞争到手，才能够真正继续执行下面的代码。命苦啊。<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &#8230;<br />
}<br />
}<br />
<br />
需要注意的是，上述代码中的signal.wait()的意思。signal.wait()很容易导致误解。signal.wait()的意思并不是
说，signal开始wait，而是说，运行这段代码的当前线程开始wait这个signal对象，即进入signal对象的待召（Waiting）队
列。<br />
<br />
（2）发出某个信号量的通知<br />
&#8230; f2() {<br />
synchronized(singal) { // 首先，我们同样要获取这个信号量。同时也是一个同步锁。<br />
<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> //
只有成功获取了signal这个信号量兼同步锁之后，我们才可能进入这段代码<br />
signal.notify(); // 这里，我们通知signal的待召队列中的某个线程。<br />
<br />
// 如果某个线程等到了这个通知，那个线程就会转到就绪队列中<br />
// 但是本线程仍然继续拥有signal这个同步锁，本线程仍然继续执行<br />
// 嘿嘿，虽然本线程好心通知其他线程，<br />
// 但是，本线程可没有那么高风亮节，放弃到手的同步锁<br />
// 本线程继续执行下面的代码<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &#8230;<br />
}<br />
}<br />
<br />
需要注意的是，signal.notify()的意思。signal.notify()并不是通知signal这个对象本身。而是通知正在等待signal信号量的其他线程。<br />
<br />
以上就是Object的wait()和notify()的基本用法。<br />
实际上，wait()还可以定义等待时间，当线程在某信号量的待召队列中，等到足够长的时间，就会等无可等，无需再等，自己就从待召队列转移到就绪队列中了。<br />
另外，还有一个notifyAll()方法，表示通知待召队列里面的所有线程。<br />
这些细节问题，并不对大局产生影响。<br />
<br />
绿色线程<br />
<br />
绿色线程（Green Thread）是一个相对于操作系统线程（Native Thread）的概念。<br />
操作系统线程（Native
Thread）的意思就是，程序里面的线程会真正映射到操作系统的线程，线程的运行和调度都是由操作系统控制的<br />
绿色线程（Green Thread）的意思是，程序里面的线程不会真正映射到操作系统的线程，而是由语言运行平台自身来调度。<br />
当前版本的Python语言的线程就可以映射到操作系统线程。当前版本的Ruby语言的线程就属于绿色线程，无法映射到操作系统的线程，因此Ruby语言的线程的运行速度比较慢。<br />
难道说，绿色线程要比操作系统线程要慢吗？当然不是这样。事实上，情况可能正好相反。Ruby是一个特殊的例子。线程调度器并不是很成熟。<br />
目前，线程的流行实现模型就是绿色线程。比如，stackless
Python，就引入了更加轻量的绿色线程概念。在线程并发编程方面，无论是运行速度还是并发负载上，都优于Python。<br />
另一个更著名的例子就是ErLang（爱立信公司开发的一种开源语言）。<br />
ErLang的绿色线程概念非常彻底。ErLang的线程不叫Thread，而是叫做Process。这很容易和进程混淆起来。这里要注意区分一下。<br />
ErLang
Process之间根本就不需要同步。因为ErLang语言的所有变量都是final的，不允许变量的值发生任何变化。因此根本就不需要同步。<br />
final变量的另一个好处就是，对象之间不可能出现交叉引用，不可能构成一种环状的关联，对象之间的关联都是单向的，树状的。因此，内存垃圾回收的算法效率也非常高。这就让ErLang能够达到Soft
Real Time（软实时）的效果。这对于一门支持内存垃圾回收的语言来说</p>
</div>
<img src ="http://www.blogjava.net/tinysun/aggbug/331651.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/tinysun/" target="_blank">何克勤</a> 2010-09-10 13:42 <a href="http://www.blogjava.net/tinysun/archive/2010/09/10/331651.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>just-in-time编译器</title><link>http://www.blogjava.net/tinysun/archive/2010/04/24/319257.html</link><dc:creator>何克勤</dc:creator><author>何克勤</author><pubDate>Sat, 24 Apr 2010 04:59:00 GMT</pubDate><guid>http://www.blogjava.net/tinysun/archive/2010/04/24/319257.html</guid><wfw:comment>http://www.blogjava.net/tinysun/comments/319257.html</wfw:comment><comments>http://www.blogjava.net/tinysun/archive/2010/04/24/319257.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/tinysun/comments/commentRss/319257.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/tinysun/services/trackbacks/319257.html</trackback:ping><description><![CDATA[在Java和MS.net Framework中，Just-In-Time编译器所扮演的角色是一个中介者，负责代码翻译和安全检查的任务。 <br />
<br />
在Java或C#等高级语言中，程序员编写的源代码首先被编译种某种格式的中间语言IL（Intermediate Language），IL是一种类似汇编语言，与汇编不同的是，IL运行的是在一个虚拟的机器环境中，或叫做虚拟机，汇编语言运行在一个特定的机器平台中。虚拟机的好处为中间语言提供了一个与平台无关的环境，比如java虚拟机，和CLR（Common Language Runtime），它能够根据所在的平台架构将中间语言翻译中这个平台上的机器语言，从而完成程序的执行过程。担任翻译任务的就是虚拟机中配备的JIT（Just In Time）编译器。与传统编译器不同的是，JIT编译器是边执行边解释，只有需要执行的代码才被翻译成机器语言，那些不会执行到代码被忽略掉的。 <br />
<br />
JIT编译器担任的第二项任务是检查代码的安全性。它必须保证编译出来的机器代码是安全，即程序不会非法访问不属于本身的内存空间或者没有权限访问的空间，这样可以防止恶意的程序修改敏感数据区域。 <br />
<br />
此外，JIT编译器提供了对代码优化的可选功能。 <br />
<br />
下图是Java应用程序的一个程序过程，JIT编译器是JVM的一个组成部分。 <br />
<img src="http://by1.storage.msn.com/y1p9T_4JhVlirsb_XdqIhQDTexk7rCIBwg4p3xS66KZ7wPyRvIUtPkXfgQC2iTbFYxaHPTqO8qhYG6AwzvTRa53oOkeqOeJuwS1?PARTNER=WRITER"  alt="" /> <br />
参考资料： <br />
[1] Microsoft MSDN, Compiling MSIL to Native code. <br />
[2] Simon Robinson, etc. Professional C# (2nd Edition). Wrox Press Inc, March 2002 <br />
[3] http://www.research.ibm.com/trl/projects/jit/index_e.htm <br />
<img src ="http://www.blogjava.net/tinysun/aggbug/319257.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/tinysun/" target="_blank">何克勤</a> 2010-04-24 12:59 <a href="http://www.blogjava.net/tinysun/archive/2010/04/24/319257.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>file的getPath getAbsolutePath和getCanonicalPath的不同</title><link>http://www.blogjava.net/tinysun/archive/2009/03/05/257941.html</link><dc:creator>何克勤</dc:creator><author>何克勤</author><pubDate>Thu, 05 Mar 2009 02:17:00 GMT</pubDate><guid>http://www.blogjava.net/tinysun/archive/2009/03/05/257941.html</guid><wfw:comment>http://www.blogjava.net/tinysun/comments/257941.html</wfw:comment><comments>http://www.blogjava.net/tinysun/archive/2009/03/05/257941.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/tinysun/comments/commentRss/257941.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/tinysun/services/trackbacks/257941.html</trackback:ping><description><![CDATA[<div class="blog_content">file的这几个取得path的方法各有不同，下边说说详细的区别<br />
<br />
概念上的区别：（内容来自jdk，个人感觉这个描述信息，只能让明白的人明白，不明白的人看起来还是有点难度（特别试中文版，英文版稍好些)所以在概念之后我会举例说明。如果感觉看概念很累就跳过直接看例子吧。看完例子回来看概念会好些。<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%; 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: #000000">getPath<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" /></span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;String&nbsp;getPath()将此抽象路径名转换为一个路径名字符串。所得到的字符串使用默认名称分隔符来分隔名称序列中的名称。&nbsp;<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" /><br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" />返回：<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" />此抽象路径名的字符串形式<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" /></span></div>
<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%; 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: #000000">getAbsolutePath<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" /></span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;String&nbsp;getAbsolutePath()返回抽象路径名的绝对路径名字符串。&nbsp;<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" />如果此抽象路径名已经是绝对路径名，则返回该路径名字符串，这与&nbsp;getPath()&nbsp;方法一样。如果此抽象路径名是空的抽象路径名，则返回当前用户目录的路径名字符串，该目录由系统属性&nbsp;user.dir&nbsp;指定。否则，使用与系统有关的方式分析此路径名。在&nbsp;UNIX&nbsp;系统上，通过根据当前用户目录分析某一相对路径名，可使该路径名成为绝对路径名。在&nbsp;Microsoft&nbsp;Windows&nbsp;系统上，通过由路径名指定的当前驱动器目录（如果有）来分析某一相对路径名，可使该路径名成为绝对路径名；否则，可以根据当前用户目录来分析它。&nbsp;<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" /><br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" /><br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" />返回：<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" />绝对路径名字符串，它与此抽象路径名表示相同的文件或目录的&nbsp;<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" />抛出：&nbsp;<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" />SecurityException&nbsp;</span><span style="color: #000000">-</span><span style="color: #000000">&nbsp;如果无法访问所需的系统属性值。<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" />另请参见：<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" />isAbsolute()<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" /></span></div>
<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%; 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: #000000"><span class="hilite1">getCanonicalPath</span><br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" /></span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;String&nbsp;<span class="hilite1">getCanonicalPath</span>()<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">throws</span><span style="color: #000000">&nbsp;IOException返回抽象路径名的规范路径名字符串。&nbsp;<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" />规范路径名是绝对路径名，并且是惟一的。规范路径名的准确定义与系统有关。如有必要，此方法首先将路径名转换成绝对路径名，这与调用&nbsp;getAbsolutePath()&nbsp;方法的效果一样，然后用与系统相关的方式将它映射到其惟一路径名。这通常涉及到从路径名中移除多余的名称（比如&nbsp;</span><span style="color: #000000">"</span><span style="color: #000000">.</span><span style="color: #000000">"</span><span style="color: #000000">&nbsp;和&nbsp;</span><span style="color: #000000">"</span><span style="color: #000000">..</span><span style="color: #000000">"</span><span style="color: #000000">）、分析符号连接（对于&nbsp;UNIX&nbsp;平台），以及将驱动器名转换成标准大小写形式（对于&nbsp;Microsoft&nbsp;Windows&nbsp;平台）。&nbsp;<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" /><br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" />表示现有文件或目录的每个路径名都有一个惟一的规范形式。表示非存在文件或目录的每个路径名也有一个惟一的规范形式。非存在文件或目录路径名的规范形式可能不同于创建文件或目录之后同一路径名的规范形式。同样，现有文件或目录路径名的规范形式可能不同于删除文件或目录之后同一路径名的规范形式。&nbsp;<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" /><br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" /><br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" />返回：<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" />表示与此抽象路径名相同的文件或目录的规范路径名字符串&nbsp;<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" />抛出：&nbsp;<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" />IOException&nbsp;</span><span style="color: #000000">-</span><span style="color: #000000">&nbsp;如果发生&nbsp;I</span><span style="color: #000000">/</span><span style="color: #000000">O&nbsp;错误（可能是因为构造规范路径名需要进行文件系统查询）&nbsp;<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" />SecurityException&nbsp;</span><span style="color: #000000">-</span><span style="color: #000000">&nbsp;如果无法访问所需的系统属性值，或者存在安全管理器，且其&nbsp;SecurityManager.checkRead(java.io.FileDescriptor)&nbsp;方法拒绝对该文件进行读取访问<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" />从以下版本开始：&nbsp;<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" />JDK1.</span><span style="color: #000000">1</span><span style="color: #000000">&nbsp;<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" /></span></div>
<br />
二、例子：<br />
1，getPath()与getAbsolutePath()的区别<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%; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><img id="Codehighlighter1_26_412_Open_Image" alt="" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_26_412_Closed_Image" style="display: none" alt="" src="http://www.blogjava.net/Images/OutliningIndicators/ContractedBlock.gif" align="top" /><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;test1()</span><span id="Codehighlighter1_26_412_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.blogjava.net/Images/dot.gif" /></span><span id="Codehighlighter1_26_412_Open_Text"><span style="color: #000000">{<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;File&nbsp;file1&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;File(</span><span style="color: #000000">"</span><span style="color: #000000">.\\test1.txt</span><span style="color: #000000">"</span><span style="color: #000000">);<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;File&nbsp;file2&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;File(</span><span style="color: #000000">"</span><span style="color: #000000">D:\\workspace\\test\\test1.txt</span><span style="color: #000000">"</span><span style="color: #000000">);<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span style="color: #000000">"</span><span style="color: #000000">-----默认相对路径：取得路径不同------</span><span style="color: #000000">"</span><span style="color: #000000">);<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(file1.getPath());<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(file1.getAbsolutePath());<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span style="color: #000000">"</span><span style="color: #000000">-----默认绝对路径:取得路径相同------</span><span style="color: #000000">"</span><span style="color: #000000">);<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(file2.getPath());<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(file2.getAbsolutePath());<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;}</span></span></div>
<br />
得到的结果：<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%; 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: #000000">-----</span><span style="color: #000000">默认相对路径：取得路径不同</span><span style="color: #000000">------</span><span style="color: #000000"><br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" />.\test1.txt<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" />D:\workspace\test\.\test1.txt<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" /></span><span style="color: #000000">-----</span><span style="color: #000000">默认绝对路径:取得路径相同</span><span style="color: #000000">------</span><span style="color: #000000"><br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" />D:\workspace\test\test1.txt<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" />D:\workspace\test\test1.txt</span></div>
因为getPath()得到的是构造file的时候的路径。<br />
getAbsolutePath()得到的是全路径<br />
如果构造的时候就是全路径那直接返回全路径<br />
如果构造的时候试相对路径，返回当前目录的路径+构造file时候的路径<br />
<br />
2，getAbsolutePath()和<span class="hilite1">getCanonicalPath</span>()的不同<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%; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><img id="Codehighlighter1_43_189_Open_Image" alt="" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_43_189_Closed_Image" style="display: none" alt="" src="http://www.blogjava.net/Images/OutliningIndicators/ContractedBlock.gif" align="top" /><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;test2()&nbsp;</span><span style="color: #0000ff">throws</span><span style="color: #000000">&nbsp;Exception</span><span id="Codehighlighter1_43_189_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.blogjava.net/Images/dot.gif" /></span><span id="Codehighlighter1_43_189_Open_Text"><span style="color: #000000">{<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;File&nbsp;file&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;File(</span><span style="color: #000000">"</span><span style="color: #000000">..\\src\\test1.txt</span><span style="color: #000000">"</span><span style="color: #000000">);<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(file.getAbsolutePath());<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(file.<span class="hilite1">getCanonicalPath</span>());<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;}</span></span></div>
得到的结果<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%; 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: #000000">D:\workspace\test\..\src\test1.txt<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" />D:\workspace\src\test1.txt</span></div>
可以看到CanonicalPath不但是全路径，而且把..或者.这样的符号解析出来。<br />
3,<span class="hilite1">getCanonicalPath</span>()和自己的不同。<br />
就是解释这段话:<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%; 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: #000000">表示现有文件或目录的每个路径名都有一个惟一的规范形式。表示非存在文件或目录的每个路径名也有一个惟一的规范形式。非存在文件或目录路径名的规范形式可能不同于创建文件或目录之后同一路径名的规范形式。同样，现有文件或目录路径名的规范形式可能不同于删除文件或目录之后同一路径名的规范形式。&nbsp;<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" /></span></div>
单下边这段代码是看不到结果的，要配合一定的操作来看。下边操作步骤，同时讲解<br />
<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%; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><img id="Codehighlighter1_43_135_Open_Image" alt="" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_43_135_Closed_Image" style="display: none" alt="" src="http://www.blogjava.net/Images/OutliningIndicators/ContractedBlock.gif" align="top" /><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;test3()&nbsp;</span><span style="color: #0000ff">throws</span><span style="color: #000000">&nbsp;Exception</span><span id="Codehighlighter1_43_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.blogjava.net/Images/dot.gif" /></span><span id="Codehighlighter1_43_135_Open_Text"><span style="color: #000000">{<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;File&nbsp;file&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;File(</span><span style="color: #000000">"</span><span style="color: #000000">D:\\Text.txt</span><span style="color: #000000">"</span><span style="color: #000000">);<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(file.<span class="hilite1">getCanonicalPath</span>());<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;}</span></span></div>
步骤：<br />
确定你的系统是Windows系统。<br />
(1),确定D盘下没有Text.txt这个文件，直接执行这段代码，得到的结果是:<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%; 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: #000000">D:\Text.txt</span></div>
注意这里试大写的Text.txt<br />
(2)在D盘下建立一个文件，名叫text.txt，再次执行代码，得到结果<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%; 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: #000000">D:\text.txt</span></div>
同样的代码得到不同的结果。<br />
同时可以对比getAbsolutePath()看看，这个得到的结果是一样的。<br />
<br />
原因：<br />
window是大小写不敏感的，也就是说在windows上test.txt和Test.txt是一个文件，所以在windows上当文件不存在时，得到的路径就是按照输入的路径。但当文件存在时，就会按照实际的情况来显示。这也就是建立文件后和删除文件后会有不同的原因。文件夹和文件类似。<br />
<br />
三、最后：<br />
1，尝试在linux下执行上边的步骤，两次打印的结果是相同的，因为linux是大小写敏感的系统。<br />
2，手动删掉test.txt,然后尝试执行下边代码<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%; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><img id="Codehighlighter1_43_287_Open_Image" alt="" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_43_287_Closed_Image" style="display: none" alt="" src="http://www.blogjava.net/Images/OutliningIndicators/ContractedBlock.gif" align="top" /><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;test4()&nbsp;</span><span style="color: #0000ff">throws</span><span style="color: #000000">&nbsp;Exception</span><span id="Codehighlighter1_43_287_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.blogjava.net/Images/dot.gif" /></span><span id="Codehighlighter1_43_287_Open_Text"><span style="color: #000000">{<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;File&nbsp;file&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;File(</span><span style="color: #000000">"</span><span style="color: #000000">D:\\Text.txt</span><span style="color: #000000">"</span><span style="color: #000000">);<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(file.<span class="hilite1">getCanonicalPath</span>());<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;File&nbsp;file1&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;File(</span><span style="color: #000000">"</span><span style="color: #000000">D:\\text.txt</span><span style="color: #000000">"</span><span style="color: #000000">);<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;file1.createNewFile();<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;file&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;File(</span><span style="color: #000000">"</span><span style="color: #000000">D:\\Text.txt</span><span style="color: #000000">"</span><span style="color: #000000">);<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(file.<span class="hilite1">getCanonicalPath</span>());<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;}</span></span></div>
<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%; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><img id="Codehighlighter1_43_203_Open_Image" alt="" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_43_203_Closed_Image" style="display: none" alt="" src="http://www.blogjava.net/Images/OutliningIndicators/ContractedBlock.gif" align="top" /><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;test3()&nbsp;</span><span style="color: #0000ff">throws</span><span style="color: #000000">&nbsp;Exception</span><span id="Codehighlighter1_43_203_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.blogjava.net/Images/dot.gif" /></span><span id="Codehighlighter1_43_203_Open_Text"><span style="color: #000000">{<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;File&nbsp;file1&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;File(</span><span style="color: #000000">"</span><span style="color: #000000">D:\\text.txt</span><span style="color: #000000">"</span><span style="color: #000000">);<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;file1.createNewFile();<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;File&nbsp;file&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;File(</span><span style="color: #000000">"</span><span style="color: #000000">D:\\Text.txt</span><span style="color: #000000">"</span><span style="color: #000000">);<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(file.<span class="hilite1">getCanonicalPath</span>());<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;}</span></span></div>
执行上边两个函数，看看结果，然后思考一下为什么？<br />
1,的结果是两个大写，<br />
2,的结果试两个小写<br />
连续两个大写的，是否跟上边的矛盾 ？<br />
这是因为虚拟机的缓存机制造成的。第一次File&nbsp;file&nbsp;<span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;File(</span><span style="color: #000000">"</span><span style="color: #000000">D:\\Text.txt</span><span style="color: #000000">"</span><span style="color: #000000">);决定了结果.</span> <br />
<br />
来至javaeye</div>
<img src ="http://www.blogjava.net/tinysun/aggbug/257941.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/tinysun/" target="_blank">何克勤</a> 2009-03-05 10:17 <a href="http://www.blogjava.net/tinysun/archive/2009/03/05/257941.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>protected访问权限</title><link>http://www.blogjava.net/tinysun/archive/2009/02/21/255973.html</link><dc:creator>何克勤</dc:creator><author>何克勤</author><pubDate>Sat, 21 Feb 2009 11:39:00 GMT</pubDate><guid>http://www.blogjava.net/tinysun/archive/2009/02/21/255973.html</guid><wfw:comment>http://www.blogjava.net/tinysun/comments/255973.html</wfw:comment><comments>http://www.blogjava.net/tinysun/archive/2009/02/21/255973.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/tinysun/comments/commentRss/255973.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/tinysun/services/trackbacks/255973.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 1、protected的类、类属变量及方法，包内的任何类，及包外的那些继承了此类的子类才能访问；注意：子类如处于不同的包，则相互间不能访问继承自父类的方法。所有不能访问的方法都已经被注释：&nbsp;&nbsp;1package&nbsp;packageA;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2&nbsp;&nbsp;&nbsp;&nbsp;3publi...&nbsp;&nbsp;<a href='http://www.blogjava.net/tinysun/archive/2009/02/21/255973.html'>阅读全文</a><img src ="http://www.blogjava.net/tinysun/aggbug/255973.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/tinysun/" target="_blank">何克勤</a> 2009-02-21 19:39 <a href="http://www.blogjava.net/tinysun/archive/2009/02/21/255973.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关联、组合、聚合、依赖关系比较</title><link>http://www.blogjava.net/tinysun/archive/2009/02/21/255957.html</link><dc:creator>何克勤</dc:creator><author>何克勤</author><pubDate>Sat, 21 Feb 2009 07:39:00 GMT</pubDate><guid>http://www.blogjava.net/tinysun/archive/2009/02/21/255957.html</guid><wfw:comment>http://www.blogjava.net/tinysun/comments/255957.html</wfw:comment><comments>http://www.blogjava.net/tinysun/archive/2009/02/21/255957.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/tinysun/comments/commentRss/255957.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/tinysun/services/trackbacks/255957.html</trackback:ping><description><![CDATA[<span style="font-family: 宋体">&nbsp;&nbsp;&nbsp; 类之间的关系</span><span style="font-family: 宋体">种类：</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif'"> Generalization(</span><span style="font-family: 宋体">泛化</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif'">)</span><span style="font-family: 宋体">，</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif'">Dependency(</span><span style="font-family: 宋体">依赖关系</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif'">)</span><span style="font-family: 宋体">、</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif'">Association(</span><span style="font-family: 宋体">关联关系</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif'">)</span><span style="font-family: 宋体">、</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif'">Aggregation(</span><span style="font-family: 宋体">聚合关系</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif'">)、</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif'">Composition(</span><span style="font-family: 宋体">合成关系</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif'">)</span><span style="font-family: 宋体">。<br />
<span style="font-family: 宋体">&nbsp;&nbsp;&nbsp; 其中</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif'">Aggregation(</span><span style="font-family: 宋体">聚合关系</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif'">)</span><span style="font-family: 宋体">、</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif'">Composition(</span><span style="font-family: 宋体">合成关系</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif'">)</span><span style="font-family: 宋体">属于</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif'">Association(</span><span style="font-family: 宋体">关联关系</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif'">)</span><span style="font-family: 宋体">，是特殊的</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif'">Association</span><span style="font-family: 宋体">关联关系。<span lang="EN-US" style="font-family: 'Verdana','sans-serif'">Generalization(</span><span style="font-family: 宋体">泛化</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif'">)</span><span style="font-family: 宋体">表现为继承或实现关系</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif'">(is a)</span><span style="font-family: 宋体">。具体形式为类与类之间的继承关系，接口与接口之间的继承关系，类对接口的实现关系。<br />
</span></span></span><span lang="EN-US" style="font-family: 'Verdana','sans-serif'"><O:P>
<div align="left"><img alt="" src="http://www.blogjava.net/images/blogjava_net/tinysun/isa.jpg" border="0" /><br />
&nbsp;&nbsp;&nbsp;&nbsp; <span lang="EN-US" style="font-family: 'Verdana','sans-serif'">Association</span><span style="font-family: 宋体">关联 系表现为变量</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif'">(has a )</span><span style="font-family: 宋体">。类与类之间的联接，它使一个类知道另一个类的属性和方法。例如如果</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif'">A</span><span style="font-family: 宋体">依赖于</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif'">B</span><span style="font-family: 宋体">，则</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif'">B</span><span style="font-family: 宋体">体现为</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif'">A</span><span style="font-family: 宋体">的全局变量。关联关系有双向关联和单向关联。双向关联：两个类都知道另一个类的公共属性和操作。单向关联：只有一个类知道另外一个类的公共属性和操作。大多数关联应该是单向的，单向关系更容易建立和维护，有助于寻找可服用的类。<br />
<br />
<img alt="" src="http://www.blogjava.net/images/blogjava_net/tinysun/association.jpg" border="0" /><br />
<br />
</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif'">&nbsp;&nbsp;&nbsp; Aggregat ion(</span><span style="font-family: 宋体">聚合关系</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif'">) </span><span style="font-family: 宋体">是关联关系的一种，是强的关联关系。聚合关系是整体和个体的关系。普通关联关系的两个类处于同一层次上，而聚合关系的两个类处于不同的层次，一个是整体，一个是部分。同时，是一种弱的&#8220;拥有&#8221;关系。体现的是</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif'">A</span><span style="font-family: 宋体">对象可以包含</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif'">B</span><span style="font-family: 宋体">对象，但</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif'">B</span><span style="font-family: 宋体">对象不是</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif'">A</span><span style="font-family: 宋体">对象的组成部分。具体表现为，如果</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif'">A</span><span style="font-family: 宋体">由</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif'">B</span><span style="font-family: 宋体">聚合成，表现为</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif'">A</span><span style="font-family: 宋体">包含有</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif'">B</span><span style="font-family: 宋体">的全局对象，但是</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif'">B</span><span style="font-family: 宋体">对象可以不在</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif'">A</span><span style="font-family: 宋体">创建的时刻创建。<br />
<br />
<img alt="" src="http://www.blogjava.net/images/blogjava_net/tinysun/aggregation.jpg" border="0" /><br />
<br />
</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif'">&nbsp;&nbsp;&nbsp; Composition(</span><span style="font-family: 宋体">组合关系</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif'">)</span><span style="font-family: 宋体">是关联关系的一种，是比聚合关系强的关系。它要求普通的聚合关系中代表整体的对象负责代表部分的对象的生命周期。</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif'">Composition(</span><span style="font-family: 宋体">组合关系</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif'">)</span><span style="font-family: 宋体">是一种强的&#8220;拥有&#8221;关系，体现了严格的部分和整体的关系，部分和整体的生命周期一致。如果</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif'">A</span><span style="font-family: 宋体">由</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif'">B</span><span style="font-family: 宋体">组成，表现为</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif'">A</span><span style="font-family: 宋体">包含有</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif'">B</span><span style="font-family: 宋体">的全局对象，并且</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif'">B</span><span style="font-family: 宋体">对象在</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif'">A</span><span style="font-family: 宋体">创建的时刻创建。<br />
<img alt="" src="http://www.blogjava.net/images/blogjava_net/tinysun/composition.jpg" border="0" /><br />
<br />
<span lang="EN-US" style="font-family: 'Verdana','sans-serif'">Dependency(</span><span style="font-family: 宋体">依赖关系</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif'">)</span><span style="font-family: 宋体">表现为函数中的参数</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif'">(use a)</span><span style="font-family: 宋体">。是类与类之间的连接，表示一个类依赖于另一个类的定义，其中一个类的变化将影响另外一个类。例如如果</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif'">A</span><span style="font-family: 宋体">依赖于</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif'">B</span><span style="font-family: 宋体">，则</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif'">B</span><span style="font-family: 宋体">体现为局部变量，方法的参数、或静态方法的调用。</span><br />
<br />
<img alt="" src="http://www.blogjava.net/images/blogjava_net/tinysun/dependency.jpg" border="0" /><br />
<br />
来至于<a href="http://blog.csdn.net/maybehelios/archive/2008/01/12/2038685.aspx" target="_blank">http://blog.csdn.net/maybehelios/archive/2008/01/12/2038685.aspx</a> <br />
</span><br />
</div>
</O:P></span>
<img src ="http://www.blogjava.net/tinysun/aggbug/255957.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/tinysun/" target="_blank">何克勤</a> 2009-02-21 15:39 <a href="http://www.blogjava.net/tinysun/archive/2009/02/21/255957.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>比较分析Vector、ArrayList和hashtable hashmap数据结构</title><link>http://www.blogjava.net/tinysun/archive/2009/02/19/255626.html</link><dc:creator>何克勤</dc:creator><author>何克勤</author><pubDate>Thu, 19 Feb 2009 10:43:00 GMT</pubDate><guid>http://www.blogjava.net/tinysun/archive/2009/02/19/255626.html</guid><wfw:comment>http://www.blogjava.net/tinysun/comments/255626.html</wfw:comment><comments>http://www.blogjava.net/tinysun/archive/2009/02/19/255626.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/tinysun/comments/commentRss/255626.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/tinysun/services/trackbacks/255626.html</trackback:ping><description><![CDATA[转至http://blog.csdn.net/HITCCBoy/archive/2008/10/09/3040921.aspx<br />
<br />
<div class="cnt">线性表，链表，哈希表是常用的数据结构，在进行Java开发时，JDK已经为我们提供了一系列相应的类来实现基本的数据结构。这些类均在java.util包中。本文试图通过简单的描述，向读者阐述各个类的作用以及如何正确使用这些类。
<p><em>Collection</em><br />
├<em>List</em><br />
│├LinkedList<br />
│├ArrayList<br />
│└Vector<br />
│　└Stack<br />
└<em>Set</em><br />
<em>Map</em><br />
├Hashtable<br />
├HashMap<br />
└WeakHashMap</p>
<p><strong><font color="#0000ff">Collection接口</font></strong><br />
　　Collection是最基本的集合接口，一个Collection代表一组Object，即Collection的元素（Elements）。一些Collection允许相同的元素而另一些不行。一些能排序而另一些不行。Java SDK不提供直接继承自Collection的类，Java SDK提供的类都是继承自Collection的&#8220;子接口&#8221;如List和Set。<br />
　　所有实现Collection接口的类都必须提供两个标准的构造函数：无参数的构造函数用于创建一个空的Collection，有一个Collection参数的构造函数用于创建一个新的Collection，这个新的Collection与传入的Collection有相同的元素。后一个构造函数允许用户复制一个Collection。<br />
　　如何遍历Collection中的每一个元素？不论Collection的实际类型如何，它都支持一个iterator()的方法，该方法返回一个迭代子，使用该迭代子即可逐一访问Collection中每一个元素。典型的用法如下：<br />
<font face="Courier New" color="#336666">　　　　Iterator it = collection.iterator(); // 获得一个迭代子<br />
　　　　while(it.hasNext()) {<br />
　　　　　　Object obj = it.next(); // 得到下一个元素<br />
　　　　}</font><br />
　　由Collection接口派生的两个接口是List和Set。</p>
<p><font color="#0000ff"><strong>List接口</strong></font><br />
　　List是有序的Collection，使用此接口能够精确的控制每个元素插入的位置。用户能够使用索引（元素在List中的位置，类似于数组下标）来访问List中的元素，这类似于Java的数组。<br />
和下面要提到的Set不同，List允许有相同的元素。<br />
　　除了具有Collection接口必备的iterator()方法外，List还提供一个listIterator()方法，返回一个ListIterator接口，和标准的Iterator接口相比，ListIterator多了一些add()之类的方法，允许添加，删除，设定元素，还能向前或向后遍历。<br />
　　实现List接口的常用类有LinkedList，ArrayList，Vector和Stack。</p>
<p><font color="#0000ff"><strong>LinkedList类</strong></font><br />
　　LinkedList实现了List接口，允许null元素。此外LinkedList提供额外的get，remove，insert方法在LinkedList的首部或尾部。这些操作使LinkedList可被用作堆栈（stack），队列（queue）或双向队列（deque）。<br />
　　注意LinkedList没有同步方法。如果多个线程同时访问一个List，则必须自己实现访问同步。一种解决方法是在创建List时构造一个同步的List：<br />
<font face="Courier New" color="#336666">　　　　List list = Collections.synchronizedList(new LinkedList(...));</font></p>
<p><font color="#0000ff"><strong>ArrayList类</strong></font><br />
　　ArrayList实现了可变大小的数组。它允许所有元素，包括null。ArrayList没有同步。<br />
size，isEmpty，get，set方法运行时间为常数。但是add方法开销为分摊的常数，添加n个元素需要O(n)的时间。其他的方法运行时间为线性。<br />
　　每个ArrayList实例都有一个容量（Capacity），即用于存储元素的数组的大小。这个容量可随着不断添加新元素而自动增加，但是增长算法并没有定义。当需要插入大量元素时，在插入前可以调用ensureCapacity方法来增加ArrayList的容量以提高插入效率。<br />
　　和LinkedList一样，ArrayList也是非同步的（unsynchronized）。</p>
<p><font color="#0000ff"><strong>Vector类</strong></font><br />
　　Vector非常类似ArrayList，但是Vector是同步的。由Vector创建的Iterator，虽然和ArrayList创建的Iterator是同一接口，但是，因为Vector是同步的，当一个Iterator被创建而且正在被使用，另一个线程改变了Vector的状态（例如，添加或删除了一些元素），这时调用Iterator的方法时将抛出ConcurrentModificationException，因此必须捕获该异常。</p>
<p><strong><font color="#0000ff">Stack 类</font></strong><br />
　　Stack继承自Vector，实现一个后进先出的堆栈。Stack提供5个额外的方法使得Vector得以被当作堆栈使用。基本的push和pop方法，还有peek方法得到栈顶的元素，empty方法测试堆栈是否为空，search方法检测一个元素在堆栈中的位置。Stack刚创建后是空栈。</p>
<p><font color="#0000ff"><strong>Set接口</strong></font><br />
　　Set是一种不包含重复的元素的Collection，即任意的两个元素e1和e2都有e1.equals(e2)=false，Set最多有一个null元素。<br />
　　很明显，Set的构造函数有一个约束条件，传入的Collection参数不能包含重复的元素。<br />
　　请注意：必须小心操作可变对象（Mutable Object）。如果一个Set中的可变元素改变了自身状态导致Object.equals(Object)=true将导致一些问题。</p>
<p><font color="#0000ff"><strong>Map接口</strong></font><br />
　　请注意，Map没有继承Collection接口，Map提供key到value的映射。一个Map中不能包含相同的key，每个key只能映射一个value。Map接口提供3种集合的视图，Map的内容可以被当作一组key集合，一组value集合，或者一组key-value映射。</p>
<p><font color="#0000ff"><strong>Hashtable类</strong></font><br />
　　Hashtable继承Map接口，实现一个key-value映射的哈希表。任何非空（non-null）的对象都可作为key或者value。<br />
　　添加数据使用put(key, value)，取出数据使用get(key)，这两个基本操作的时间开销为常数。<br />
Hashtable通过initial capacity和load factor两个参数调整性能。通常缺省的load factor 0.75较好地实现了时间和空间的均衡。增大load factor可以节省空间但相应的查找时间将增大，这会影响像get和put这样的操作。<br />
使用Hashtable的简单示例如下，将1，2，3放到Hashtable中，他们的key分别是&#8221;one&#8221;，&#8221;two&#8221;，&#8221;three&#8221;：<br />
<font face="Courier New" color="#336666">　　　　Hashtable numbers = new Hashtable();<br />
　　　　numbers.put(&#8220;one&#8221;, new Integer(1));<br />
　　　　numbers.put(&#8220;two&#8221;, new Integer(2));<br />
　　　　numbers.put(&#8220;three&#8221;, new Integer(3));</font><br />
　　要取出一个数，比如2，用相应的key：<br />
<font face="Courier New" color="#336666">　　　　Integer n = (Integer)numbers.get(&#8220;two&#8221;);<br />
　　　　System.out.println(&#8220;two = &#8221; + n);</font><br />
　　由于作为key的对象将通过计算其散列函数来确定与之对应的value的位置，因此任何作为key的对象都必须实现hashCode和equals方法。hashCode和equals方法继承自根类Object，如果你用自定义的类当作key的话，要相当小心，按照散列函数的定义，如果两个对象相同，即obj1.equals(obj2)=true，则它们的hashCode必须相同，但如果两个对象不同，则它们的hashCode不一定不同，如果两个不同对象的hashCode相同，这种现象称为冲突，冲突会导致操作哈希表的时间开销增大，所以尽量定义好的hashCode()方法，能加快哈希表的操作。<br />
　　如果相同的对象有不同的hashCode，对哈希表的操作会出现意想不到的结果（期待的get方法返回null），要避免这种问题，只需要牢记一条：要同时复写equals方法和hashCode方法，而不要只写其中一个。<br />
　　Hashtable是同步的。</p>
<p><strong><font color="#0000ff">HashMap类</font></strong><br />
　　HashMap和Hashtable类似，不同之处在于HashMap是非同步的，并且允许null，即null value和null key。，但是将HashMap视为Collection时（values()方法可返回Collection），其迭代子操作时间开销和HashMap的容量成比例。因此，如果迭代操作的性能相当重要的话，不要将HashMap的初始化容量设得过高，或者load factor过低。</p>
<p><font color="#0000ff"><strong>WeakHashMap类</strong></font><br />
　　WeakHashMap是一种改进的HashMap，它对key实行&#8220;弱引用&#8221;，如果一个key不再被外部所引用，那么该key可以被GC回收。</p>
<p><font color="#ff0000"><strong>总结</strong></font><br />
　　如果涉及到堆栈，队列等操作，应该考虑用List，对于需要快速插入，删除元素，应该使用LinkedList，如果需要快速随机访问元素，应该使用ArrayList。<br />
　　如果程序在单线程环境中，或者访问仅仅在一个线程中进行，考虑非同步的类，其效率较高，如果多个线程可能同时操作一个类，应该使用同步的类。<br />
　　要特别注意对哈希表的操作，作为key的对象要正确复写equals和hashCode方法。<br />
　　尽量返回接口而非实际的类型，如返回List而非ArrayList，这样如果以后需要将ArrayList换成LinkedList时，客户端代码不用改变。这就是针对抽象编程。</p>
<p>同步性<br />
<font size="+0">Vector</font>是同步的。这个类中的一些方法保证了<font size="+0">Vector</font>中的对象是线程安全的。而ArrayList则是异步的，因此ArrayList中的对象并不是线程安全的。因为同步的要求会影响执行的效率，所以如果你不需要线程安全的集合那么使用ArrayList是一个很好的选择，这样可以避免由于同步带来的不必要的性能开销。<br />
数据增长<br />
从内部实现机制来讲ArrayList和<font size="+0">Vector</font>都是使用数组(Array)来控制集合中的对象。当你向这两种类型中增加元素的时候，如果元素的数目超出了内部数组目前的长度它们都需要扩展内部数组的长度，<font size="+0">Vector</font>缺省情况下自动增长原来一倍的数组长度，ArrayList是原来的50%,所以最后你获得的这个集合所占的空间总是比你实际需要的要大。所以如果你要在集合中保存大量的数据那么使用<font size="+0">Vector</font>有一些优势，因为你可以通过设置集合的初始化大小来避免不必要的资源开销。<br />
使用模式<br />
在ArrayList和<font size="+0">Vector</font>中，从一个指定的位置（通过索引）查找数据或是在集合的末尾增加、移除一个元素所花费的时间是一样的，这个时间我们用O(1)表示。但是，如果在集合的其他位置增加或移除元素那么花费的时间会呈线形增长：O(n-i)，其中n代表集合中元素的个数，i代表元素增加或移除元素的索引位置。为什么会这样呢？以为在进行上述操作的时候集合中第i和第i个元素之后的所有元素都要执行位移的操作。这一切意味着什么呢？<br />
这意味着，你只是查找特定位置的元素或只在集合的末端增加、移除元素，那么使用<font size="+0">Vector</font>或ArrayList都可以。如果是其他操作，你最好选择其他的集合操作类。比如，LinkList集合类在增加或移除集合中任何位置的元素所花费的时间都是一样的?O(1)，但它在索引一个元素的使用缺比较慢－O(i),其中i是索引的位置.使用ArrayList也很容易，因为你可以简单的使用索引来代替创建iterator对象的操作。LinkList也会为每个插入的元素创建对象，所有你要明白它也会带来额外的开销。<br />
最后，在《Practical Java》一书中Peter Haggar建议使用一个简单的数组（Array）来代替<font size="+0">Vector</font>或ArrayList。尤其是对于执行效率要求高的程序更应如此。因为使用数组(Array)避免了同步、额外的方法调用和不必要的重新分配空间的操作。</p>
<p>&nbsp;</p>
<div style="margin: 0mm 0mm 0pt; text-indent: 22pt"><font color="#000000"><span style="font-size: 11pt; color: #333333">Vector</span><span style="font-size: 11pt; color: #333333">和</span><span style="font-size: 11pt; color: #333333">Hashtable</span><span style="font-size: 11pt; color: #333333">都是</span><span style="font-size: 11pt; color: #333333">jdk1.0</span><span style="font-size: 11pt; color: #333333">的就有了的。后来到</span><span style="font-size: 11pt; color: #333333">java2</span><span style="font-size: 11pt; color: #333333">后，</span><span style="font-size: 11pt; color: #333333">java</span><span style="font-size: 11pt; color: #333333">的容器框架改</span><span style="font-size: 11pt; color: #333333">动</span><span style="font-size: 11pt; color: #333333">很多，</span><span style="font-size: 11pt; color: #333333">为</span><span style="font-size: 11pt; color: #333333">了兼容，就</span><span style="font-size: 11pt; color: #333333">让</span><span style="font-size: 11pt; color: #333333">Vector</span><span style="font-size: 11pt; color: #333333">和</span><span style="font-size: 11pt; color: #333333">Hashtable</span><span style="font-size: 11pt; color: #333333">分</span><span style="font-size: 11pt; color: #333333">别实现</span><span style="font-size: 11pt; color: #333333">了新的容器框架的</span><span style="font-size: 11pt; color: #333333">List</span><span style="font-size: 11pt; color: #333333">和</span><span style="font-size: 11pt; color: #333333">Map</span><span style="font-size: 11pt; color: #333333">。</span><span style="font-size: 11pt; color: #333333">ArrayList</span><span style="font-size: 11pt; color: #333333">和</span><span style="font-size: 11pt; color: #333333">HashMap</span><span style="font-size: 11pt; color: #333333">都是</span><span style="font-size: 11pt; color: #333333">java2(</span><span style="font-size: 11pt; color: #333333">也就是</span><span style="font-size: 11pt; color: #333333">jdk1.2)</span><span style="font-size: 11pt; color: #333333">后才有的。</span></font></div>
<div style="margin: 0mm 0mm 0pt; text-indent: 22pt"><font color="#000000"><span style="font-size: 11pt">1. </span><span style="font-size: 11pt">安全、效率方面：如果要</span><span style="font-size: 11pt">实现</span><span style="font-size: 11pt">同</span><span style="font-size: 11pt">步</span><span style="font-size: 11pt">安全，</span><span style="font-size: 11pt">则</span><span style="font-size: 11pt">要用</span><span style="font-size: 11pt; color: #333333">Vector</span><span style="font-size: 11pt; color: #333333">和</span><span style="font-size: 11pt; color: #333333">Hashtable</span><span style="font-size: 11pt">，否</span><span style="font-size: 11pt">则则</span><span style="font-size: 11pt">用</span><span style="font-size: 11pt; color: #333333">ArrayList</span><span style="font-size: 11pt; color: #333333">和</span><span style="font-size: 11pt; color: #333333">HashMap</span><span style="font-size: 11pt">，因</span><span style="font-size: 11pt">为</span><span style="font-size: 11pt; color: #333333">ArrayList</span><span style="font-size: 11pt; color: #333333">和</span><span style="font-size: 11pt; color: #333333">HashMap</span><span style="font-size: 11pt">不考</span><span style="font-size: 11pt">虑</span><span style="font-size: 11pt">同</span><span style="font-size: 11pt">步</span><span style="font-size: 11pt">安全的</span><span style="font-size: 11pt">问题</span><span style="font-size: 11pt">，所以效率要高些</span><span style="font-size: 11pt; color: #333333">。但</span><span style="font-size: 11pt; color: #333333">Collections</span><span style="font-size: 11pt; color: #333333">类</span><span style="font-size: 11pt; color: #333333">可以解决</span><span style="font-size: 11pt; color: #333333">这</span><span style="font-size: 11pt; color: #333333">个</span><span style="font-size: 11pt; color: #333333">问题</span><span style="font-size: 11pt; color: #333333">。</span></font></div>
<div style="margin: 0mm 0mm 0pt 27.5pt; text-indent: -27.5pt"><span style="font-size: 11pt; color: #333333"><font color="#000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Collections.synchronizedList<br />
Collections.synchronizedMap</font></span></div>
<div style="margin: 0mm 0mm 0pt"><font color="#000000"><span style="font-size: 11pt; color: #333333">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="font-size: 11pt">2. </span><span style="font-size: 11pt">资</span><span style="font-size: 11pt">源方面：当两者的容量已</span><span style="font-size: 11pt">满时</span><span style="font-size: 11pt">，它</span><span style="font-size: 11pt">们</span><span style="font-size: 11pt">都会自</span><span style="font-size: 11pt">动</span><span style="font-size: 11pt">增</span><span style="font-size: 11pt">长</span><span style="font-size: 11pt">其容量，但</span><span style="font-size: 11pt">Vector</span><span style="font-size: 11pt">是按其容量的一倍增</span><span style="font-size: 11pt">长</span><span style="font-size: 11pt">，而</span><span style="font-size: 11pt">ArrayList</span><span style="font-size: 11pt">则</span><span style="font-size: 11pt">按其容量的</span><span style="font-size: 11pt">50%</span><span style="font-size: 11pt">增加，所以</span><span style="font-size: 11pt">Vector</span><span style="font-size: 11pt">更能</span><span style="font-size: 11pt">节</span><span style="font-size: 11pt">省</span><span style="font-size: 11pt">资</span><span style="font-size: 11pt">源。</span></font></div>
<div style="margin: 0mm 0mm 0pt"><font color="#000000"><span style="font-size: 11pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3.</span><span style="font-size: 11pt">迭代器：</span><span style="font-size: 11pt; color: #333333">Vector</span><span style="font-size: 11pt; color: #333333">和</span><span style="font-size: 11pt; color: #333333">Hashtable</span><span style="font-size: 11pt">使用Enumeration，</span><span style="font-size: 11pt; color: #333333">ArrayList</span><span style="font-size: 11pt; color: #333333">和</span><span style="font-size: 11pt; color: #333333">HashMap</span><span style="font-size: 11pt">使用Iterator</span></font></div>
<div style="margin: 0mm 0mm 0pt"></div>
<div style="margin: 0mm 0mm 0pt"><font color="#000000"><span style="font-size: 11pt; color: #333333">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="font-size: 11pt; color: #333333">ARRAY</span><span style="font-size: 11pt; color: #333333">是必</span><span style="font-size: 11pt; color: #333333">须</span><span style="font-size: 11pt; color: #333333">在声明的</span><span style="font-size: 11pt; color: #333333">时</span><span style="font-size: 11pt; color: #333333">候</span><span style="font-size: 11pt; color: #333333">说</span><span style="font-size: 11pt; color: #333333">明</span><span style="font-size: 11pt; color: #333333">长</span><span style="font-size: 11pt; color: #333333">度</span><span style="font-size: 11pt; color: #333333">的</span><span style="font-size: 11pt; color: #333333">;</span><span style="font-size: 11pt; color: #333333"> ARRYLIST</span><span style="font-size: 11pt; color: #333333">也是和</span><span style="font-size: 11pt; color: #333333">Vector</span><span style="font-size: 11pt; color: #333333">类</span><span style="font-size: 11pt; color: #333333">似</span><span style="font-size: 11pt; color: #333333">,</span><span style="font-size: 11pt; color: #333333">可以自</span><span style="font-size: 11pt; color: #333333">动</span><span style="font-size: 11pt; color: #333333">增加</span><span style="font-size: 11pt; color: #333333">长</span><span style="font-size: 11pt; color: #333333">度</span><span style="font-size: 11pt; color: #333333">的</span><span style="font-size: 11pt; color: #333333">。</span></font></div>
<div style="margin: 0mm 0mm 0pt"><font color="#000000"><span style="font-size: 11pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; List</span><span style="font-size: 11pt">和</span><span style="font-size: 11pt">Set</span><span style="font-size: 11pt">的区</span><span style="font-size: 11pt">别</span><span style="font-size: 11pt">：</span></font></div>
<div style="margin: 0mm 0mm 0pt; text-indent: 22pt"><font color="#000000"><span style="font-size: 11pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; List</span><span style="font-size: 11pt">用来</span><span style="font-size: 11pt">处</span><span style="font-size: 11pt">理序列，而</span><span style="font-size: 11pt">Set</span><span style="font-size: 11pt">用来</span><span style="font-size: 11pt">处</span><span style="font-size: 11pt">理集</span><span style="font-size: 11pt">。</span></font></div>
<div style="margin: 0mm 0mm 0pt; text-indent: 22pt"><font color="#000000"><span style="font-size: 11pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; List中的内容可以重</span><span style="font-size: 11pt">复</span><span style="font-size: 11pt">，而</span><span style="font-size: 11pt">Set</span><span style="font-size: 11pt">则</span><span style="font-size: 11pt">不行</span><span style="font-size: 11pt">。</span></font></div>
<div style="margin: 0mm 0mm 0pt"><font color="#000000"><span style="font-size: 11pt; color: #333333">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Vecto</span><span style="font-size: 11pt; color: #333333">r</span><span style="font-size: 11pt; color: #333333">，</span><span style="font-size: 11pt; color: #333333">ArrayList</span><span style="font-size: 11pt; color: #333333">和</span><span style="font-size: 11pt; color: #333333">Hashtable</span><span style="font-size: 11pt; color: #333333">，</span><span style="font-size: 11pt; color: #333333">HashMap</span><span style="font-size: 11pt; color: #333333">的区别：</span></font></div>
<div style="margin: 0mm 0mm 0pt"><font color="#000000"><span style="font-size: 11pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.</span><span style="font-size: 11pt; color: #333333">Vecto</span><span style="font-size: 11pt; color: #333333">r</span><span style="font-size: 11pt; color: #333333">和</span><span style="font-size: 11pt; color: #333333">ArrayList</span><span style="font-size: 11pt; color: #333333">是数值联系对象。按照插入的顺序进行排列，可以有重复值。</span></font></div>
<div style="margin: 0mm 0mm 0pt"><font color="#000000"><span style="font-size: 11pt; color: #333333">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.</span><span style="font-size: 11pt; color: #333333">Hashtable</span><span style="font-size: 11pt; color: #333333">和</span><span style="font-size: 11pt; color: #333333">HashMap</span><span style="font-size: 11pt; color: #333333">是对象联系对象。按照自己的排列方式进行排序，不可以有重复值。</span></font></div>
<div style="margin: 0mm 0mm 0pt"><font color="#000000"><span style="font-size: 11pt; color: #333333">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="font-size: 11pt; color: #333333">HashMap：</span><span style="font-size: 11pt; color: #333333">继</span><span style="font-size: 11pt; color: #333333">承了</span><span style="font-size: 11pt; color: #333333">Map接口，</span><span style="font-size: 11pt; color: #333333">实现</span><span style="font-size: 11pt; color: #333333">用</span><span style="font-size: 11pt; color: #333333">Keys来存</span><span style="font-size: 11pt; color: #333333">储</span><span style="font-size: 11pt; color: #333333">和</span><span style="font-size: 11pt; color: #333333">访问</span><span style="font-size: 11pt; color: #333333">Values，Keys和Values都可以</span><span style="font-size: 11pt; color: #333333">为</span><span style="font-size: 11pt; color: #333333">空，它与</span><span style="font-size: 11pt; color: #333333">Hashtable</span><span style="font-size: 11pt; color: #333333">类</span><span style="font-size: 11pt; color: #333333">的区</span><span style="font-size: 11pt; color: #333333">别</span><span style="font-size: 11pt; color: #333333">在于</span><span style="font-size: 11pt; color: #333333">Hashtable</span><span style="font-size: 11pt; color: #333333">类</span><span style="font-size: 11pt; color: #333333">的</span><span style="font-size: 11pt; color: #333333">Keys不能</span><span style="font-size: 11pt; color: #333333">为</span><span style="font-size: 11pt; color: #333333">null,</span></font></div>
<div style="margin: 0mm 0mm 0pt"><font color="#000000"><span style="font-size: 11pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="font-size: 11pt; color: #333333">Vector</span><span style="font-size: 11pt; color: #333333">内部</span><span style="font-size: 11pt; color: #333333">实际</span><span style="font-size: 11pt; color: #333333">是以</span><span style="font-size: 11pt; color: #333333">Array</span><span style="font-size: 11pt; color: #333333">实现</span><span style="font-size: 11pt; color: #333333">的，也通</span><span style="font-size: 11pt; color: #333333">过</span><span style="font-size: 11pt; color: #333333">元素的整数索引来</span><span style="font-size: 11pt; color: #333333">访问</span><span style="font-size: 11pt; color: #333333">元素，但它只能存放</span><span style="font-size: 11pt; color: #333333">j</span><span style="font-size: 11pt; color: #333333">ava.lang.Object</span><span style="font-size: 11pt; color: #333333">对</span><span style="font-size: 11pt; color: #333333">象，不能用于存放基本</span><span style="font-size: 11pt; color: #333333">类</span><span style="font-size: 11pt; color: #333333">型数据，比如要存放一个整数</span><span style="font-size: 11pt; color: #333333">10,</span><span style="font-size: 11pt; color: #333333">得用</span><span style="font-size: 11pt; color: #333333">new Integer(10)</span><span style="font-size: 11pt; color: #333333">构造出一个</span><span style="font-size: 11pt; color: #333333">Integer</span><span style="font-size: 11pt; color: #333333">包装</span><span style="font-size: 11pt; color: #333333">类对</span><span style="font-size: 11pt; color: #333333">象再放</span><span style="font-size: 11pt; color: #333333">进</span><span style="font-size: 11pt; color: #333333">去。</span></font></div>
<div style="margin: 0mm 0mm 0pt"></div>
<div style="margin: 0mm 0mm 0pt"></div>
<div style="margin: 0mm 0mm 0pt">还有一点:</div>
<div style="margin: 0mm 0mm 0pt">HASHMAP不是同步的,线程不安全的,HASHTABLE是同步的,线程安全的?&nbsp;&nbsp;&nbsp;</div>
<div style="margin: 0mm 0mm 0pt">在Hashtable中，所有涉及到更新其中存放的内容的方法都是同步的&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp; 如：&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp; public&nbsp;&nbsp;&nbsp; synchronized&nbsp;&nbsp;&nbsp; Object&nbsp;&nbsp;&nbsp; put(Object&nbsp;&nbsp;&nbsp; key,&nbsp;&nbsp;&nbsp; Object&nbsp;&nbsp;&nbsp; value)&nbsp;&nbsp;&nbsp; {}&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp; public&nbsp;&nbsp;&nbsp; synchronized&nbsp;&nbsp;&nbsp; Object&nbsp;&nbsp;&nbsp; get(Object&nbsp;&nbsp;&nbsp; key)&nbsp;&nbsp;&nbsp; {}&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp; ...&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp; 以此来保证Hashtable不会被多个线程同时更改</div>
<div style="margin: 0mm 0mm 0pt">因为HashMap的公共方法上没加synchronized关键字</div>
<div style="margin: 0mm 0mm 0pt">如何理解synchronized&nbsp;&nbsp; 关键字呢?</div>
<div style="margin: 0mm 0mm 0pt">比如:</div>
<div style="margin: 0mm 0mm 0pt">用synchronized和不用synchronized简单的说就是&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp; 1个房子有2个门，用synchronized的是从有锁的门&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp; 进入房子，并且进入后锁门，出来后门打开。&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp; 而不用synchronized的是从没有锁的门进入。&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp; 从有锁的门进入的人只管把这个门锁上，但没办法干预从无锁的门进入的人&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp; 所以如果clear()方法是synchronized，他进门后取走所有鸡蛋&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp; 这时如果一个非synchronized的get()方法想进门取得一个鸡蛋就出错了</div>
</div>
 <img src ="http://www.blogjava.net/tinysun/aggbug/255626.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/tinysun/" target="_blank">何克勤</a> 2009-02-19 18:43 <a href="http://www.blogjava.net/tinysun/archive/2009/02/19/255626.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]Java RPC通信机制之RMI </title><link>http://www.blogjava.net/tinysun/archive/2008/11/15/240653.html</link><dc:creator>何克勤</dc:creator><author>何克勤</author><pubDate>Sat, 15 Nov 2008 03:24:00 GMT</pubDate><guid>http://www.blogjava.net/tinysun/archive/2008/11/15/240653.html</guid><wfw:comment>http://www.blogjava.net/tinysun/comments/240653.html</wfw:comment><comments>http://www.blogjava.net/tinysun/archive/2008/11/15/240653.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/tinysun/comments/commentRss/240653.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/tinysun/services/trackbacks/240653.html</trackback:ping><description><![CDATA[<p style="margin: 0in 0in 0pt"><span style="font-size: 11pt; font-family: 宋体">在传统的</span><span style="font-size: 11pt; font-family: 'Courier New'">RPC</span><span style="font-size: 11pt; font-family: 宋体">编程接口逐渐淡出人们视线的同时，新的、更便于使用且附加了更多特性的</span><span style="font-size: 11pt; font-family: 'Courier New'">RPC</span><span style="font-size: 11pt; font-family: 宋体">编程接口也不断涌现，</span><span style="font-size: 11pt; font-family: 'Courier New'">CORBA</span><span style="font-size: 11pt; font-family: 宋体">作为分布式对象计算技术的典范，在很长一段时间内极大地吸引了大家的注意，但是由于</span><span style="font-size: 11pt; font-family: 'Courier New'">CORBA</span><span style="font-size: 11pt; font-family: 宋体">规范试图覆盖过多的内容，使得</span><span style="font-size: 11pt; font-family: 'Courier New'">CORBA</span><span style="font-size: 11pt; font-family: 宋体">显得过于复杂，也极大地限制了</span><span style="font-size: 11pt; font-family: 'Courier New'">CORBA</span><span style="font-size: 11pt; font-family: 宋体">的应用范围，本系列将向大家介绍几种轻量级的，更适于在</span><span style="font-size: 11pt; font-family: 'Courier New'">Java</span><span style="font-size: 11pt; font-family: 宋体">开发中使用的</span><span style="font-size: 11pt; font-family: 'Courier New'">RPC</span><span style="font-size: 11pt; font-family: 宋体">编程接口：</span><span style="font-size: 11pt; font-family: 'Courier New'">RMI</span><span style="font-size: 11pt; font-family: 宋体">、</span><span style="font-size: 11pt; font-family: 'Courier New'">XML-RPC</span><span style="font-size: 11pt; font-family: 宋体">、</span><span style="font-size: 11pt; font-family: 'Courier New'">SOAP</span><span style="font-size: 11pt; font-family: 宋体">。</span></p>
<h2 style="margin: 12pt 0in 3pt"><em>RMI<span style="font-family: 宋体">（</span>Remote Method Invocation<span style="font-family: 宋体">）</span></em></h2>
<p style="margin: 0in 0in 0pt"><span style="font-size: 11pt; font-family: 宋体">与本系列将介绍的其它两种</span><span style="font-size: 11pt; font-family: 'Courier New'">RPC</span><span style="font-size: 11pt; font-family: 宋体">编程接口不同，</span><span style="font-size: 11pt; font-family: 'Courier New'">RMI</span><span style="font-size: 11pt; font-family: 宋体">（</span><span style="font-size: 11pt; font-family: 'Courier New'">Remote Method Invocation</span><span style="font-size: 11pt; font-family: 宋体">）显得有些老旧，它是在</span><span style="font-size: 11pt; font-family: 'Courier New'">Java-IDL</span><span style="font-size: 11pt; font-family: 宋体">加入</span><span style="font-size: 11pt; font-family: 'Courier New'">J2SE</span><span style="font-size: 11pt; font-family: 宋体">之前被引入的。</span><span style="font-size: 11pt; font-family: 'Courier New'">RMI</span><span style="font-size: 11pt; font-family: 宋体">开发流程与</span><span style="font-size: 11pt; font-family: 'Courier New'">CORBA</span><span style="font-size: 11pt; font-family: 宋体">如出一辙（从出现的时间上无法确定</span><span style="font-size: 11pt; font-family: 'Courier New'">RMI</span><span style="font-size: 11pt; font-family: 宋体">是否是按照</span><span style="font-size: 11pt; font-family: 'Courier New'">CORBA</span><span style="font-size: 11pt; font-family: 宋体">规范定制的），因此，其开发过程相对比较烦琐，但是由于</span><span style="font-size: 11pt; font-family: 'Courier New'">RMI</span><span style="font-size: 11pt; font-family: 宋体">是</span><span style="font-size: 11pt; font-family: 'Courier New'">EJB</span><span style="font-size: 11pt; font-family: 宋体">的基础，因此，它在</span><span style="font-size: 11pt; font-family: 'Courier New'">Java</span><span style="font-size: 11pt; font-family: 宋体">开发中具有十分重要的地位。</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 11pt; font-family: 宋体">以下是创建远程方法调用的</span><span style="font-size: 11pt; font-family: 'Courier New'">5</span><span style="font-size: 11pt; font-family: 宋体">个步骤：</span></p>
<p style="margin: 0in 0in 0pt 0.25in; text-indent: -0.25in"><span style="font-size: 11pt; font-family: 'Courier New'">1.<span style="font: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">&nbsp;&nbsp; </span></span><span style="font-size: 11pt; font-family: 宋体">定义一个扩展了</span><span style="font-size: 11pt; font-family: 'Courier New'">Remote</span><span style="font-size: 11pt; font-family: 宋体">接口的接口，该接口中的每一个方法必须声明它将产生一个</span><span style="font-size: 11pt; font-family: 'Courier New'">RemoteException</span><span style="font-size: 11pt; font-family: 宋体">异常；</span></p>
<p style="margin: 0in 0in 0pt 0.25in; text-indent: -0.25in"><span style="font-size: 11pt; font-family: 'Courier New'">2.<span style="font: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">&nbsp;&nbsp; </span></span><span style="font-size: 11pt; font-family: 宋体">定义一个实现该接口的类；</span></p>
<p style="margin: 0in 0in 0pt 0.25in; text-indent: -0.25in"><span style="font-size: 11pt; font-family: 'Courier New'">3.<span style="font: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">&nbsp;&nbsp; </span></span><span style="font-size: 11pt; font-family: 宋体">使用</span><span style="font-size: 11pt; font-family: 'Courier New'">rmic</span><span style="font-size: 11pt; font-family: 宋体">程序生成远程实现所需的存根和框架；</span></p>
<p style="margin: 0in 0in 0pt 0.25in; text-indent: -0.25in"><span style="font-size: 11pt; font-family: 'Courier New'">4.<span style="font: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">&nbsp;&nbsp; </span></span><span style="font-size: 11pt; font-family: 宋体">创建一个客户程序和服务器进行</span><span style="font-size: 11pt; font-family: 'Courier New'">RMI</span><span style="font-size: 11pt; font-family: 宋体">调用；</span></p>
<p style="margin: 0in 0in 0pt 0.25in; text-indent: -0.25in"><span style="font-size: 11pt; font-family: 'Courier New'">5.<span style="font: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">&nbsp;&nbsp; </span></span><span style="font-size: 11pt; font-family: 宋体">启动</span><span style="font-size: 11pt; font-family: 'Courier New'">rmiregistry</span><span style="font-size: 11pt; font-family: 宋体">并运行自己的服务程序和客户程序。</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 11pt; font-family: 宋体">下面举一个简单、而且被无数次引用的例子：</span><span style="font-size: 11pt; font-family: 'Courier New'">Echo</span><span style="font-size: 11pt; font-family: 宋体">。</span></p>
<h3 style="margin: 12pt 0in 3pt">1<span style="font-family: 宋体">、定义</span>Echo<span style="font-family: 宋体">接口</span></h3>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; color: green; font-family: 'Courier New'">//Echo.java</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; color: green; font-family: 'Courier New'">//The Echo remote interface</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; font-family: 'Courier New'">package demo.rmi;</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; font-family: 'Courier New'">import java.rmi.*;</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; color: blue; font-family: 'Courier New'">public</span><span style="font-size: 10pt; font-family: 'Courier New'"> <span style="color: blue">interface</span> Echo extends Remote {</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; font-family: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String echo(String msg) throws RemoteException;</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; font-family: 'Courier New'">}</span></p>
<h3 style="margin: 12pt 0in 3pt">2<span style="font-family: 宋体">、实现</span>Echo<span style="font-family: 宋体">接口</span></h3>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; color: green; font-family: 'Courier New'">//EchoServer.java</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; color: green; font-family: 'Courier New'">//The implementation of the Echo remote object</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; font-family: 'Courier New'">package demo.rmi;</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; font-family: 'Courier New'">import java.net.*;</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; font-family: 'Courier New'">import java.rmi.*;</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; font-family: 'Courier New'">import java.rmi.registry.*;</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; font-family: 'Courier New'">import java.rmi.server.*;</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; color: blue; font-family: 'Courier New'">public</span><span style="font-size: 10pt; font-family: 'Courier New'"> <span style="color: blue">class</span> EchoServer</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; font-family: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; extends UnicastRemoteObject</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; font-family: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; implements Echo {</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; font-family: 宋体">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: green">//默认构件器，也要&#8220;掷&#8221;出</span></span><span style="font-size: 10pt; color: green; font-family: 'Courier New'">RemoteException</span><span style="font-size: 10pt; color: green; font-family: 宋体">违例</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; font-family: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue">public</span> EchoServer() throws RemoteException {</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; font-family: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; super();</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; font-family: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; font-family: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue">public</span> String echo(String msg) throws RemoteException {</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; font-family: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue">return</span> <span style="color: maroon">"Echo: "</span> + msg;</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; font-family: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; font-family: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue">public</span> <span style="color: blue">static</span> <span style="color: blue">void</span> main(String [] args) {</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; font-family: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-size: 10pt; color: green; font-family: 'Courier New'">/*</span><span style="font-size: 10pt; color: green; font-family: 宋体">创建和安装一个安全管理器，令其支持</span><span style="font-size: 10pt; color: green; font-family: 'Courier New'">RMI</span><span style="font-size: 10pt; color: green; font-family: 宋体">。</span><span style="font-size: 10pt; color: green; font-family: 宋体">作为</span><span style="font-size: 10pt; color: green; font-family: 'Courier New'">Java</span><span style="font-size: 10pt; color: green; font-family: 宋体">开发包的一部分，适用于</span><span style="font-size: 10pt; color: green; font-family: 'Courier New'">RMI</span><span style="font-size: 10pt; color: green; font-family: 宋体">唯一一个是</span><span style="font-size: 10pt; color: green; font-family: 'Courier New'">RMISecurityManager.*/</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; font-family: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.setSecurityManager(<span style="color: blue">new</span> RMISecurityManager());</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; font-family: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue">try</span> {</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; font-family: 宋体">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: green">/*创建远程对象的一个或多个实例，下面是</span></span><span style="font-size: 10pt; color: green; font-family: 'Courier New'">EchoServer</span><span style="font-size: 10pt; color: green; font-family: 宋体">对象*/</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; font-family: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; EchoServer es = <span style="color: blue">new</span> EchoServer();</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; font-family: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-size: 10pt; color: green; font-family: 宋体">/*向</span><span style="font-size: 10pt; color: green; font-family: 'Courier New'">RMI</span><span style="font-size: 10pt; color: green; font-family: 宋体">远程对象注册表注册至少一个远程对象。一个远程对象拥有的方法即可生成指向其他远程对象的句柄，这样，客户到注册表里访问一次，得到第一个远程对象即可.*/</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; font-family: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-size: 10pt; font-family: 'Courier New'">Naming.rebind(<span style="color: maroon">"EchoServer"</span>, es);</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; font-family: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(<span style="color: maroon">"Ready to provide echo service..."</span>);</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; font-family: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <span style="color: blue">catch</span> (Exception e) {</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; font-family: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; e.printStackTrace();</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; font-family: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; font-family: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; font-family: 'Courier New'">}</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 11pt; font-family: 宋体">这个实现类使用了</span><span style="font-size: 11pt; font-family: 'Courier New'">UnicastRemoteObject</span><span style="font-size: 11pt; font-family: 宋体">去连接</span><span style="font-size: 11pt; font-family: 'Courier New'">RMI</span><span style="font-size: 11pt; font-family: 宋体">系统。在我们的例子中，我们是直接的从</span><span style="font-size: 11pt; font-family: 'Courier New'">UnicastRemoteObject</span><span style="font-size: 11pt; font-family: 宋体">这个类上继承的，事实上并不一定要这样做，如果一个类不是从</span><span style="font-size: 11pt; font-family: 'Courier New'">UnicastRmeoteObject</span><span style="font-size: 11pt; font-family: 宋体">上继承，那必须使用它的</span><span style="font-size: 11pt; font-family: 'Courier New'">exportObject()</span><span style="font-size: 11pt; font-family: 宋体">方法去连接到</span><span style="font-size: 11pt; font-family: 'Courier New'">RMI</span><span style="font-size: 11pt; font-family: 宋体">。（否则，运行时将被告知无法序列化。）</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 11pt; font-family: 宋体">如果一个类继承自</span><span style="font-size: 11pt; font-family: 'Courier New'">UnicastRemoteObject</span><span style="font-size: 11pt; font-family: 宋体">，那么它必须提供一个构造函数并且声明抛出一个</span><span style="font-size: 11pt; font-family: 'Courier New'">RemoteException</span><span style="font-size: 11pt; font-family: 宋体">对象（否则，会遇到编译错误）。当这个构造函数调用了</span><span style="font-size: 11pt; font-family: 'Courier New'">super()</span><span style="font-size: 11pt; font-family: 宋体">，它就激活</span><span style="font-size: 11pt; font-family: 'Courier New'">UnicastRemoteObject</span><span style="font-size: 11pt; font-family: 宋体">中的代码完成</span><span style="font-size: 11pt; font-family: 'Courier New'">RMI</span><span style="font-size: 11pt; font-family: 宋体">的连接和远程对象的初始化。</span></p>
<h3 style="margin: 12pt 0in 3pt">3<span style="font-family: 宋体">、运行</span>rmic<span style="font-family: 宋体">编译实现类，产生</span>_Stub<span style="font-family: 宋体">类</span></h3>
<p style="margin: 0in 0in 0pt"><span style="font-size: 11pt; font-family: 宋体">在</span><span style="font-size: 11pt; font-family: 'Courier New'">demo.rmi.EchoServer.java</span><span style="font-size: 11pt; font-family: 宋体">上级目录下运行如下命令：</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; font-family: 'Courier New'">rmic demo.rmi.EchoServer</span></p>
<h3 style="margin: 12pt 0in 3pt">4<span style="font-family: 宋体">、编写客户程序</span></h3>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; color: green; font-family: 'Courier New'">//EchoClient.java</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; color: green; font-family: 'Courier New'">//Uses remote object EchoServer</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; font-family: 'Courier New'">package demo.rmi;</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; font-family: 'Courier New'">import java.rmi.*;</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; font-family: 'Courier New'">import java.rmi.registry.*;</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; color: blue; font-family: 'Courier New'">public</span><span style="font-size: 10pt; font-family: 'Courier New'"> <span style="color: blue">class</span> EchoClient {</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; font-family: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue">public</span> <span style="color: blue">static</span> <span style="color: blue">void</span> main(String [] args) {</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; font-family: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.setSecurityManager(<span style="color: blue">new</span> RMISecurityManager());</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; font-family: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue">try</span> {</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; font-family: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Echo t = (Echo)Naming.lookup(<span style="color: maroon">"EchoServer"</span>);</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; font-family: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue">for</span> (<span style="color: blue">int</span> i = 0; i &lt; 10; i++) {</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; font-family: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(t.echo(String.valueOf(i)));</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; font-family: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; font-family: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <span style="color: blue">catch</span> (Exception e) {</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; font-family: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; e.printStackTrace();</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; font-family: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; font-family: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; font-family: 'Courier New'">}</span></p>
<h3 style="margin: 12pt 0in 3pt">5<span style="font-family: 宋体">、运行</span></h3>
<p style="margin: 0in 0in 0pt"><span style="font-size: 11pt; font-family: 宋体">编码的工作就只有这些，现在可以依次启动</span><span style="font-size: 11pt; font-family: 'Courier New'">rmiregistry</span><span style="font-size: 11pt; font-family: 宋体">（启动</span><span style="font-size: 11pt; font-family: 'Courier New'">rmiregistry</span><span style="font-size: 11pt; font-family: 宋体">时可以附加一个端口，一般使用默认的端口</span><span style="font-size: 11pt; font-family: 'Courier New'">1099</span><span style="font-size: 11pt; font-family: 宋体">即可，这是默认的</span><span style="font-size: 11pt; font-family: 'Courier New'">Naming Service</span><span style="font-size: 11pt; font-family: 宋体">运行端口）、</span><span style="font-size: 11pt; font-family: 'Courier New'">EchoServer</span><span style="font-size: 11pt; font-family: 宋体">、</span><span style="font-size: 11pt; font-family: 'Courier New'">EchoClient</span><span style="font-size: 11pt; font-family: 宋体">了。但是，虽然有些</span><span style="font-size: 11pt; font-family: 'Courier New'">RMI</span><span style="font-size: 11pt; font-family: 宋体">的资料没有提到，但你运行时不可避免会遇到如下两个错误：</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 11pt; font-family: 'Courier New'">1</span><span style="font-size: 11pt; font-family: 宋体">）</span><span style="font-size: 11pt; font-family: 'Courier New'">java.security.AccessControlException: access denied (java.net.SocketPermission 127.0.0.1:1099 connect,resolve)</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 11pt; font-family: 宋体">原因很简单，</span><span style="font-size: 11pt; font-family: 'Courier New'">RMI Server/Client</span><span style="font-size: 11pt; font-family: 宋体">程序试图通过</span><span style="font-size: 11pt; font-family: 'Courier New'">Socket</span><span style="font-size: 11pt; font-family: 宋体">连接访问本机的</span><span style="font-size: 11pt; font-family: 'Courier New'">rmiregistry</span><span style="font-size: 11pt; font-family: 宋体">服务（即</span><span style="font-size: 11pt; font-family: 'Courier New'">RMI</span><span style="font-size: 11pt; font-family: 宋体">的</span><span style="font-size: 11pt; font-family: 'Courier New'">Naming Service</span><span style="font-size: 11pt; font-family: 宋体">，其运行的默认端口是</span><span style="font-size: 11pt; font-family: 'Courier New'">1099</span><span style="font-size: 11pt; font-family: 宋体">）。要解决这个问题，可以在运行</span><span style="font-size: 11pt; font-family: 'Courier New'">Server/Client</span><span style="font-size: 11pt; font-family: 宋体">时指定一个</span><span style="font-size: 11pt; font-family: 'Courier New'">Policy</span><span style="font-size: 11pt; font-family: 宋体">文件（关于</span><span style="font-size: 11pt; font-family: 'Courier New'">Policy</span><span style="font-size: 11pt; font-family: 宋体">的更多信息，见参考</span><span style="font-size: 11pt; font-family: 'Courier New'">2</span><span style="font-size: 11pt; font-family: 宋体">），如下：</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; font-family: 'Courier New'">java -Djava.security.policy=demo/rmi/policyfile.txt demo.rmi.EchoServer</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 11pt; font-family: 'Courier New'">Policy</span><span style="font-size: 11pt; font-family: 宋体">文件的内容为：</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; font-family: 'Courier New'">grant{</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; font-family: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; permission java.net.SocketPermission <span style="color: maroon">"localhost:1099"</span>, <span style="color: maroon">"connect, resolve"</span>;</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; font-family: 'Courier New'">};</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 11pt; font-family: 宋体">即允许访问本机的</span><span style="font-size: 11pt; font-family: 'Courier New'">1099</span><span style="font-size: 11pt; font-family: 宋体">端口。</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 11pt; font-family: 宋体">或者干脆来个彻底开放：</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; font-family: 'Courier New'">grant {</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; font-family: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; permission java.security.AllPermission <span style="color: maroon">""</span>, <span style="color: maroon">""</span>;</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; font-family: 'Courier New'">};</span></p>
<p style="margin: 0in 0in 0pt"><font size="3"><span style="font-family: 'Courier New'">2</span><span style="font-family: 宋体">）</span></font><span style="font-size: 10pt; font-family: 'Courier New'">java.rmi.ServerException: RemoteException occurred in server thread; nested exception is:</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; font-family: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is:</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; font-family: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; java.lang.ClassNotFoundException: demo.rmi.EchoServer_Stub</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; font-family: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ...</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 11pt; font-family: 宋体">如果你凑巧用启动</span><span style="font-size: 11pt; font-family: 'Courier New'">rmiregistry</span><span style="font-size: 11pt; font-family: 宋体">的终端窗口启动了</span><span style="font-size: 11pt; font-family: 'Courier New'">EchoServer</span><span style="font-size: 11pt; font-family: 宋体">，那么你很走运，你看不到上面的错误，但如果你不是在看完这篇文章后就再也用不到</span><span style="font-size: 11pt; font-family: 'Courier New'">RMI</span><span style="font-size: 11pt; font-family: 宋体">，那么，这个错误在那里等着你，</span><span style="font-size: 11pt; font-family: 'Courier New'">:)</span><span style="font-size: 11pt; font-family: 宋体">。</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 11pt; font-family: 宋体">错误很明显，</span><span style="font-size: 11pt; font-family: 'Courier New'">rmiregistry</span><span style="font-size: 11pt; font-family: 宋体">找不到与</span><span style="font-size: 11pt; font-family: 'Courier New'">EchoServer</span><span style="font-size: 11pt; font-family: 宋体">放在同一目录下的</span><span style="font-size: 11pt; font-family: 'Courier New'">EchoServer_Stub</span><span style="font-size: 11pt; font-family: 宋体">，因为</span><span style="font-size: 11pt; font-family: 'Courier New'">package</span><span style="font-size: 11pt; font-family: 宋体">所在</span><span style="font-size: 11pt; font-family: 'Courier New'">demo.rmi</span><span style="font-size: 11pt; font-family: 宋体">目录的上级目录不在</span><span style="font-size: 11pt; font-family: 'Courier New'">rmiregistry</span><span style="font-size: 11pt; font-family: 宋体">的</span><span style="font-size: 11pt; font-family: 'Courier New'">classpath</span><span style="font-size: 11pt; font-family: 宋体">中，这个问题有两种解决方案：</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 11pt; font-family: 'Courier New'">a</span><span style="font-size: 11pt; font-family: 宋体">）在启动</span><span style="font-size: 11pt; font-family: 'Courier New'">rmiregistry</span><span style="font-size: 11pt; font-family: 宋体">前先调整一下</span><span style="font-size: 11pt; font-family: 'Courier New'">CLASSPATH</span><span style="font-size: 11pt; font-family: 宋体">环境变量，以目录</span><span style="font-size: 11pt; font-family: 'Courier New'">E:"</span><span style="font-size: 11pt; font-family: 宋体">为例，执行：</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; font-family: 'Courier New'">set CLASSPATH=%CLASSPATH%;E:"</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 11pt; font-family: 'Courier New'">b</span><span style="font-size: 11pt; font-family: 宋体">）修改</span><span style="font-size: 11pt; font-family: 'Courier New'">code</span><span style="font-size: 11pt; font-family: 宋体">，在</span><span style="font-size: 11pt; font-family: 'Courier New'">EchoServer</span><span style="font-size: 11pt; font-family: 宋体">中通过如下代码：</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; font-family: 'Courier New'">Registry r = LocateRegistry.createRegistry(8111);</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; font-family: 'Courier New'">r.rebind(<span style="color: maroon">"EchoServer"</span>, es);</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 11pt; font-family: 宋体">在程序内部创建一个</span><span style="font-size: 11pt; font-family: 'Courier New'">LocateRegistry</span><span style="font-size: 11pt; font-family: 宋体">，并将自身注册到该</span><span style="font-size: 11pt; font-family: 'Courier New'">LocateRegistry</span><span style="font-size: 11pt; font-family: 宋体">，其中的数值</span><span style="font-size: 11pt; font-family: 'Courier New'">8111</span><span style="font-size: 11pt; font-family: 宋体">表示</span><span style="font-size: 11pt; font-family: 'Courier New'">LocateRegistry</span><span style="font-size: 11pt; font-family: 宋体">运行的端口。</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 11pt; font-family: 宋体">同样，对于客户程序，也需要作相应的调整：</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; font-family: 'Courier New'">Registry r = LocateRegistry.getRegistry(<span style="color: maroon">"localhost"</span>, 8111);</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 10pt; font-family: 'Courier New'">Echo e = (Echo)r.lookup(<span style="color: maroon">"EchoServer"</span>);</span></p>
<p style="margin: 0in 0in 0pt"><span style="font-size: 11pt; font-family: 宋体">而不是像上面例子中一样访问</span><span style="font-size: 11pt; font-family: 'Courier New'">Naming</span><span style="font-size: 11pt; font-family: 宋体">类的</span><span style="font-size: 11pt; font-family: 'Courier New'">static</span><span style="font-size: 11pt; font-family: 宋体">方法来访问默认的</span><span style="font-size: 11pt; font-family: 'Courier New'">rmiregistry</span><span style="font-size: 11pt; font-family: 宋体">服务。</span></p>
<h2 style="margin: 12pt 0in 3pt"><span style="font-family: 宋体"><em>参考：</em></span></h2>
<p style="margin: 0in 0in 0pt 21.75pt; text-indent: -21.75pt"><span style="font-size: 11pt; font-family: 'Courier New'">1.<span style="font: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-size: 11pt; font-family: 'Courier New'">Java RMI Tutorial, <a href="http://www.ccs.neu.edu/home/kenb/com3337/rmi_tut.html">http://www.ccs.neu.edu/home/kenb/com3337/rmi_tut.html</a></span></p>
<p style="margin: 0in 0in 0pt 21.75pt; text-indent: -21.75pt"><span style="font-size: 11pt; font-family: 'Courier New'">2.<span style="font: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-size: 11pt; font-family: 'Courier New'">Policy Tool - Policy File Creation and Management Tool. <a href="http://java.sun.com/j2se/1.4.2/docs/tooldocs/windows/policytool.html">http://java.sun.com/j2se/1.4.2/docs/tooldocs/windows/policytool.html</a></span></p>
<span style="font-family: 'Courier New'"><font size="3">3.</font><span style="font: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-size: 11pt; font-family: 'Courier New'">Java RMI</span><span style="font-size: 11pt; font-family: 宋体">入门实战，</span><span style="font-size: 11pt; font-family: 'Courier New'"><a href="http://www.huihoo.com/java/rmi/index.html">http://www.huihoo.com/java/rmi/index.html</a></span><br />
 <img src ="http://www.blogjava.net/tinysun/aggbug/240653.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/tinysun/" target="_blank">何克勤</a> 2008-11-15 11:24 <a href="http://www.blogjava.net/tinysun/archive/2008/11/15/240653.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>(转)Java中URI,URL和URN的使用</title><link>http://www.blogjava.net/tinysun/archive/2008/10/04/232297.html</link><dc:creator>何克勤</dc:creator><author>何克勤</author><pubDate>Sat, 04 Oct 2008 03:54:00 GMT</pubDate><guid>http://www.blogjava.net/tinysun/archive/2008/10/04/232297.html</guid><wfw:comment>http://www.blogjava.net/tinysun/comments/232297.html</wfw:comment><comments>http://www.blogjava.net/tinysun/archive/2008/10/04/232297.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/tinysun/comments/commentRss/232297.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/tinysun/services/trackbacks/232297.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: Java中URI,URL和URN的使用从天极网抄录整理 2006-1-13URI、URL和URN是识别、定位和命名网上资源的标准途径。本文分析了URI、URL和URN的概念，以及Java的URI和URL类（以及与URL相关的类），并演示了如何在程序中使用这些类。Internet被认为是全球的实际和抽象的资源的集合。实际的资源包括从文件（file）到人(person)，抽象的资源包括...&nbsp;&nbsp;<a href='http://www.blogjava.net/tinysun/archive/2008/10/04/232297.html'>阅读全文</a><img src ="http://www.blogjava.net/tinysun/aggbug/232297.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/tinysun/" target="_blank">何克勤</a> 2008-10-04 11:54 <a href="http://www.blogjava.net/tinysun/archive/2008/10/04/232297.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于java连接sql server 2000的问题</title><link>http://www.blogjava.net/tinysun/archive/2008/03/10/185067.html</link><dc:creator>何克勤</dc:creator><author>何克勤</author><pubDate>Mon, 10 Mar 2008 06:15:00 GMT</pubDate><guid>http://www.blogjava.net/tinysun/archive/2008/03/10/185067.html</guid><wfw:comment>http://www.blogjava.net/tinysun/comments/185067.html</wfw:comment><comments>http://www.blogjava.net/tinysun/archive/2008/03/10/185067.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/tinysun/comments/commentRss/185067.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/tinysun/services/trackbacks/185067.html</trackback:ping><description><![CDATA[<span style="font-size: 10pt">
<p>在xp机器上面安装了ms sql server2000后,jdbc连接的时候出现了各种问题.上网查询都解决后纪录下来.</p>
<p>1.</p>
<p>[Microsoft][SQLServer 2000 Driver for JDBC]Error establishing socket.</p>
<p>按照网上大家说的办法.打sp3的补丁.到官方网站上下载下来.安装文件以及版本相应的驱动jar包.</p>
<p>网址如下:http://www.microsoft.com/downloads/details.aspx?FamilyID=07287b11-0502-461a-b138-2aa54bfdc03a&amp;DisplayLang=en</p>
<p>注意: <font size="2">在安装升级包的时候要注意的是下载的安装文件"setup.exe"仅仅是一次解压缩,在这个地方容易让人以为双击就是安装了.需要"安装"一次后再到安装目录找到setup.bat文件执行安装.</font></p>
<p><font size="2">同时也要将自己所建工程下的lib包中用到的sqlserver驱动更换成sp3的.</font></p>
<p><font size="2">2.</font></p>
<p>用户 'sa' 登录失败。原因: 未与信任 SQL Server 连接相关联。</p>
<p>这一问题一般是由于SQL Server未集成Windows身份验证导致的<br />
这个问题一般是由于sqlserver 没有集成windows身份验证所导致的.第一步先打开SQL Server企业管理器。选择服务器名称上右键选择&#8220;编辑SQL Server注册属性&#8221;，然后在对话框中选择&#8220;使用windows身份验证&#8221;。<br />
如果还不行,在执行第二步.第二步: 同样右键，选择&#8220;属性&#8221;，然后打开&#8220;安全性&#8221;选项卡。&nbsp;在选项卡中，选择身份验证为&#8220;SQL Server和 Windows &#8221;,其他不变. 这样这个问题就可以解决.</p>
<p>3.</p>
<p>[SQLServer]对象名XXX无效</p>
<p>这个一般是由登陆数据库的用户名的权限造成的。</p>
<p>我在做数据库连接的时候用户名用的是sa.之后换成了自己建的用户，就可以了。如果还不可以就给自己建的用户重新分配一下权限。</p>
<p>&nbsp;</p>
<p>下面是我测试的jsp代码。</p>
<div class="highlighter">
<ol class="highlighter-j">
    <li><span>&lt;%@&nbsp;page&nbsp;contentType=</span><span class="string">"text/html;&nbsp;charset=gb2312"</span><span>&nbsp;language=</span><span class="string">"java"</span><span>&nbsp;</span>
    <li class="alt"><span class="keyword">import</span><span>=</span><span class="string">"java.sql.*"</span>
    <li><span class="keyword">import</span><span>=</span><span class="string">"java.io.*"</span>
    <li class="alt"><span class="keyword">import</span><span>=</span><span class="string">"java.sql.Connection"</span>
    <li><span class="keyword">import</span><span>=</span><span class="string">"java.sql.Date"</span>
    <li class="alt"><span class="keyword">import</span><span>=</span><span class="string">"java.sql.PreparedStatement"</span>
    <li><span class="keyword">import</span><span>=</span><span class="string">"java.sql.ResultSet"</span>
    <li class="alt"><span class="keyword">import</span><span>=</span><span class="string">"java.sql.SQLException"</span>
    <li><span class="keyword">import</span><span>=</span><span class="string">"java.sql.Statement"</span>
    <li class="alt"><span>%&gt;</span>
    <li><span>&lt;html&gt;</span>
    <li class="alt"><span>&lt;body&gt;</span>
    <li><span>data&nbsp;from&nbsp;SQL&nbsp;SERVER&nbsp;DB:</span>
    <li class="alt"><span>&lt;hr&gt;</span>
    <li><span>&lt;table&gt;</span>
    <li class="alt"><span>&lt;%!&nbsp;String&nbsp;trans(String&nbsp;chi)</span>
    <li><span>{</span>
    <li class="alt"><span>String&nbsp;result=</span><span class="keyword">null</span><span>;</span>
    <li><span class="keyword">byte</span><span>&nbsp;temp[];</span>
    <li class="alt"><span class="keyword">try</span>
    <li><span>{</span>
    <li class="alt"><span>temp=chi.getBytes(</span><span class="string">"iso-8859-1"</span><span>);</span>
    <li><span>result=</span><span class="keyword">new</span><span>&nbsp;String(temp);</span>
    <li class="alt"><span>}</span>
    <li><span class="keyword">catch</span><span>(UnsupportedEncodingException&nbsp;e)</span>
    <li class="alt"><span>{</span>
    <li><span>System.out.println(e.toString());</span>
    <li class="alt"><span>}</span>
    <li><span class="keyword">return</span><span>&nbsp;result;</span>
    <li class="alt"><span>}&nbsp;%&gt;</span>
    <li><span>&lt;%</span>
    <li class="alt"><span>Class.forName(</span><span class="string">"com.microsoft.jdbc.sqlserver.SQLServerDriver"</span><span>).newInstance();</span>
    <li><span>Connection&nbsp;con=java.sql.DriverManager.getConnection(</span><span class="string">"jdbc:microsoft:sqlserver://127.0.0.1:4567;&nbsp;DatabaseName=ch12"</span><span>,</span><span class="string">"sx"</span><span>,</span><span class="string">"sx"</span><span>);</span>
    <li class="alt">
    <li><span>Statement&nbsp;stmt=con.createStatement();</span>
    <li class="alt"><span>ResultSet&nbsp;rst=stmt.executeQuery(</span><span class="string">"select&nbsp;*&nbsp;from&nbsp;contact"</span><span>);</span>
    <li><span class="keyword">while</span><span>&nbsp;(rst.next())</span>
    <li class="alt"><span>{</span>
    <li><span>out.println(</span><span class="string">"&lt;tr&gt;"</span><span>);</span>
    <li class="alt"><span>out.println(</span><span class="string">"&lt;td&gt;"</span><span>+trans(rst.getString(</span><span class="string">"userName"</span><span>))+</span><span class="string">"&lt;/td&gt;"</span><span>);</span>
    <li><span>out.println(</span><span class="string">"&lt;td&gt;"</span><span>+trans(rst.getString(</span><span class="string">"phone"</span><span>))+</span><span class="string">"&lt;/td&gt;"</span><span>);</span>
    <li class="alt"><span>out.println(</span><span class="string">"&lt;td&gt;"</span><span>+trans(rst.getString(</span><span class="string">"mail"</span><span>))+</span><span class="string">"&lt;/td&gt;"</span><span>);</span>
    <li><span>out.println(</span><span class="string">"&lt;/tr&gt;"</span><span>);</span>
    <li class="alt"><span>}</span>
    <li><span>rst.close();</span>
    <li class="alt"><span>stmt.close();</span>
    <li><span>con.close();</span>
    <li class="alt"><span>%&gt;</span>
    <li><span>&lt;/table&gt;</span>
    <li class="alt"><span>&lt;/body&gt;</span>
    <li><span>&lt;/html&gt;</span></li>
</ol>
</div>
<br />
开发环境:Eclipse3.3+Sql Server 2000<br />
在练习使用Ibatis开发数据库应用程序时,按照如下步骤:<br />
1)<span style="font-family: 宋体">下载SQL Server 2000 driver for JDBC&nbsp;<br />
2)安装驱动,并将msutil.jar,msbase.jar,mssqlserver.jar添加到classpath<br />
3)写好配置文件,其中用了java property文件.<br />
//file:database.properties<br />
<font face="宋体">jdbc.driver=com.microsoft.jdbc.sqlserver.SQLServerDriver<br />
jdbc.url=jdbc:sqlserver://localhost:1433;DatabaseName=test;SelectMethod=cursor<br />
jdbc.username=sa<br />
jdbc.password=sa<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
运行时却出现如下异常:<br />
<font face="宋体">ERROR - JakartaCommonsLoggingImpl.error(19) | SimpleDataSource: Error while loading properties.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
Cause:&nbsp;&nbsp;java.lang.ClassNotFoundException: com.microsoft.sqlserver.jdbc.SQLServerDriver<br />
java.lang.ClassNotFoundException: com.microsoft.sqlserver.jdbc.SQLServerDriver<br />
at java.net.URLClassLoader$1.run(URLClassLoader.java:200)<br />
at java.security.AccessController.doPrivileged(Native Method)<br />
at java.net.URLClassLoader.findClass(URLClassLoader.java:188)<br />
at java.lang.ClassLoader.loadClass(ClassLoader.java:306)<br />
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:268)<br />
at java.lang.ClassLoader.loadClass(ClassLoader.java:251)<br />
at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:319)<br />
at java.lang.Class.forName0(Native Method)<br />
at java.lang.Class.forName(Class.java:164)<br />
at com.ibatis.common.resources.Resources.classForName(Resources.java:244)<br />
at com.ibatis.common.resources.Resources.instantiate(Resources.java:260)<br />
at com.ibatis.common.jdbc.SimpleDataSource.initialize(SimpleDataSource.java:199)<br />
at com.ibatis.common.jdbc.SimpleDataSource.&lt;init&gt;(SimpleDataSource.java:116)<br />
at com.ibatis.sqlmap.engine.datasource.SimpleDataSourceFactory.initialize(SimpleDataSourceFactory.java:31)<br />
at com.ibatis.sqlmap.engine.builder.xml.SqlMapConfigParser$9.process(SqlMapConfigParser.java:318)<br />
at com.ibatis.common.xml.NodeletParser.processNodelet(NodeletParser.java:111)<br />
at com.ibatis.common.xml.NodeletParser.process(NodeletParser.java:95)<br />
at com.ibatis.common.xml.NodeletParser.process(NodeletParser.java:92)<br />
at com.ibatis.common.xml.NodeletParser.process(NodeletParser.java:92)<br />
at com.ibatis.common.xml.NodeletParser.parse(NodeletParser.java:62)<br />
at com.ibatis.common.xml.NodeletParser.parse(NodeletParser.java:50)<br />
at com.ibatis.sqlmap.engine.builder.xml.SqlMapConfigParser.parse(SqlMapConfigParser.java:81)<br />
at com.ibatis.sqlmap.client.SqlMapClientBuilder.buildSqlMapClient(SqlMapClientBuilder.java:62)<br />
at Ibatis.Test.&lt;clinit&gt;(Test.java:22)<br />
最后在师兄帮助下,下了SQL Server&nbsp;2005的驱动,结果成功了.<br />
<br />
事后仔细对比了SQL Server&nbsp;2000 与 SQL Server&nbsp;2005驱动包，惊奇的发现<br />
<font face="宋体">com.microsoft.sqlserver.jdbc.SQLServerDriver&nbsp; －－－－&gt;这个是2000的<br />
com.microsoft.jdbc.sqlserver.SQLServerDriver&nbsp; --------&gt;这个是2005的<br />
真的汗死！！<br />
</font></font></font></span></span>
<img src ="http://www.blogjava.net/tinysun/aggbug/185067.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/tinysun/" target="_blank">何克勤</a> 2008-03-10 14:15 <a href="http://www.blogjava.net/tinysun/archive/2008/03/10/185067.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>