﻿<?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-桔子园</title><link>http://www.blogjava.net/orangelizq/</link><description>orangelizq</description><language>zh-cn</language><lastBuildDate>Fri, 05 Sep 2008 04:46:29 GMT</lastBuildDate><pubDate>Fri, 05 Sep 2008 04:46:29 GMT</pubDate><ttl>60</ttl><item><title>JAVA中多种计时器的比较与分析</title><link>http://www.blogjava.net/orangelizq/archive/2008/09/05/227175.html</link><dc:creator>桔子汁</dc:creator><author>桔子汁</author><pubDate>Fri, 05 Sep 2008 03:46:00 GMT</pubDate><guid>http://www.blogjava.net/orangelizq/archive/2008/09/05/227175.html</guid><wfw:comment>http://www.blogjava.net/orangelizq/comments/227175.html</wfw:comment><comments>http://www.blogjava.net/orangelizq/archive/2008/09/05/227175.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/orangelizq/comments/commentRss/227175.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/orangelizq/services/trackbacks/227175.html</trackback:ping><description><![CDATA[<span class="postbody"><span style="font-size: 15px; line-height: normal"><strong>介绍</strong></span> <br />
<br />
计时器可以提供运行基于时间的工作任务的功能，在计时器的管理下，特定的任务可在某一时间运行一次，也可以按指定的时间间隔反复运行。在众多厂商提供的计时器中应用得比较多的有以下三种： <br />
<br />
● java.util.Timer <br />
Sun JDK 提供的一种轻量级的计时器。 <br />
<br />
● Commonj Timer <br />
IBM 和 BEA 联合制定和推出的一种适用于 J2EE 环境的计时器。<br />
&nbsp;<br />
● WebSphere Application Server Scheduler <br />
IBM WebSphere Application Server 提供的一种功能强大的计时器。 <br />
<br />
<br />
<span style="font-size: 15px; line-height: normal"><strong>java.util.Timer</strong> <br />
</span><br />
java.util.Timer 是 Sun JDK 提供的一种计时器，用于使后台线程按计划执行指定任务，这些任务可以被执行一次，也可以被定期执行。每个 Timer 对象对应一个后台线程，顺序地执行所有计时器任务。如果完成某个计时器任务的时间太长，那么它会&#8220;独占&#8221;计时器的任务执行线程，从而可能延迟后续任务的执行。对 Timer 对象最后的引用完成并且所有未处理的任务都已执行完成后，计时器的任务执行线程会正常终止（并且成为垃圾回收的对象）。</span><br />
<br />
java.util.Timer 简单易用，比较适合提供轻量级的计时器功能。由于其创建的线程会超出容器的管理范围，因此不能应用于管理的环境中。如果用户需要在 J2EE 环境中提供计时器功能，可考虑使用后面即将介绍的 Commonj Timer 或 WebSphere Application Server Scheduler。 <br />
<br />
<br />
<br />
<span style="font-size: 15px; line-height: normal"><strong>Commonj Timer</strong></span> <br />
<br />
Commonj Timer 是 Commonj 规范的一部分，它由 IBM 和 BEA 联合制定和推出，用以更好的响应客户和独立软件商的需求，给开发人员在开发可移植的服务端应用程序时提供一些更加简单和功能更加强大的方法。这个规范主要包括以下几个部分：Service Component Architecture，Service Data Objects，Work Manager and Timer 和 Enterprise Metadata Discovery。其中，Work Manager and Time 为在应用服务器中支持并发任务的执行提供了一些简单 API。这使用户可以方便地在 Servlet 和 EJB 中执行并发的计划任务，从而提高呑吐量，缩短服务端程序的响应时间，很好地解决了在 J2EE 环境中执行用户自定义的多线程并发与计时器服务的问题。 <br />
<br />
Commonj Timer API 包括三个接口：TimerManager, Timer 和 TimerListener。应用程序可以通过 TimerManager 来定期调用 TimerListener。每个 TimerManager 的 shcedule 方法返回一个 Timer 对象。用户可以通过 TimerManager 的 JNDI 名称在管理环境的上下文中查找 TimerManager。 <br />
<br />
<br />
<br />
java.util.Timer、 CommonJ Timer 和 WebSphere Application Server Scheduler 为用户提供了不同级别的、适用与不同范围的计时器，用户可以根据各自的需求使用不同的计时器，表 1 列出了 java.util.Timer、Commonj Timer 和 WebSphere Application Server Scheduler 之间比较结果，用户在使用计时器时可以用来参照比较。 <br />
<br />
表 1. 计时器比较结果 <br />
<strong>java.util.Timer</strong> <br />
来源：Sun <br />
优点：易于使用轻量级 <br />
缺点：创建的线程会超出容器管理范围 <br />
适用范围：非 J2EE 环境 <br />
<strong><br />
Commonj Timer</strong> <br />
来源：BEA and IBM <br />
优点：解决了 java.util.Timer 创建的线程超出容器管理范围的问题；不同于 JMX Timer Service 与 JMX framework 之间的紧耦合，提供了更加友好和独立的 API <br />
缺点：timer 是瞬时的、非事务性的，并且运行于创建它的 JVM 中，不适合于集群环境 <br />
适用范围：J2EE 普通环境 <br />
<br />
<strong>java.util.Timer</strong> <br />
来源：WebSphere Application Server Scheduler <br />
优点：易于管理 具有持久性和事务性 具有灵活的时间定制方式 具有扩展性，适用于集群环境 <br />
缺点：与 WebSphere Application Server 紧耦合 <br />
适用范围：J2EE 普通和集群环境 <br />
<br />
详见：http://www.ibm.com/developerworks/cn/java/j-lo-timer/index.html<br />
</span><!-- Attachments -->
<img src ="http://www.blogjava.net/orangelizq/aggbug/227175.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/orangelizq/" target="_blank">桔子汁</a> 2008-09-05 11:46 <a href="http://www.blogjava.net/orangelizq/archive/2008/09/05/227175.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]java Serialization</title><link>http://www.blogjava.net/orangelizq/archive/2008/09/05/227169.html</link><dc:creator>桔子汁</dc:creator><author>桔子汁</author><pubDate>Fri, 05 Sep 2008 03:26:00 GMT</pubDate><guid>http://www.blogjava.net/orangelizq/archive/2008/09/05/227169.html</guid><wfw:comment>http://www.blogjava.net/orangelizq/comments/227169.html</wfw:comment><comments>http://www.blogjava.net/orangelizq/archive/2008/09/05/227169.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/orangelizq/comments/commentRss/227169.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/orangelizq/services/trackbacks/227169.html</trackback:ping><description><![CDATA[<div id="BlogArticleDetail" style="font-size: 14px"><strong><font size="3">1. 什么是Serialization?</font></strong><br />
<br />
串行化(Serialization)是计算机科学中的一个概念，它是指将对象存储到介质（如文件、内在缓冲区等）中或是以二进制方式通过网络传输。之后可以通过反串行化从这些连续的位数据重新构建一个与原始对象状态相同的对象，因此在特定情况下也可以说是得到一个副本，但并不是所有情况都这样。<br />
<br />
Java有Serialization API为开发者提供了一种标准的机制来串行化类。<br />
<br />
<font color="#c0c0c0"><font color="#000000"><strong><font size="3">2. 为什么要Serilzation?</font></strong></font><br />
<br />
</font>特别地，串行化主要有三种用途：<br />
1）作为一种持久化机制<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 如果使用的是FileOutputStream流的方式，则数据将被自动地写入文件中，<br />
2）作为一种复制机制<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 如果使用的是<code class="Literal">ByteArrayOutputStream</code>流的方式，数据将写入内存中的字节数组中。该字节数组可以用来创建初始对象的副本，<br />
3）作为一种通信机制<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 如果是使用套接字（Socket）流的方式，则数据自动地通过网络连接传输一另一个端点，并由这个端点上的程序来决定做什么。<br />
<br />
<font size="3"><strong>3. Serialization的基本用法</strong></font><strong>：<font size="3">默认机制</font></strong><br />
<br />
将要串行化的类必须实现java.io.Serializable接口，或者是继承实现了该接口的类。然后通过java.io.ObjectOutputStream类来实现持久化，如果用保存到文件上还需要用到java.io.FileOutputStream类。因为ObjectOutputStream被认为是java.io包中的高级类所以可用它来包装低级的类FileOutputStream。在持久化过程中调用的一个方法是ObjectOutputStream对象的writeObject(obj)方法。<br />
<br />
当要从文件中恢复对象时，则是使用java.io.OjbectInputStream与FileInputStream类，调用一方法是ObjectInputStream对象的readObject()方法。<br />
<br />
<strong>示例1：</strong><br />
<font color="#808080"><br />
import java.io.*;<br />
<br />
public class Cat implements Serializable {<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> private String name;<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> public Cat () {<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> this.name = "new cat";<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> }<br />
<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> public String getName() {<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> return this.name;<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> }<br />
<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> public void setName(String name) {<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> this.name = name;<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> }<br />
}<br />
<br />
<br />
import java.io.*;<br />
<br />
public class CatDemo {<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> public static void main(String[] args) {<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> Cat cat = new Cat();<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> try { //串行化<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> FileOutputStream fos = new FileOutputStream("catDemo.out");<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ObjectOutputStream oos = new ObjectOutputStream(fos);<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> System.out.println(" 1&gt; " + cat.getName());<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> cat.setName("My Cat"); &nbsp;<wbr>&nbsp;<wbr><br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> oos.writeObject(cat);<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> oos.close();&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr><br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> } catch (IOException ex) {<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ex.printStackTrace();<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> }<br />
<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> try { //反串行化<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> FileInputStream fis = new FileInputStream("catDemo.out");<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ObjectInputStream ois = new ObjectInputStream(fis);<br />
<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> cat = (Cat) ois.readObject();<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr><br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> System.out.println(" 2&gt; " + cat.getName());<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ois.close();<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> } catch (IOException ex) {<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ex.printStackTrace();<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> }<code>catch(ClassNotFoundException ex) {&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr><br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ex.printStackTrace();<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> }</code><br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> }<br />
}</font><br />
<br />
<br />
<font size="3"><strong>4. Serialization常见问题</strong></font><br />
<br />
正如前面提到的，所有可串行化的类必须直接或是通过继承方式间接地实现java.io.Serializable接口，由于Object类关没有实现这个接口，所以并不是所有类的对象都是可串行化的。像AWT与Swing的GUI组件、字符串、数组等都是可串行化的，而像一些系统级的类（Thread<code>，OutputStream</code> 等）和Socket类是不可串行化的。<br />
<br />
<font color="#0000ff">问题一：如果在一个可串行化的类中Has-As不可串行化的类该怎么处理？</font><br />
在这种情况下在运行时会抛出NotSerializableException<wbr>。<br />
<br />
为了解决类似问题，Java中提供了transient关键字来跳过对不可串行化类的对象的处理。但这依然可能会引起一些问题，在反串行化时，被标识为transient变量不会恢复到其原始状态，而是提供默认值，如示例２中的pig引用将赋值为null，age变量赋值为0;<br />
<br />
<em>附：基本类型和引用类型的默认值<br />
对象引用：null<br />
byte, short, int, long ：0<br />
float, double：0.0<br />
boolean：false<br />
char：'\u0000'(这是Unicode字符集的空格)</em><br />
<br />
<strong>示例2：</strong><br />
<code><font color="#808080">import java.io.*;<br />
public class NewPig2 implements Serializable {<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> private String newName;<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> private <font color="#0000ff"><strong>transient</strong></font> Pig pig = new Pig();<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> private <font color="#0000ff"><strong>transient</strong></font> int age = 2;&nbsp;<wbr>&nbsp;<wbr><br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> public NewPig2() {<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> newName = "new Pig 2";<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> //pig = new Pig();<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> }<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> public Pig getPig() {<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> return this.pig;<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> }<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> public void setName(String name) {<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> this.newName = name;<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> }<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> public String getName() {<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> return this.newName;<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> }<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> public int getAge() {<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> return this.age;<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> }<br />
}<br />
</font></code><code><br />
<font color="#0000ff">问题二：如果父类不可串行化，子类实现了Serializable会怎样？</font><br />
如果有一个Animal类是不可串行化的，而有一个Dog类继承自Animal类并且实现了Serializabl接口，则没有串行化时没有任何问题，但是在反串行化时将会重新调用Animal的构造函数，如示例3所示。<br />
<br />
示例3的运行结果如下：</code><code><br />
1&gt; No Color - new Dog<br />
2&gt; Green - My Dog<br />
4&gt; No Color - My Dog<br />
因为Animal不可串行化，所以必须运行构造函数，但不会在实现Serializable的反串行化类上运行构造函数。<br />
</code><code><br />
示例3：<br />
<font color="#808080"><br />
public class Animal {<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> private String color;<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> <font color="#333399">public Animal () {<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> this.color = "No Color";<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> }</font><br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> public void setColor(String color) {<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> this.color = color;<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> }<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> public String getColor () {<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> return this.color;<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> }<br />
}<br />
<br />
<br />
import java.io.*;<br />
public class Dog extends Animal implements Serializable {<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> private String name;<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> public Dog () {<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> this.name = "new Dog";<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> }<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> public String getName() {<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> return this.name;<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> }<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> public void setName(String name) {<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> this.name = name;<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> }<br />
}<br />
<br />
import java.io.*;<br />
public class DogTest {<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> public static void main(String[] args) {<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> Dog dog = new Dog();&nbsp;<wbr>&nbsp;<wbr><br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> System.out.println(" 1&gt; " + dog.getColor() + " - " + dog.getName());<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> dog.setColor("Green");<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> dog.setName("My Dog");<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> System.out.println(" 2&gt; " + dog.getColor() + " - " + dog.getName());<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> try {//串行化<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> FileOutputStream fos = new FileOutputStream("myDog.out");<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ObjectOutputStream oos = new ObjectOutputStream(fos);<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> oos.writeObject(dog);<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> oos.close();<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> } catch (Exception ex) {<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ex.printStackTrace();<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> }<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> try {//反串行化<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> FileInputStream fis = new FileInputStream("myDog.out");<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ObjectInputStream ois = new ObjectInputStream(fis);<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> dog = (Dog) ois.readObject(); &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr><br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> System.out.println(" 4&gt; " + dog.getColor() + " - " + dog.getName());<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ois.close();<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> } catch (Exception ex) {<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ex.printStackTrace();<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> }<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> }<br />
}<br />
<br />
</font><strong><font size="3">5.</font></strong></code><strong>自定义默认方法：使用writeOject和readObject<br />
</strong><font size="2"><br />
假如在一个可以串行化的类中有一个不可串行化的对象，但又想保存该对象的状态信息该如何是好？在这样情况下可以在这个可串行化的类中实现writeObject()和readObject()。<br />
<br />
<strong>示例4:</strong><br />
<font color="#808080">import java.io.*;<br />
import java.util.Scanner;<br />
<br />
public class NewPig3 implements Serializable {<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> private String newName;<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> private transient Pig pig = new Pig();<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> private transient int age = 2;<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr><br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> public NewPig3() {<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> newName = "new Pig 3";<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> //pig = new Pig();<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> }<br />
<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> <font color="#0000ff"><strong>private void writeObject(ObjectOutputStream oos) throws IOException {</strong></font><br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> oos.defaultWriteObject();<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> oos.writeChars(pig.getName());<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> //oos.writeInt(this.age);<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> }<br />
<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> <font color="#0000ff"><strong>private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {</strong></font><br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ois.defaultReadObject();<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> pig = new Pig();<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> Scanner in = new Scanner(ois);<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> if (in.hasNextLine()) {&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr><br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> pig.setName(in.nextLine());<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> }<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> }<br />
<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> public Pig getPig() {<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> return this.pig;<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> }<br />
<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> public void setName(String name) {<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> this.newName = name;<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> }<br />
<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> public String getName() {<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> return this.newName;<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> }<br />
<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> public int getAge() {<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> return this.age;<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> }<br />
}<br />
</font></font></div>
<img src ="http://www.blogjava.net/orangelizq/aggbug/227169.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/orangelizq/" target="_blank">桔子汁</a> 2008-09-05 11:26 <a href="http://www.blogjava.net/orangelizq/archive/2008/09/05/227169.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]java中byte转换int时为何与0xff进行与运算</title><link>http://www.blogjava.net/orangelizq/archive/2008/07/20/216228.html</link><dc:creator>桔子汁</dc:creator><author>桔子汁</author><pubDate>Sun, 20 Jul 2008 12:36:00 GMT</pubDate><guid>http://www.blogjava.net/orangelizq/archive/2008/07/20/216228.html</guid><wfw:comment>http://www.blogjava.net/orangelizq/comments/216228.html</wfw:comment><comments>http://www.blogjava.net/orangelizq/archive/2008/07/20/216228.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/orangelizq/comments/commentRss/216228.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/orangelizq/services/trackbacks/216228.html</trackback:ping><description><![CDATA[在剖析该问题前请看如下代码<br />
public static String bytes2HexString(byte[] b) {<br />
&nbsp;&nbsp;String ret = "";<br />
&nbsp;&nbsp;for (int i = 0; i &lt; b.length; i++) {<br />
&nbsp; &nbsp;String hex = Integer.toHexString(b[ i ] &amp; 0xFF);<br />
&nbsp; &nbsp;if (hex.length() == 1) {<br />
&nbsp; &nbsp; hex = '0' + hex;<br />
&nbsp; &nbsp;}<br />
&nbsp; &nbsp;ret += hex.toUpperCase();<br />
&nbsp;&nbsp;}<br />
&nbsp;&nbsp;return ret;<br />
}<br />
上面是将byte[]转化十六进制的字符串,注意这里b[ i ] &amp; 0xFF将一个byte和 0xFF进行了与运算,然后使用Integer.toHexString取得了十六进制字符串,可以看出<br />
b[ i ] &amp; 0xFF运算后得出的仍然是个int,那么为何要和 0xFF进行与运算呢?直接 Integer.toHexString(b[ i ]);,将byte强转为int不行吗?答案是不行的.<br />
<br />
其原因在于:<br />
1.byte的大小为8bits而int的大小为32bits<br />
2.java的二进制采用的是补码形式<br />
<br />
在这里先温习下计算机基础理论<br />
<br />
byte是一个字节保存的，有8个位，即8个0、1。<br />
8位的第一个位是符号位， <br />
也就是说0000 0001代表的是数字1 <br />
1000 0000代表的就是-1 <br />
所以正数最大位0111 1111，也就是数字127 <br />
负数最大为1111 1111，也就是数字-128<br />
<br />
上面说的是二进制原码，但是在java中采用的是补码的形式，下面介绍下什么是补码<br />
<br />
1、反码：<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;一个数如果是正，则它的反码与原码相同；<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;一个数如果是负，则符号位为1，其余各位是对原码取反；<br />
<br />
2、补码：利用溢出，我们可以将减法变成加法<br />
&nbsp; &nbsp;&nbsp; &nbsp; 对于十进制数，从9得到5可用减法：<br />
&nbsp; &nbsp;&nbsp; &nbsp; 9－4＝5&nbsp; &nbsp; 因为4+6＝10，我们可以将6作为4的补数<br />
&nbsp; &nbsp;&nbsp; &nbsp; 改写为加法：<br />
&nbsp; &nbsp;&nbsp; &nbsp; 9+6＝15（去掉高位1，也就是减10）得到5.<br />
<br />
&nbsp; &nbsp;&nbsp; &nbsp; 对于十六进制数，从c到5可用减法：<br />
&nbsp; &nbsp;&nbsp; &nbsp; c－7＝5&nbsp; &nbsp; 因为7+9＝16 将9作为7的补数<br />
&nbsp; &nbsp;&nbsp; &nbsp; 改写为加法：<br />
&nbsp; &nbsp;&nbsp; &nbsp; c+9＝15（去掉高位1，也就是减16）得到5.<br />
<br />
&nbsp; &nbsp; 在计算机中，如果我们用1个字节表示一个数，一个字节有8位，超过8位就进1，在内存中情况为（100000000），进位1被丢弃。<br />
<br />
&nbsp; &nbsp; ⑴一个数为正，则它的原码、反码、补码相同<br />
&nbsp; &nbsp; ⑵一个数为负，刚符号位为1，其余各位是对原码取反，然后整个数加1<br />
&nbsp; &nbsp; <br />
- 1的原码为&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 10000001<br />
- 1的反码为&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 11111110<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;+ 1<br />
- 1的补码为&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 11111111<br />
<br />
0的原码为&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;00000000<br />
0的反码为&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;11111111（正零和负零的反码相同）<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;+1<br />
0的补码为&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;100000000（舍掉打头的1，正零和负零的补码相同）<br />
<br />
Integer.toHexString的参数是int，如果不进行&amp;0xff，那么当一个byte会转换成int时，由于int是32位，而byte只有8位这时会进行补位，<br />
例如补码11111111的十进制数为-1转换为int时变为11111111111111111111111111111111好多1啊，呵呵！即0xffffffff但是这个数是不对的，这种补位就会造成误差。<br />
和0xff相与后，高24比特就会被清0了，结果就对了。<br />
<br />
----<br />
Java中的一个byte，其范围是-128~127的，而Integer.toHexString的参数本来是int，如果不进行&amp;0xff，那么当一个byte会转换成int时，对于负数，会做位扩展，举例来说，一个byte的-1（即0xff），会被转换成int的-1（即0xffffffff），那么转化出的结果就不是我们想要的了。<br />
<br />
而0xff默认是整形，所以，一个byte跟0xff相与会先将那个byte转化成整形运算，这样，结果中的高的24个比特就总会被清0，于是结果总是我们想要的。<br />
<br />
<img src ="http://www.blogjava.net/orangelizq/aggbug/216228.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/orangelizq/" target="_blank">桔子汁</a> 2008-07-20 20:36 <a href="http://www.blogjava.net/orangelizq/archive/2008/07/20/216228.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]十年学会编程</title><link>http://www.blogjava.net/orangelizq/archive/2008/07/16/215313.html</link><dc:creator>桔子汁</dc:creator><author>桔子汁</author><pubDate>Wed, 16 Jul 2008 13:07:00 GMT</pubDate><guid>http://www.blogjava.net/orangelizq/archive/2008/07/16/215313.html</guid><wfw:comment>http://www.blogjava.net/orangelizq/comments/215313.html</wfw:comment><comments>http://www.blogjava.net/orangelizq/archive/2008/07/16/215313.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/orangelizq/comments/commentRss/215313.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/orangelizq/services/trackbacks/215313.html</trackback:ping><description><![CDATA[<h1>十年学会编程</h1>
<p>著者： Peter Norvig</p>
<p>翻译： Dai Yuwen</p>
<hr />
<h2>为何人人都这么着急？</h2>
信步走进任何一家书店，你会看到名为《如何在7天内学会Java》的书，还有各种各样类似的书：在几天内或几小时内学会Visual Basic, Windows, Internet等等，一眼望不到尽头。我在<a href="http://www.amazon.com/">Amazon</a> 上做了如下的<a href="http://www.amazon.com/exec/obidos/tg/browse/-/468558/104-5938873-6579160"> 强力检索 </a>：
<pre>     <a href="http://www.amazon.com/exec/obidos/search-handle-url/ix=books&amp;rank=%2Bfeaturedrank&amp;fqp=power%01pubdate%3A%20after%201992%20and%20title%3A%20days%20and%0D%20%28title%3A%20learn%20or%20title%3A%20teach%20yourself%29&amp;sz=25&amp;pg=1/ref=s_b_np">pubdate: after 1992 and title: days and</a>
<a href="http://www.amazon.com/exec/obidos/search-handle-url/ix=books&amp;rank=%2Bfeaturedrank&amp;fqp=power%01pubdate%3A%20after%201992%20and%20title%3A%20days%20and%0D%20%28title%3A%20learn%20or%20title%3A%20teach%20yourself%29&amp;sz=25&amp;pg=1/ref=s_b_np">(title: learn or title: teach yourself)</a></pre>
得到了248个结果。前78个都是计算机类书籍（第79个是 <a href="http://www.amazon.com/exec/obidos/ASIN/0781802245/"><em>Learn Bengali in 30 days</em></a>）。我用<a href="http://www.amazon.com/exec/obidos/search-handle-url/ix=books&amp;rank=%2Bfeaturedrank&amp;fqp=power%01pubdate%3A%20after%201992%20and%20title%3A%20hours%20and%0D%20%28title%3A%20learn%20or%20title%3A%20teach%20yourself%29&amp;sz=25&amp;pg=3/ref=s_b_np">"hours"</a>替换"days"，得到了类似的结果：更多的253书。前77本是计算机类书籍，第78本是 <a href="http://www.amazon.com/exec/obidos/ASIN/0028638999/"><em>Teach Yourself Grammar and Style in 24 Hours</em></a>。在前200本书中，有96% 是计算机类书籍。
<p>结论是：要么人们都在急急忙忙地学习计算机，要么计算机比其它任何东西都容易学。没有书籍教你在几天内学会古典音乐、量子物理，或者是养狗。 </p>
<p>让我们分析一下，象一本名为<em><a href="http://www.amazon.com/exec/obidos/ISBN=1556225679/4094-7934802-027992">《三天内学会Pascal》</a></em>的书意味着什么： </p>
<ul>
    <li><strong>学习：</strong> 在三天里，你没有时间写一些重大的程序，并从成功或失败中得益。你没有时间与有经验的程序员合作，并理解在那样的环境下工作是怎么回事。一句话，你不会有时间学到太多东西。因此他们只能谈论一些肤浅的东西，而不是深入的理解。正如亚力山大教皇所说，浅尝辄止是危险的事情。
    <p>&nbsp;</p>
    <li><strong>Pascal：</strong> 在三天时间里，你可能学会Pascal的语法（如果你已经学过类似的语言），但你学不到更多的如何使用这些语法的知识。也就是说，假如你曾是个BASIC程序员，你可以学着用Pascal语法写出BASIC风格的程序，但你不可能了解Pascal真正的好处（和坏处）。那么关键是什么？ <a href="http://www-pu.informatik.uni-tuebingen.de/users/klaeren/epigrams.html">Alan Perlis</a> 说过：&#8220;一种不改变你编程的思维方式的语言，不值得去学。&#8221; 一种可能的情况是：你必须学一点儿Pascal（或可能性更大的象Visual Basic 或 JavaScript之类），因为你为了完成某种特定的任务，需要与一个现存的工具建立接口。不过那不是学习如何编程，而是在学习如何完成那个任务。
    <p>&nbsp;</p>
    <li><strong>三天内：</strong> 很不幸，这不够，原因由下一节告诉我们。 </li>
</ul>
<h2>在十年里学会编程</h2>
研究表明 (<a href="http://www.amazon.com/exec/obidos/ASIN/0805803092">Hayes</a>，<a href="http://www.amazon.com/exec/obidos/ASIN/034531509X/">Bloom</a>)在任何一种领域内，象下棋、作曲、绘画、钢琴演奏、游泳、网球、以及原子物理学和拓扑学，等等，要达到专家水平大约都要化十年时间。没有真正的捷径：即使是莫扎特，4岁时就是音乐神童，13年后才开始写出世界级的作品。在另一方面，披头士似乎在1964年的Ed Sullivan表演上一炮走红。但他们从1957年就开始表演，在获得大众青睐后，他们的第一个重大成功，<em>Sgt. Peppers</em>，是1967年发行的。Samuel Johnson （塞缪尔&#183;约翰逊，英国辞典编纂家及作家）认为要花比十年更长的时间：&#8220;在任何领域中出类拔萃都要用毕生的劳作来取得；它不可能用较低的代价获得。&#8221; 而Chaucer（乔叟，英国诗人）感叹到：&#8220;人生短暂，学海无涯。&#8221;
<p>这是我为编程成功开出的方子： </p>
<ul>
    <li>设法对编程感兴趣，并且因为它有趣而编一些程序。确保编程一直充满足够乐趣，这样你才愿意投入十年宝贵时间。
    <p>&nbsp;</p>
    <li>与其他程序员交流； 阅读其它程序。这比任何书本或训练课程都重要。
    <p>&nbsp;</p>
    <li>写程序。 最好的学习方式是 <a href="http://www.engines4ed.org/hyperbook/nodes/NODE-120-pg.html">从实践中学习</a>。 用更技术性的话说，&#8220;在一个给定的领域内，个人的最大能力不是自动地由扩展了的经验取得的，但即使是高度有经验的人也可以通过有意识的努力来提高自己的能力&#8221; <a href="http://www2.umassd.edu/swpi/DesignInCS/expertise.html">(p. 366)</a> 和 &#8220;最有效的学习需要因人而异的适当难度，目标明确的任务，丰富的信息反馈，以及重复的机会和错误修正。&#8221; (p. 20-21) 此书 <em><a href="http://www.amazon.com/exec/obidos/ASIN/0521357349">Cognition in Practice: Mind，Mathematics，and Culture in Everyday Life</a></em> 是阐明此观点的令人感兴趣的参考文献。
    <p>&nbsp;</p>
    <li>如果愿意，在大学里呆上4年或更长（在研究生院里）。你会接触到一些需要学历证明的工作，你会对此领域有更深的理解。如果你不喜欢学校，你可以（通过一些贡献）在工作中获得相似的经验。在任何情况下，光啃书本是不够的。Eric Raymond，<em>The New Hacker's Dictionary</em>一书的作者，说过，&#8220;计算机科学不能把任何人变成编程专家，就象光研究刷子和颜料不会使人变成画家一样。&#8221; 我雇佣过的最好的程序员之一仅有高中程度；他做出了许多<a href="http://www.xemacs.org/">优秀的 </a><a href="http://www.mozilla.org/">软件</a>，有他自己的<a href="http://groups.google.com/groups?q=alt.fan.jwz&amp;meta=site%3Dgroups">新闻组</a>，而且通过股票期权，他无疑比我富有的多。
    <p>&nbsp;</p>
    <li>和其他程序员一起做项目。在其中的一些项目中作为最好的程序员； 而在另一些项目中是最差的。当你是最好的，你能测试领导项目的能力，用你的观点激发别人。当你是最差的，你学习杰出者是怎么做的，了解他们不喜欢做什么（因为他们吩咐你做事）。
    <p>&nbsp;</p>
    <li>在其他程序员 <em>之后</em>接手项目。使自己理解别人写的程序。当程序的原作者不在的时候，研究什么需要理解并且修改它。思考如何设计你的程序以便后来者的维护。
    <p>&nbsp;</p>
    <li>学习至少半打的编程语言。包括一种支持类抽象的语言（象Java 或C++），一种支持函数化抽象的语言（象Lisp或ML），一种支持语法抽象的语言（象 Lisp），一种支持声明规格说明的语言（象Prolog或C++ 的模板），一种支持共行程序（coroutine）的语言（象Icon或Scheme），一种支持并行的语言（象Sisal）。
    <p>&nbsp;</p>
    <li>请记住&#8220;计算机科学&#8221;中有&#8220;计算机&#8221;一词。了解你的计算机要花多长时间执行一条指令，从内存中取一个字（有cache），从磁盘中读取连续的字，和在磁盘中找到新的位置。（<a href="http://daiyuwen.freeshell.org/gb/misc/21-days-cn.html#answers">答案</a>）
    <p>&nbsp;</p>
    <li>参与一种语言标准化的工作。它可以是ANSI C++委员会，也可以是决定你周围小范围内的编程风格是应该两个还是四个空格缩进。通过任何一种方式，你了解到其他人在某种语言中的想法，他们的理解深度，甚至一些他们这样想的原因。
    <p>&nbsp;</p>
    <li>找到适当的理由尽快地从语言标准化的努力中脱身。 </li>
</ul>
<p>明白了这些，仅从书本中你能得到多少就成了一个问题。在我第一个孩子出生前，我读了所有的（关于育儿的）<em>How to </em>书籍，仍然感觉是个手足无措的新手。30个月以后，我的第二个孩子快要出生了，我回头温习这些书了吗？ 没有。相反，我依靠我的个人经验，它比专家写的数千页书更有用和可靠。
<p>Fred Brooks在他的随笔 <em><a href="http://citeseer.nj.nec.com/context/7718/0">《没有银弹》</a></em> 中定出了一个寻找优秀软件设计者的三步计划： </p>
<ol>
    <li>尽可能早地，有系统地识别顶级的设计人员。
    <p>&nbsp;</p>
    <li>为设计人员指派一位职业导师，负责他们技术方面的成长，仔细地为他们规划职业生涯。
    <p>&nbsp;</p>
    <li>为成长中的设计人员提供相互交流和学习的机会。
    <p>&nbsp;</p>
    </li>
</ol>
此计划假设某些人已经具备了杰出设计者的必要才能； 要做的只是如何恰当地诱导他们。 <a href="http://www-pu.informatik.uni-tuebingen.de/users/klaeren/epigrams.html">Alan Perlis</a> 说得更简明扼要：&#8220;每个人都能被教会雕刻：对米开朗其罗而言，反倒是告诉他哪些事不要做。同样的道理也适用于优秀的程序员。&#8221;
<p>所以尽管买那本Java的书吧。你可能会从中学到点儿东西。但作为一个程序员，你不会在几天内或24小时内，哪怕是几个月内改变你的人生，或你实际的水平。 </p>
<p>&nbsp;</p>
<h2>参考文献</h2>
<p>Bloom, Benjamin (ed.) <em><a href="http://www.amazon.com/exec/obidos/ASIN/034531509X">Developing Talent in Young People</a></em>, Ballantine, 1985. </p>
<p>Brooks, Fred, <em><a href="http://citeseer.nj.nec.com/context/7718/0">No Silver Bullets</a></em>, IEEE Computer, vol. 20, no. 4, 1987, p. 10-19. </p>
<p>Hayes, John R., <em><a href="http://www.amazon.com/exec/obidos/ASIN/0805803092">Complete Problem Solver</a></em> Lawrence Erlbaum, 1989. </p>
<p>Lave, Jean, <em><a href="http://www.amazon.com/exec/obidos/ASIN/0521357349">Cognition in Practice: Mind, Mathematics, and Culture in Everyday Life</a></em>, Cambridge University Press, 1988. <a name="answers">
<h2>答案</h2>
</a>2001年夏天典型的1GHz PC的各种操作要花的时间
<p>&nbsp;</p>
<p>
<table cellspacing="2" cellpadding="2" border="1">
    <tbody>
        <tr>
            <td>执行一条指令</td>
            <td>1 nsec = (1/1,000,000,000) sec </td>
        </tr>
        <tr>
            <td>从L1 cache memory 中取一个字</td>
            <td>2 nsec </td>
        </tr>
        <tr>
            <td>从内存中取一个字</td>
            <td>10 nsec </td>
        </tr>
        <tr>
            <td>从磁盘的连续位置取一个字</td>
            <td>200 nsec </td>
        </tr>
        <tr>
            <td>从磁盘的新位置取一个字(seek) </td>
            <td>8,000,000nsec = 8msec </td>
        </tr>
    </tbody>
</table>
<h2>附录：语言的选择</h2>
不少人问我，他们首先该学哪种编程语言。没有绝对的答案，不过请考虑以下几点：
<p>&nbsp;</p>
<ul>
    <li><em>用你的朋友的</em>。当被问起&#8220;我该用哪种操作系统，Windows，Unix，还是Mac？&#8221;，我总是回答：&#8220;你朋友用什么，你就用什么。&#8221; 你从朋友那能学到知识，这种优势可以抵销不同操作系统或语言之间本质的差异。也考虑你将来的朋友：程序员社区 — 你将成为它的一部分如果你继续往前走的话。你选择的语言是否有一个成长中的社区，还是人数不多、即将消亡？ 有没有书籍、网站、在线论坛回答你的问题？ 你喜欢论坛里的那些人吗？
    <p>&nbsp;</p>
    <li><em>Keep it simple, stupid.</em> 象C++和Java这样的语言是为经验丰富的程序员组成的团队进行专业开发而设计的，他们专注于代码运行时的效率。因此，这些语言有些部分非常复杂。 而你关注的是如何编程，不需要那些复杂性。你需要的是这样的语言： 对单个的编程新手来说，它易学易记。
    <p>&nbsp;</p>
    <li><em>练习</em>。你偏爱哪种学弹钢琴的方式：通常的交互式的方式，你一按下琴键就能听到音符；还是&#8220;批量&#8221;模式，你只有弹完整首曲子才能听到音符？显然，用交互模式学习弹钢琴更容易些，编程也一样。坚持用交互模式学习并使用一种语言。 </li>
</ul>
<p>有了上面的准则，我推荐的第一个编程语言是<a href="http://python.org/">Python</a>或<a href="http://www.schemers.org/">Scheme</a>。因人而异，还有其它好的选择。如果你的年纪是10岁以下，你可能更喜欢<a href="http://alice.org/">Alice</a>。关键是你要选择并开始实践。
<h2>附录：书籍和其它资源</h2>
不少人问我，他们该从什么书籍或网页开始学起。我重申&#8220;仅从书本里学习是不够的。&#8221; 但我还是推荐：
<p>&nbsp;</p>
<ul>
    <li><strong>Scheme:</strong><a href="http://www.amazon.com/gp/product/0262011530"> Structure and Interpretation of Computer Programs (Abelson &amp; Sussman)</a>可能是最好的计算机科学的入门书，而且它的确把讲授编程作为理解计算机科学的一种方法。但它具有挑战性，会让许多通过其它方式可能成功的人望而却步。
    <p>&nbsp;</p>
    <li><strong>Scheme:</strong><a href="http://www.amazon.com/gp/product/0262062186"> How to Design Programs (Felleisen et al.)</a>是关于如何用一种优美的、函数化的方式设计程序的最好的书之一。
    <p>&nbsp;</p>
    <li><strong>Python:</strong><a href="http://www.amazon.com/gp/product/1887902996"> Python Programming: An Intro to CS (Zelle)</a>是优秀的Python入门指导。
    <p>&nbsp;</p>
    <li><strong>Python:</strong><a href="http://python.org/"> Python.org</a>上有许多在线<a href="http://wiki.python.org/moin/BeginnersGuide">指导</a>。
    <p>&nbsp;</p>
    <li><strong>Oz:</strong><a href="http://www.amazon.com/gp/product/0262220695"> Concepts, Techniques, and Models of Computer Programming (Van Roy &amp; Haridi)</a> 被视为Abelson &amp; Sussman的当代继承者。它是对编程的高层次概念的巡视。涉及的范围比Abelson &amp; Sussman更广，同时可能更容易学习和跟进。 它用了叫做Oz的语言，不太知名，却可以作为学习其它语言的基础。 </li>
</ul>
<p>&nbsp;</p>
<hr />
<h2>脚注</h2>
<p>This page also available in <a href="http://www1.neweb.ne.jp/wa/yamdas/column/technique/21-daysj.html">Japanese translation</a> thanks to Yasushi Murakawa, in <a href="http://loro.sf.net/notes/21-dias.html">Spanish translation</a> thanks to Carlos Rueda and in <a href="http://purl.net/stefan_ram/html/21-tage">German translation</a> thanks to Stefan Ram. </p>
<p>T. Capey points out that the <a href="http://www.amazon.com/exec/obidos/ASIN/0805803092">Complete Problem Solver</a> page on Amazon now has the "Teach Yourself Bengali in 21 days" and "Teach Yourself Grammar and Style" books under the "Customers who shopped for this item also shopped for these items" section. I guess that a large portion of the people who look at that book are coming from this page. </p>
<hr />
<a href="http://www.norvig.com/index.html"><em>Peter Norvig</em>(Copyright 2001)</a> 
<img src ="http://www.blogjava.net/orangelizq/aggbug/215313.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/orangelizq/" target="_blank">桔子汁</a> 2008-07-16 21:07 <a href="http://www.blogjava.net/orangelizq/archive/2008/07/16/215313.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]软件版本号定义 </title><link>http://www.blogjava.net/orangelizq/archive/2008/07/07/213053.html</link><dc:creator>桔子汁</dc:creator><author>桔子汁</author><pubDate>Mon, 07 Jul 2008 08:05:00 GMT</pubDate><guid>http://www.blogjava.net/orangelizq/archive/2008/07/07/213053.html</guid><wfw:comment>http://www.blogjava.net/orangelizq/comments/213053.html</wfw:comment><comments>http://www.blogjava.net/orangelizq/archive/2008/07/07/213053.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/orangelizq/comments/commentRss/213053.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/orangelizq/services/trackbacks/213053.html</trackback:ping><description><![CDATA[<p>版本控制比较普遍的 3 种命名格式 :<br />
<strong>一、GNU 风格的版本号命名格式 :</strong><br />
主版本号 . 子版本号 [. 修正版本号 [. 编译版本号 ]]<br />
Major_Version_Number.Minor_Version_Number[.Revision_Number[.Build_Number]]<br />
示例 : 1.2.1, 2.0, 5.0.0 build-13124<br />
<br />
<strong>二、Windows 风格的版本号命名格式 :</strong><br />
主版本号 . 子版本号 [ 修正版本号 [. 编译版本号 ]]<br />
Major_Version_Number.Minor_Version_Number[Revision_Number[.Build_Number]]<br />
示例: 1.21, 2.0<br />
<br />
<strong>三、.Net Framework 风格的版本号命名格式:</strong><br />
主版本号.子版本号[.编译版本号[.修正版本号]]<br />
Major_Version_Number.Minor_Version_Number[.Build_Number[.Revision_Number]]<br />
版本号由二至四个部分组成：主版本号、次版本号、内部版本号和修订号。主版本号和次版本号是必选的；内部版本号和修订号是可选的，但是如果定义了修订号部分，则内部版本号就是必选的。所有定义的部分都必须是大于或等于 0 的整数。<br />
<br />
<strong>应根据下面的约定使用这些部分：</strong><br />
Major ：具有相同名称但不同主版本号的程序集不可互换。例如，这适用于对产品的大量重写，这些重写使得无法实现向后兼容性。<br />
Minor ：如果两个程序集的名称和主版本号相同，而次版本号不同，这指示显著增强，但照顾到了向后兼容性。例如，这适用于产品的修正版或完全向后兼容的新版本。<br />
Build ：内部版本号的不同表示对相同源所作的重新编译。这适合于更改处理器、平台或编译器的情况。<br />
Revision ：名称、主版本号和次版本号都相同但修订号不同的程序集应是完全可互换的。这适用于修复以前发布的程序集中的安全漏洞。<br />
程序集的只有内部版本号或修订号不同的后续版本被认为是先前版本的修补程序 (Hotfix) 更新。<br />
<br />
<strong>版本号管理策略</strong><br />
<strong>一、GNU 风格的版本号管理策略：</strong><br />
1．项目初版本时，版本号可以为 0.1 或 0.1.0, 也可以为 1.0 或 1.0.0，如果你为人很低调，我想你会选择那个主版本号为 0 的方式；<br />
2．当项目在进行了局部修改或 bug 修正时，主版本号和子版本号都不变，修正版本号加 1；<br />
3. 当项目在原有的基础上增加了部分功能时，主版本号不变，子版本号加 1，修正版本号复位为 0，因而可以被忽略掉；<br />
4．当项目在进行了重大修改或局部修正累积较多，而导致项目整体发生全局变化时，主版本号加 1；<br />
5．另外，编译版本号一般是编译器在编译过程中自动生成的，我们只定义其格式，并不进行人为控制。<br />
<br />
<strong>二、Window 下的版本号管理策略：</strong><br />
1．项目初版时，版本号为 1.0 或 1.00；<br />
2. 当项目在进行了局部修改或 bug 修正时，主版本号和子版本号都不变，修正版本号加 1；<br />
3. 当项目在原有的基础上增加了部分功能时，主版本号不变，子版本号加 1，修正版本号复位为 0，因而可以被忽略掉；<br />
4. 当项目在进行了重大修改或局部修正累积较多，而导致项目整体发生全局变化时，主版本号加 1；<br />
5. 另外 , 编译版本号一般是编译器在编译过程中自动生成的，我们只定义其格式，并不进行人为控制。<br />
另外，还可以在版本号后面加入 Alpha、Beta、Gamma、Current、RC (Release Candidate)、Release、Stable 等后缀，在这些后缀后面还可以加入 1 位数字的版本号。<br />
对于用户来说，如果某个软件的主版本号进行了升级，用户还想继续那个软件，则发行软件的公司一般要对用户收取升级费用；而如果子版本号或修正版本号发生了升级，一般来说是免费的。<br />
<br />
=============附录软件版本名称============<br />
<strong>&#945;（alphal） 内部测试版</strong><br />
&#945;版，此版本表示该软件仅仅是一个初步完成品，通常只在软件开发者内部交流，也有很少一部分发布给专业测试人员。一般而言，该版本软件的 bug 较多，普通用户最好不要安装。<br />
<strong>&#946;（beta）外部测试版</strong><br />
该版本相对于&#945;版已有了很大的改进，消除了严重的错误，但还是存在着一些缺陷，需要经过大规模的发布测试来进一步消除。这一版本通常由软件公司免费发布，用户可从相关的站点下载。通过一些专业爱好者的测试，将结果反馈给开发者，开发者们再进行有针对性的修改。该版本也不适合一般用户安装。<br />
<strong>&#947;（gamma）版</strong><br />
该版本已经相当成熟了，与即将发行的正式版相差无几，如果用户实在等不及了，尽可以装上一试。<br />
<strong>trial（试用版）</strong><br />
试用版软件在最近的几年里颇为流行，主要是得益于互联网的迅速发展。该版本软件通常都有时间限制，过期之后用户如果希望继续使用，一般得交纳一定的费用进行注册或购买。有些试用版软件还在功能上做了一定的限制。<br />
<strong>unregistered（未注册版）</strong><br />
未注册版与试用版极其类似，只是未注册版通常没有时间限制，在功能上相对于正式版做了一定的限制，例如绝大多数网络电话软件的注册版和未注册版，两者之间在通话质量上有很大差距。还有些虽然在使用上与正式版毫无二致，但是动不动就会弹出一个恼人的消息框来提醒你注册，如看图软件acdsee、智能陈桥汉字输入软件等。<br />
<strong>demo 演示版</strong><br />
在非正式版软件中，该版本的知名度最大。demo版仅仅集成了正式版中的几个功能，颇有点像 unregistered。不同的是，demo版一般不能通过升级或注册的方法变为正式版。<br />
以上是软件正式版本推出之前的几个版本，&#945;、&#946;、&#947;可以称为测试版，大凡成熟软件总会有多个测试版，如 windows 98 的&#946;版，前前后后将近有10个。这么多的测试版一方面为了最终产品尽可能地满足用户的需要，另一方面也尽量减少了软件中的bug 。而 trial 、unregistered 、demo有时统称为演示版，这一类版本的广告色彩较浓，颇有点先尝后买的味道，对于普通用户而言自然是可以免费尝鲜了。<br />
<strong>正式版，不同类型的软件的正式版本通常也有区别。</strong><br />
<strong>release 最终释放版</strong><br />
该版本意味"最终释放版"，在出了一系列的测试版之后，终归会有一个正式版本，对于用户而言，购买该版本的软件绝对不会错。该版本有时也称为标准版。一般情况下，release不会以单词形式出现在软件封面上，取而代之的是符号 (r) ，如 windows nt(r) 4.0、ms-dos(r) 6.22 等。<br />
<strong>registered 注册版</strong><br />
很显然，该版本是与 unregistered 相对的注册版。注册版、release和下面所讲的standard版一样，都是软件的正式版本，只是注册版软件的前身有很大一部分是从网上下载的。<br />
<strong>standard 标准版</strong><br />
这是最常见的标准版，不论是什么软件，标准版一定存在。标准版中包含了该软件的基本组件及一些常用功能，可以满足一般用户的需求。其价格相对高一级版本而言还是"平易近人"的。<br />
<strong>deluxe 豪华版</strong><br />
顾名思义即为"豪华版"。豪华版通常是相对于标准版而言的，主要区别是多了几项功能，价格当然会高出一大块，不推荐一般用户购买。此版本通常是为那些追求"完美"的专业用户所准备的。<br />
<strong>reference</strong><br />
该版本型号常见于百科全书中，比较有名的是微软的encarta系列。 reference是最高级别，其包含的主题、图像、影片剪辑等相对于standard和deluxe版均有大幅增加，容量由一张光盘猛增至三张光盘，并且加入了很强的交互功能，当然价格也不菲。可以这么说，这一版本的百科全书才能算是真正的百科全书，也是发烧友们收藏的首选。<br />
<strong>professional（专业版）</strong><br />
专业版是针对某些特定的开发工具软件而言的。专业版中有许多内容是标准版中所没有的，这些内容对于一个专业的软件开发人员来说是极为重要的。如微软的visual foxpro标准版并不具备编译成可执行文件的功能，这对于一个完整的开发项目而言显然是无法忍受的，若客户机上没有foxpro将不能使用。如果用专业版就没有这个问题了。<br />
<strong>enterprise（企业版）</strong><br />
企业版是开发类软件中的极品（相当于百科全书中的reference版）。拥有一套这种版本的软件可以毫无障碍地开发任何级别的应用软件。如著名的visual c++的企业版相对于专业版来说增加了几个附加的特性，如sql调试、扩展的存储过程向导、支持as/400对ole db的访问等。而这一版本的价格也是普通用户无法接受的。如微软的visual studios 6.0 enterprise 中文版的价格为 23000 元。<br />
<strong>其他版本，除了以上介绍的一些版本外，还有一些专有版本名称。</strong><br />
<strong>update（升级版）</strong><br />
升级版的软件是不能独立使用的，该版本的软件在安装过程中会搜索原有的正式版，如果不存在，则拒绝执行下一步。如microsoft office 2000升级版、windows 9x升级版等等。<br />
<strong>oem版</strong><br />
oem 版通常是捆绑在硬件中而不单独销售的版本。将自己的产品交给别的公司去卖，保留自己的著作权，双方互惠互利，一举两得。<br />
<strong>单机（网络）版</strong><br />
网络版在功能、结构上远比单机版复杂，如果留心一下软件的报价，你就会发现某些软件单机版和网络版的价格相差非常大，有些网络版甚至多一个客户端口就要加不少钱。<br />
<strong>普及版</strong><br />
该版本有时也会被称为共享版，其特点是价格便宜（有些甚至完全免费）、功能单一、针对性强（当然也有占领市场、打击盗版等因素）。与试用版不同的是，该版本的软件一般不会有时间上的限制。当然，如果用户想升级，最好还是去购买正式版。<br />
Enhance 增强版或者加强版 属于正式版<br />
Free 自由版<br />
Full version 完全版 属于正式版<br />
shareware 共享版<br />
Release 发行版 有时间限制<br />
Upgrade 升级版<br />
Retail 零售版<br />
Cardware 属共享软件的一种，只要给作者回复一封电邮或明信片即可。（有的作者并由此提供注册码等），目前这种形式已不多见。<br />
Plus 属增强版，不过这种大部分是在程序界面及多媒体功能上增强。<br />
Preview 预览版<br />
Corporation &amp; Enterprise 企业版<br />
Standard 标准版<br />
Mini 迷你版也叫精简版只有最基本的功能<br />
Premium -- 贵价版<br />
Professional -- 专业版<br />
Express -- 特别版<br />
Deluxe -- 豪华版<br />
Regged -- 已注册版<br />
CN -- 简体中文版<br />
CHT -- 繁体中文版<br />
EN -- 英文版<br />
Multilanguage -- 多语言版 </p>
<img src ="http://www.blogjava.net/orangelizq/aggbug/213053.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/orangelizq/" target="_blank">桔子汁</a> 2008-07-07 16:05 <a href="http://www.blogjava.net/orangelizq/archive/2008/07/07/213053.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>