﻿<?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-Bacoo的程序人生！-随笔分类-Java</title><link>http://www.blogjava.net/bacoo/category/28259.html</link><description>鉴证我学习Java的历程！</description><language>zh-cn</language><lastBuildDate>Tue, 11 Mar 2008 22:07:58 GMT</lastBuildDate><pubDate>Tue, 11 Mar 2008 22:07:58 GMT</pubDate><ttl>60</ttl><item><title>assert使用小结</title><link>http://www.blogjava.net/bacoo/archive/2008/03/11/185491.html</link><dc:creator>bacoo</dc:creator><author>bacoo</author><pubDate>Tue, 11 Mar 2008 14:00:00 GMT</pubDate><guid>http://www.blogjava.net/bacoo/archive/2008/03/11/185491.html</guid><wfw:comment>http://www.blogjava.net/bacoo/comments/185491.html</wfw:comment><comments>http://www.blogjava.net/bacoo/archive/2008/03/11/185491.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/bacoo/comments/commentRss/185491.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/bacoo/services/trackbacks/185491.html</trackback:ping><description><![CDATA[<p>assert expression1;<br />
assert expression1:expression2;<br />
如果expression1为true，则不抛出错误，程序正常运行，expression2也不会执行。<br />
如果expression1为false，则抛出异常，程序中断跳出，expression2执行。</p>
<p>一般来说，不要在expression1、expression2中使用函数的返回值；<br />
不要将其使用在public函数中检查输入参数，但可以用于private函数中检测输入参数。<br />
</p>
<p>使用时，编译时需要用javac -source；执行时需要使用java -ea。<br />
</p>
<p><br />
个人的一点理解：使用assert只是为了帮助我们调试程序，因此使用assert所遵循的原则就是&#8220;不能因为有了assert的存在而使程序的结构发生任何的改变&#8221;，说白了就是&#8220;如果把assert部分删除了，程序依然不会有任何的问题，只不过不能帮助我们检查出一些错误来了&#8221;，因此使用assert的时候不应该在表达式中使用函数，因为一旦把这句assert语句删除后，程序的结构就改变了，这不符合上述提到的原则！</p>
<p>&nbsp;</p>
<p>&nbsp;附上一篇写得很不错的原文：</p>
<p style="font-size: 25px; color: rgb(55,72,145); font-family: lucida handwirting italic">深入解析Java的assertion</p>
<p><a name="1"><span class="atitle2">一、assertion的语法和语义</span></a> </p>
<p>&nbsp;&nbsp;&nbsp; J2SE 1.4在语言上提供了一个新特性，就是assertion(断言)功能，它是该版本在Java语言方面最大的革新。在软件开发中，assertion是一种经典的调试、测试方式，本文将深入解析assertion功能的使用以及其设计理念，并给出相关的例子 。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; assertion(断言)在软件开发中是一种常用的调试方式，很多开发语言中都支持这种机制，如C，C++和Eiffel等，但是支持的形式不尽相同，有的是通过语言本身、有的是通过库函数等。另外，从理论上来说，通过assertion方式可以证明程序的正确性，但是这是一项相当复杂的工作，目前还没有太多的实践意义。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在实现中，assertion就是在程序中的一条语句，它对一个boolean表达式进行检查，一个正确程序必须保证这个boolean表达式的值为true；如果该值为false，说明程序已经处于不正确的状态下，系统将给出警告或退出。一般来说，assertion用于保证程序最基本、关键的正确性。assertion检查通常在开发和测试时开启。为了提高性能，在软件发布后，assertion检查通常是关闭的。下面简单介绍一下Java中assertion的实现。</p>
<p><span class="atitle3">1．1) 语法表示</span></p>
<p>在语法上，为了支持assertion，Java增加了一个关键字assert。它包括两种表达式，分别如下：</p>
<ol class="n01">
    <li>assert expression1;
    <li>assert expression1: expression2; </li>
</ol>
<p>在两种表达式中，expression1表示一个boolean表达式，expression2表示一个基本类型或者是一个对象(Object) ，基本类型包括boolean,char,double,float,int和long。由于所有类都为Object的子类，因此这个参数可以用于所有对象。</p>
<p><span class="atitle3">1．2) 语义含义</span></p>
<p>在运行时，如果关闭了assertion功能，这些语句将不起任何作用。如果打开了assertion功能，那么expression1的值将被计算，如果它的值为false，该语句强抛出一个AssertionError对象。如果assertion语句包括expression2参数，程序将计算出expression2的结果，然后将这个结果作为AssertionError的构造函数的参数，来创建AssertionError对象，并抛出该对象；如果expression1值为true，expression2将不被计算。</p>
<p>一种特殊情况是，如果在计算表达式时，表达式本身抛出Exception，那么assert将停止运行，而抛出这个Exception。</p>
<p><span class="atitle3">1．3) 一些assertion例子</span></p>
<p>下面是一些Assert的例子。</p>
<ol class="n01">
    <li>assert　　0 &lt; value;
    <li>assert　　0 &lt; value:"value="+value;
    <li>assert　　ref != null:"ref doesn't equal null";
    <li>assert　　isBalanced(); </li>
</ol>
<p><span class="atitle3">1．4) 编译</span></p>
<p>由于assert是一个新关键字，使用老版本的JDK是无法编译带有assert的源程序。因此，我们必须使用JDK1.4(或者更新)的Java编译器，在使用Javac命令时，我们必须加上-source 1.4作为参数。-source 1.4表示使用JDK 1.4版本的方式来编译源代码，否则编译就不能通过，因为缺省的Javac编译器使用JDK1.3的语法规则。</p>
<p>一个简单的例子如下：</p>
<pre>javac      -source   1.4    test.java</pre>
<p><span class="atitle3">1．5) 运行</span></p>
<p>由于带有assert语句的程序运行时，使用了新的ClassLoader和Class类，因此，这种程序必须在JDK1.4(或者更高版本)的JRE下运行，而不能在老版本的JRE下运行。</p>
<p>由于我们可以选择开启assertion功能，或者不开启，另外我们还可以开启一部分类或包的assertion功能，所以运行选项变得有些复杂。通过这些选项，我们可以过滤所有我们不关心的类，只选择我们关心的类或包来观察。下面介绍两类参数：</p>
<ol class="n01">
    <li>参数 <strong>-esa</strong> 和 <strong>-dsa</strong>：<br />
    它们含义为开启(关闭)系统类的assertion功能。由于新版本的Java的系统类中，也使了assertion语句，因此如果用户需要观察它们的运行情况，就需要打开系统类的assertion功能 ，我们可使用-esa参数打开，使用 -dsa参数关闭。<br />
    -esa和-dsa的全名为-enablesystemassertions和-disenablesystemassertions，全名和缩写名有同样的功能。<br />
    &nbsp;
    <li>参数 <strong>-ea</strong>和<strong>-ea</strong>：<br />
    它们含义为开启(关闭)用户类的assertion功能：通过这个参数，用户可以打开某些类或包的assertion功能，同样用户也可以关闭某些类和包的assertion功能。打开assertion功能参数为-ea；如果不带任何参数，表示打开所有用户类；如果带有包名称或者类名称，表示打开这些类或包；如果包名称后面跟有三个点，代表这个包及其子包；如果只有三个点，代表无名包。关闭assertion功能参数为-da，使用方法与-ea类似。<br />
    -ea和-da的全名为-enableassertions和-disenableassertions，全名和缩写名有同样的功能。<br />
    下面表格表示了参数及其含义，并有例子说明如何使用。<br />
    　
    <table id="table3" width="60%" border="1">
        <tbody>
            <tr>
                <td>参数</td>
                <td>例子</td>
                <td>说明</td>
            </tr>
            <tr>
                <td>-ea</td>
                <td>java -ea</td>
                <td>打开所有用户类的assertion</td>
            </tr>
            <tr>
                <td>-da</td>
                <td>java -da</td>
                <td>关闭所有用户类的assertion</td>
            </tr>
            <tr>
                <td>-ea:&lt;classname&gt;</td>
                <td>java -ea:MyClass1</td>
                <td>打开MyClass1的assertion</td>
            </tr>
            <tr>
                <td>-da:&lt;classname&gt;</td>
                <td>java -da: MyClass1</td>
                <td>关闭MyClass1的assertion</td>
            </tr>
            <tr>
                <td>-ea:&lt;packagename&gt;</td>
                <td>java -ea:pkg1</td>
                <td>打开pkg1包的assertion</td>
            </tr>
            <tr>
                <td>-da:&lt;packagename&gt;</td>
                <td>java -da:pkg1</td>
                <td>关闭pkg1包的assertion</td>
            </tr>
            <tr>
                <td>-ea:...</td>
                <td>java -ea:...</td>
                <td>打开缺省包(无名包)的assertion</td>
            </tr>
            <tr>
                <td>-da:...</td>
                <td>java -da:...</td>
                <td>关闭缺省包(无名包)的assertion</td>
            </tr>
            <tr>
                <td>-ea:&lt;packagename&gt;...</td>
                <td>java -ea:pkg1...</td>
                <td>打开pkg1包和其子包的assertion</td>
            </tr>
            <tr>
                <td>-da:&lt;packagename&gt;...</td>
                <td>java -da:pkg1...</td>
                <td>关闭pkg1包和其子包的assertion</td>
            </tr>
            <tr>
                <td>-esa</td>
                <td>java -esa</td>
                <td>打开系统类的assertion</td>
            </tr>
            <tr>
                <td>-dsa</td>
                <td>java -dsa</td>
                <td>关闭系统类的assertion</td>
            </tr>
            <tr>
                <td>综合使用</td>
                <td>java -dsa:MyClass1:pkg1</td>
                <td>关闭MyClass1和pkg1包的assertion</td>
            </tr>
        </tbody>
    </table>
    <br />
    其中...代表，此包和其子包的含义。例如我们有两个包为pkg1和pkg1.subpkg。那么pkg1...就代表pkg1和pkg1.subpkg两个包。<br />
    另外，Java为了让程序也能够动态开启和关闭某些类和包的assertion功能，Java修该了Class和ClassLoader的实现，增加了几个用于操作assert的API。下面简单说明一下几个API的作用。<br />
    ClassLoader类中的几个相关的API:<br />
    　　setDefaultAssertionStatus:用于开启/关闭assertion功能<br />
    　　setPackageAssertionStatus:用于开启/关闭某些包的assertion功能<br />
    　　setClassAssertionStatus: 用于开启/关闭某些类的assertion功能<br />
    　　clearAssertionStatus：用于关闭assertion功能<br />
    　 </li>
</ol>
<p><a name="2"><span class="atitle2">二、assertion的设计问题</span></a></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 首先，我们认为assertion是必要的。因为，如果没有统一的assertion机制，Java程序通常使用if-then-else或者switch-case语句进行assertion检查，而且检查的数据类型也不完全相同。assertion机制让Java程序员用统一的方式处理assertion问题，而不是按自己的方式处理。另外，如果用户使用自己的方式进行检查，那么这些代码在发布以后仍然将起作用，这可能会影响程序的性能。而从语言言层次支持assertion功能，这将把assertion对性能带来的负面影响降到最小。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Java是通过增强一个关键字assert实现支持assertion，而不是使用一个库函数支持，这说明Java认为assertion对于语言本身来说是非常重要的。实际上，在Java的早期的规范中，Java是能够支持assert的，但是由于一些实现的限制，这些特性从规范中除去了。因此，assert的再次引入应该是恢复了Java对assert的支持。C语言就是通过Assert.h函数库实现断言的支持。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Java的assertion的开启也和C语言不太一样，我们都知道在C语言中，assertion的开启是在编译时候决定的。当我们使用debug方式编译程序时候，assertion被开启，而使用release方式编译时候，assertion自动被关闭。而Java的assertion却是在运行的时候进行决定的。其实，这两种方式是各有优缺点。如果采用编译时决定方式，开发人员将处理两种类型的目标码，debug版本和release版本，这加大了文档管理的难度，但是提高了代码的运行效率。Java采用运行时决定的方式，这样所有的assertion信息将置于目标代码中，同一目标代码可以选择不同方式运行，增强目标代码的灵活性，但是它将牺牲因为assertion而引起一部分性能损失。Java专家小组认为，所牺牲的性能相当小，因此java采用了运行时决定方式。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 另外，我们注意到AssertionError作为Error的一个子类，而不是RuntimeException。关于这一点，专家组也进行了长期的讨论。Error代表一些异常的错误，通常是不可以恢复的，而RuntimeException强调该错误在运行时才发生的特点。AssertionError通常为非常关键的错误，这些错误往往是不容易恢复的，而且assertion机制也不鼓励程序员对这种错误进行恢复。因此，为了强调assertion的含义，Java专家小组选择了让AssertError为Error的子类。</p>
<p><a name="3"><span class="atitle2">三、assertion与继承</span></a></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在本节，我们将考虑assertion与继承的关系，研究assert是如何定位的。如果开启一个子类的assertion，那么它的父类的assertion是否执行？</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 下面的例子将显示如果一个assert语句在父类，而当它的子类调用它时，该assert为false。我们看看在不同的情况下，该assertion是否被处理。</p>
<pre>class Base
{
public void baseMethod()
{
assert      false : "Assertion failed:This is base ";// 总是assertion失败
System.out.println("Base Method");
}
}
class Derived
extends Base
{
public void derivedMethod()
{
assert false: "Assertion failed:This is derive";// 总是assertion失败
System.out.println( "Derived Method" );
}
public static void main( String[] args )
{
try
{
Derived derived = new Derived();
derived.baseMethod(  );
derived.derivedMethod();
}
catch( AssertionError ae )
{
System.out.println(ae);
}
}
}</pre>
<p>
<table id="table4" width="60%" border="1">
    <tbody>
        <tr>
            <td>运行命令</td>
            <td>含义</td>
            <td>结果</td>
        </tr>
        <tr>
            <td>Java Derived</td>
            <td>不启用assertion</td>
            <td>Base Method<br />
            Derived Method</td>
        </tr>
        <tr>
            <td>Java -ea Derived</td>
            <td>开启所有assertion</td>
            <td>Java.lang.AssertionError:Assertion Failed:This is base</td>
        </tr>
        <tr>
            <td>Java -da Derived</td>
            <td>关闭所有assertion</td>
            <td>Base Method<br />
            Derived Method</td>
        </tr>
        <tr>
            <td>Java -ea:Base Derived</td>
            <td>仅打开Base的assertion</td>
            <td>Java.lang.AssertionError:Assertion Failed:This is base</td>
        </tr>
        <tr>
            <td>Java -ea:Derived Derived </td>
            <td>仅打开Derived的assertion</td>
            <td>Base Method<br />
            Java.lang.AssertionError:Assertion Failed:This is derived</td>
        </tr>
    </tbody>
</table>
</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 从这个例子我们可以看出，父类的assert语句将只有在父类的assert开启才起作用，如果仅仅开启子类的assert，父类的assert仍然不运行。例如，我们执行java -ea:Derived Derived的时候，Base类的assert语句并不执行。因此，我们可以认为，assert语句不具有继承功能。</p>
<p><a name="4"><span class="atitle2">四、assertion的使用</span></a></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; assertion的使用是一个复杂的问题，因为这将涉及到程序的风格，assertion运用的目标，程序的性质等问题。通常来说，assertion用于检查一些关键的值，并且这些值对整个程序，或者局部功能的完成有很大的影响，并且这种错误不容易恢复的。assertion表达式应该短小、易懂，如果需要评估复杂的表达式，应该使用函数计算。以下是一些使用assertion的情况的例子，这些方式可以让java程序的可靠性更高。</p>
<ol class="n01">
    <li>检查控制流； 在if-then-else和swith-case语句中，我们可以在不应该发生的控制支流上加上assert false语句。如果这种情况发生了，assert能够检查出来。<br />
    例如：x取值只能使1,2,3，我们的程序可以如下表示<br />
    　
    <pre>	switch (x)
    { case 1: &#8230;;
    case 2: &#8230;;
    case 3: &#8230;
    default: assert false:"x value is invalid: "+x;
    }
    </pre>
    <li>在私有函数计算前，检查输入参数是否有效；对于一私有些函数，要求输入满足一些特定的条件，那么我们可以在函数开始处使用assert进行参数检查。对于公共函数，我们通常不使用assertion检查，因为一般来说，公共函数必须对无效的参数进行检查和处理。而私有函数往往是直接使用的。<br />
    例如：某函数可能要求输入的参数必须不为null。那么我们可以在函数的一开始加上 assert parameter1!=null : "paramerter is null in test method";
    <li>在函数计算后，检查函数结果是否有效；对于一些计算函数，函数运行完成后，某些值需要保证一定的性质，因此我们可以通过assert检查该值。<br />
    例如，我们有一个计算绝对值的函数，那么我们就可以在函数的结果处，加上一个语句：<br />
    　
    <pre>assert  value&gt;=0:"Value should be bigger than 0:"+value;</pre>
    通过这种方式，我们可以对函数计算完的结果进行检查。
    <li>检查程序不变量；有些程序中，存在一些不变量，在程序的运行生命周期，这些不变量的值都是不变的。这些不变量可能是一个简单表达式，也可能是一个复杂的表达式。对于一些关键的不变量，我们可以通过assert进行检查。<br />
    例如，在一个财会系统中，公司的支出和收入必须保持一定的平衡关系，因此我们可以编写一个表达式检查这种平衡关系，如下表示。<br />
    　
    <pre>          private boolean isBalance() {
    &#8230;&#8230;
    }
    </pre>
    在这个系统中，在一些可能影响这种平衡关系的方法的前后，我们都可以加上assert验证：assert isBalance():"balance is destoried";<br />
    　 </li>
</ol>
<p><a name="5"><span class="atitle2">五、结论</span></a></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; assertion为开发人员提供了一种灵活地调试和测试机制，它的使用也非常简单、方便。但是，如何规范、系统地使用assertion(特别是在Java语言中)仍然是一个亟待研究的问题。<br />
<br />
<!-- AUTHOR BIOS--><!-- Make author heading singular or plural as needed-->
<table id="table5" cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td><a name="author1"><span class="atitle2">关于作者</span></a> <br />
            欧阳辰，北京大学计算机系硕士毕业，98年起开始研究基于java的软件开发、测试，参与开发、测试过多个基于Java的应用程序和Web服务项目。联系方式<a href="mailto:yeekee@sina.com">mailto:yeekee@sina.com</a><br />
            周欣，北京大学计算机系在读博士生，主要研究方向：程序理解、逆向工程及软件度量，联系方式 <a href="mailto:zhouxin@sei.pku.edu.cn">zhouxin@sei.pku.edu.cn</a>。</td>
        </tr>
    </tbody>
</table>
</p>
<img src ="http://www.blogjava.net/bacoo/aggbug/185491.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/bacoo/" target="_blank">bacoo</a> 2008-03-11 22:00 <a href="http://www.blogjava.net/bacoo/archive/2008/03/11/185491.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>线程方法interrupt的说明</title><link>http://www.blogjava.net/bacoo/archive/2008/02/23/181622.html</link><dc:creator>bacoo</dc:creator><author>bacoo</author><pubDate>Sat, 23 Feb 2008 11:13:00 GMT</pubDate><guid>http://www.blogjava.net/bacoo/archive/2008/02/23/181622.html</guid><wfw:comment>http://www.blogjava.net/bacoo/comments/181622.html</wfw:comment><comments>http://www.blogjava.net/bacoo/archive/2008/02/23/181622.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/bacoo/comments/commentRss/181622.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/bacoo/services/trackbacks/181622.html</trackback:ping><description><![CDATA[<p>线程的interrupt方法很特殊，有必要在这里着重说明一下。<br />
interrupted方法是查询是否有&#8220;中断状态&#8221;这一标志，而这一标志很重要很重要。<br />
通常情况下这个标志都是没有被设置的，一旦这个标志被设置了，则所有当前正在阻塞的方法（限定在由于wait、sleep、join三种方法引发的阻塞）都会立刻完成&#8220;跳出阻塞状态、抛出InterruptedException异常、清除中断状态标志&#8221;这三件工作。仿佛线程在阻塞时，总在不断的查询这一标志，一旦发现这个标志被设置了，那么就立刻发生上述提到的三件工作。不过这只是一种猜测，至于底层到底是如何实现的，我们并不知道。</p>
<p>而我们调用interrupt方法也很有趣，通常这个标志都是未被设置的，一旦调用这个方法，它就会设置这个标志，说白了，这个方法所完成的工作也就仅仅限于设置了一个这样的标志。接下来就能和上一段落中提到的事情相关联了，如果线程当前是阻塞的状态，那么它会利用这个标志啦，然后做&#8220;三件事情&#8221;，然后这个标志又被清除了；如果线程当前是非阻塞状态，那么该方法的调用也就仅仅是设置一个标志而已，注意设置了这个标记就和没设置这个标记完全不同了，一旦你再想调用sleep等阻塞方法时，它们都会&#8220;立刻跳出阻塞状态、抛出异常、清除标记&#8221;啦，呵呵。</p>
<p>至此，终于清除了interrupt方法的作用了吧？</p>
<img src ="http://www.blogjava.net/bacoo/aggbug/181622.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/bacoo/" target="_blank">bacoo</a> 2008-02-23 19:13 <a href="http://www.blogjava.net/bacoo/archive/2008/02/23/181622.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于serialVersionUID</title><link>http://www.blogjava.net/bacoo/archive/2008/01/07/173450.html</link><dc:creator>bacoo</dc:creator><author>bacoo</author><pubDate>Mon, 07 Jan 2008 13:12:00 GMT</pubDate><guid>http://www.blogjava.net/bacoo/archive/2008/01/07/173450.html</guid><wfw:comment>http://www.blogjava.net/bacoo/comments/173450.html</wfw:comment><comments>http://www.blogjava.net/bacoo/archive/2008/01/07/173450.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/bacoo/comments/commentRss/173450.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/bacoo/services/trackbacks/173450.html</trackback:ping><description><![CDATA[<p>serialVersionUID的解释 ：<br />
前两天升级了Eclipse到3.1版本，在老版本的IDE环境中写的程序在Problems中会出来好多类似的警告。当采用程序的自动修复时，采用默认方</p>
<p>式，Eclipse会加上：private static final long serialVersionUID = 1L; <br />
　　其实这个问题倒也不影响程序的运行，但是我看到Problems里面有警告就不舒服，同时也说明我们写的代码还是不规范。不怕，我们有互</p>
<p>联网查查是怎么回事，具体的原因还就是和序列化中的这个serialVersionUID有关。<br />
　　<br />
　　serialVersionUID 用来表明类的不同版本间的兼容性。如果你修改了此类, 要修改此值。否则以前用老版本的类序列化的类恢复时会出错</p>
<p>。<br />
　　<br />
　　在JDK中，可以利用JDK的bin目录下的serialver.exe工具产生这个serialVersionUID，对于Test.class，执行命令：serialver Test。</p>
<p>　　为了在反序列化时，确保类版本的兼容性，最好在每个要序列化的类中加入private static final long serialVersionUID这个属性，具</p>
<p>体数值自己定义。这样，即使某个类在与之对应的对象已经序列化出去后做了修改，该对象依然可以被正确反序列化。否则，如果不显式定义</p>
<p>该属性，这个属性值将由JVM根据类的相关信息计算，而修改后的类的计算结果与修改前的类的计算结果往往不同，从而造成对象的反序列化因</p>
<p>为类版本不兼容而失败。</p>
<p>　　不显式定义这个属性值的另一个坏处是，不利于程序在不同的JVM之间的移植。因为不同的编译器实现该属性值的计算策略可能不同，从而</p>
<p>造成虽然类没有改变，但是因为JVM不同，出现因类版本不兼容而无法正确反序列化的现象出现。</p>
<p>　　<br />
serialVersionUID作用： <br />
序列化时为了保持版本的兼容性，即在版本升级时反序列化仍保持对象的唯一性。 </p>
<p>你可以随便写一个，在Eclipse中它替你生成一个，有两种生成方式：<br />
一个是默认的1L，比如：private static final long serialVersionUID = 1L;<br />
一个是根据类名、接口名、成员方法及属性等来生成一个64位的哈希字段，比如：private static final long serialVersionUID = -</p>
<p>8940196742313994740L;之类的。</p>
<p>当你一个类实现了Serializable接口，如果没有定义serialVersionUID，Eclipse会提供这个提示功能告诉你去定义之。 <br />
在Eclipse中点击类中warning的图标一下，Eclipse就会自动给定两种生成的方式，如上面所述。如果不想定义它，在Eclipse的设置中也可以</p>
<p>把它关掉的，设置如下： <br />
Window ==&gt; Preferences ==&gt; Java ==&gt; Compiler ==&gt; Error/Warnings ==&gt; Potential programming problems <br />
将Serializable class without serialVersionUID的warning改成ignore即可。 </p>
<p>如果你没有考虑到兼容性问题时，就把它关掉，不过有这个功能是好的，这个serialVersionUID为了让该类别Serializable向后兼容。 </p>
<p>如果你的类Serialized存到硬盘上面后，可是后来你却更改了类别的field(增加或减少或改名)，当你Deserialize时，就会出现Exception的，</p>
<p>这样就会造成不兼容性的问题。 </p>
<p>但当serialVersionUID相同时，它就会将不一样的field以type的预设值Deserialize，这个可以避开不兼容性的问题。<br />
</p>
<img src ="http://www.blogjava.net/bacoo/aggbug/173450.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/bacoo/" target="_blank">bacoo</a> 2008-01-07 21:12 <a href="http://www.blogjava.net/bacoo/archive/2008/01/07/173450.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java类中的限定词</title><link>http://www.blogjava.net/bacoo/archive/2008/01/07/173341.html</link><dc:creator>bacoo</dc:creator><author>bacoo</author><pubDate>Mon, 07 Jan 2008 06:37:00 GMT</pubDate><guid>http://www.blogjava.net/bacoo/archive/2008/01/07/173341.html</guid><wfw:comment>http://www.blogjava.net/bacoo/comments/173341.html</wfw:comment><comments>http://www.blogjava.net/bacoo/archive/2008/01/07/173341.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/bacoo/comments/commentRss/173341.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/bacoo/services/trackbacks/173341.html</trackback:ping><description><![CDATA[<p>java语言中有四种不同的限定词，提供了四种不同的访问权限。</p>
<p>　　1） private <br />
　　类中限定为private的成员，只能被这个类本身访问。<br />
　　如果一个类的构造方法声明为private,则其它类不能生成该类的一个实例。</p>
<p>　　2） default<br />
　　类中不加任何访问权限限定的成员属于缺省的（default）访问状态，可以被这个类本身和同一个包中的类所访问。</p>
<p>　　3） protected<br />
　　类中限定为protected的成员，可以被这个类本身、它的子类（包括同一个包中以及不同包中的子类）和同一个包中的所有其他的类访问。</p>
<p>　　4） public<br />
　　类中限定为public的成员，可以被所有的类访问。</p>
<p>　　表3-1列出了这些限定词的作用范围。</p>
<p>【表3-1】　java中类的限定词的作用范围比较<br />
&nbsp; =============================================================<br />
||&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 同一个类&nbsp; 同一个包的类 不同包的子类&nbsp; 不同包非子类&nbsp;&nbsp;&nbsp;&nbsp;||<br />
|| private&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;&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;&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; ||<br />
|| default&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;&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;&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; ||<br />
|| protected&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;&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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;||<br />
|| public&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;&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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;||<br />
&nbsp; =============================================================<br />
说明：上面这个表，看起来很简单，而且也很容易记忆，但是却蕴含着极为丰富的信息，可以从不同的角度来理解上面的这个表。<br />
比如在同一个类里面时，四个关键词都相当于是public，可以不在乎限定词是什么；在同一个包里面时，除了private限定词外，所有的限定词的作用都完全等同于public。我们经常会思考这样一个问题：一个类的属性和方法是否对外可见？这个问题描述中提到的&#8220;可见&#8221;二字，当环境为&#8220;非子类&#8221;时，说白了就是我们能否通过实例化这个类后，用一个对象把这个类的这些字段或者方法给&#8220;点&#8221;出来，即&#8220;某对象.某属性（或某方法）&#8221;。因为通常我们都是在不同包的环境下操作的，比如我们会import很多系统的包中的类，诸如&#8220;import java.awt.*;&#8221;这样的语句，因此我们使用这些包中的类时，它们对我们的可见也就仅仅局限在使用&#8220;public&#8221;限定词修饰的属性或方法上了，因此大家往往会误以为只有public的东西才能点出来，实则不然，当我们在同一个包中的非子类中也可以把除了private修饰的东西之外的所有属性和方法给&#8220;点&#8221;出来。其实对于&#8220;点&#8221;这个运算，可以分两个角度去理解，既然能用到&#8220;点&#8221;操作，那就代表了我们使用的环境应该是&#8220;非子类&#8221;，非子类又可以分为&#8220;包内&#8221;和&#8220;非包内&#8221;，对于&#8220;包内&#8221;，只要不是private修饰的东西都能点出来；对于&#8220;非包内&#8221;则只能是public的东西才能点出来；；；如果是在&#8220;子类&#8221;中操作时，大家可以思考一下，我们还用&#8220;点&#8221;操作吗？显然不用了，因为在子类中，父类中定义的东西只要可见的话都可以被你拿过来用，因此根本就用不到点操作，当然这里也要分&#8220;包内&#8221;和&#8220;非包内&#8221;。对于default限定词，我们不能显示的使用它来定义属性或方法，只要我们在定义属性或方法的前面什么限定词都不加，就默认的使用了default限定词。</p>
<img src ="http://www.blogjava.net/bacoo/aggbug/173341.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/bacoo/" target="_blank">bacoo</a> 2008-01-07 14:37 <a href="http://www.blogjava.net/bacoo/archive/2008/01/07/173341.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转载]Java垃圾收集算法</title><link>http://www.blogjava.net/bacoo/archive/2008/01/02/172047.html</link><dc:creator>bacoo</dc:creator><author>bacoo</author><pubDate>Tue, 01 Jan 2008 17:56:00 GMT</pubDate><guid>http://www.blogjava.net/bacoo/archive/2008/01/02/172047.html</guid><wfw:comment>http://www.blogjava.net/bacoo/comments/172047.html</wfw:comment><comments>http://www.blogjava.net/bacoo/archive/2008/01/02/172047.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/bacoo/comments/commentRss/172047.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/bacoo/services/trackbacks/172047.html</trackback:ping><description><![CDATA[1．垃圾收集算法的核心思想<br />
<br />
Java语言建立了垃圾收集机制，用以跟踪正在使用的对象和发现并回收不再使用（引用）的对象。该机制可以有效防范动态内存分配中可能发生的两个危险：因内存垃圾过多而引发的内存耗尽，以及不恰当的内存释放所造成的内存非法引用。<br />
<br />
垃圾收集算法的核心思想是：对虚拟机可用内存空间，即堆空间中的对象进行识别，如果对象正在被引用，那么称其为存活对象，反之，如果对象不再被引用，则为垃圾对象，可以回收其占据的空间，用于再分配。垃圾收集算法的选择和垃圾收集系统参数的合理调节直接影响着系统性能，因此需要开发人员做比较深入的了解。<br />
<br />
<br />
<br />
2．触发主GC（Garbage Collector）的条件<br />
<br />
JVM进行次GC的频率很高,但因为这种GC占用时间极短,所以对系统产生的影响不大。更值得关注的是主GC的触发条件,因为它对系统影响很明显。总的来说,有两个条件会触发主GC:<br />
<br />
①当应用程序空闲时,即没有应用线程在运行时,GC会被调用。因为GC在优先级最低的线程中进行,所以当应用忙时,GC线程就不会被调用,但以下条件除外。<br />
<br />
②Java堆内存不足时,GC会被调用。当应用线程在运行,并在运行过程中创建新对象,若这时内存空间不足,JVM就会强制地调用GC线程,以便回收内存用于新的分配。若GC一次之后仍不能满足内存分配的要求,JVM会再进行两次GC作进一步的尝试,若仍无法满足要求,则 JVM将报&#8220;out of memory&#8221;的错误,Java应用将停止。<br />
<br />
由于是否进行主GC由JVM根据系统环境决定,而系统环境在不断的变化当中,所以主GC的运行具有不确定性,无法预计它何时必然出现,但可以确定的是对一个长期运行的应用来说,其主GC是反复进行的。<br />
<br />
<br />
<br />
3．减少GC开销的措施<br />
<br />
根据上述GC的机制,程序的运行会直接影响系统环境的变化,从而影响GC的触发。若不针对GC的特点进行设计和编码,就会出现内存驻留等一系列负面影响。为了避免这些影响,基本的原则就是尽可能地减少垃圾和减少GC过程中的开销。具体措施包括以下几个方面:<br />
<br />
(1)不要显式调用System.gc()<br />
<br />
此函数建议JVM进行主GC,虽然只是建议而非一定,但很多情况下它会触发主GC,从而增加主GC的频率,也即增加了间歇性停顿的次数。<br />
<br />
<br />
<br />
(2)尽量减少临时对象的使用<br />
<br />
临时对象在跳出函数调用后,会成为垃圾,少用临时变量就相当于减少了垃圾的产生,从而延长了出现上述第二个触发条件出现的时间,减少了主GC的机会。<br />
<br />
<br />
<br />
(3)对象不用时最好显式置为Null<br />
<br />
一般而言,为Null的对象都会被作为垃圾处理,所以将不用的对象显式地设为Null,有利于GC收集器判定垃圾,从而提高了GC的效率。<br />
<br />
<br />
<br />
(4)尽量使用StringBuffer,而不用String来累加字符串（详见blog另一篇文章JAVA中String与StringBuffer）<br />
<br />
由于String是固定长的字符串对象,累加String对象时,并非在一个String对象中扩增,而是重新创建新的String对象,如Str5=Str1+Str2+Str3+Str4,这条语句执行过程中会产生多个垃圾对象,因为对次作&#8220;+&#8221;操作时都必须创建新的String对象,但这些过渡对象对系统来说是没有实际意义的,只会增加更多的垃圾。避免这种情况可以改用StringBuffer来累加字符串,因StringBuffer是可变长的,它在原有基础上进行扩增,不会产生中间对象。<br />
<br />
<br />
<br />
(5)能用基本类型如Int,Long,就不用Integer,Long对象<br />
<br />
基本类型变量占用的内存资源比相应对象占用的少得多,如果没有必要,最好使用基本变量。<br />
<br />
<br />
<br />
(6)尽量少用静态对象变量<br />
<br />
静态变量属于全局变量,不会被GC回收,它们会一直占用内存。<br />
<br />
<br />
<br />
(7)分散对象创建或删除的时间<br />
<br />
集中在短时间内大量创建新对象,特别是大对象,会导致突然需要大量内存,JVM在面临这种情况时,只能进行主GC,以回收内存或整合内存碎片,从而增加主GC的频率。集中删除对象,道理也是一样的。它使得突然出现了大量的垃圾对象,空闲空间必然减少,从而大大增加了下一次创建新对象时强制主GC的机会。<br />
<br />
<br />
<br />
4．gc与finalize方法<br />
<br />
⑴gc方法请求垃圾回收<br />
<br />
使用System.gc()可以不管JVM使用的是哪一种垃圾回收的算法，都可以请求Java的垃圾回收。需要注意的是，调用System.gc()也仅仅是一个请求。JVM接受这个消息后，并不是立即做垃圾回收，而只是对几个垃圾回收算法做了加权，使垃圾回收操作容易发生，或提早发生，或回收较多而已。<br />
<br />
<br />
<br />
⑵finalize方法透视垃圾收集器的运行<br />
<br />
在JVM垃圾收集器收集一个对象之前 ，一般要求程序调用适当的方法释放资源，但在没有明确释放资源的情况下，Java提供了缺省机制来终止化该对象释放资源，这个方法就是finalize（）。它的原型为：<br />
<br />
protected void finalize() throws Throwable<br />
<br />
在finalize()方法返回之后，对象消失，垃圾收集开始执行。原型中的throws Throwable表示它可以抛出任何类型的异常。<br />
<br />
因此，当对象即将被销毁时，有时需要做一些善后工作。可以把这些操作写在finalize()方法里。<br />
<br />
protected void finalize()<br />
<br />
{<br />
<br />
// finalization code here<br />
<br />
}<br />
<br />
<br />
<br />
⑶代码示例<br />
<br />
<br />
<br />
class Garbage<br />
<br />
{<br />
<br />
int index;<br />
<br />
static int count;<br />
<br />
Garbage()<br />
<br />
{<br />
<br />
count++;<br />
<br />
System.out.println("object "+count+" construct");<br />
<br />
setID(count);<br />
<br />
}<br />
<br />
<br />
<br />
void setID(int id)<br />
<br />
{<br />
<br />
index=id;<br />
<br />
}<br />
<br />
<br />
<br />
protected void finalize() //重写finalize方法<br />
<br />
{<br />
<br />
System.out.println("object "+index+" is reclaimed");<br />
<br />
}<br />
<br />
<br />
<br />
public static void main(String[] args)<br />
<br />
{<br />
<br />
new Garbage();<br />
<br />
new Garbage();<br />
<br />
new Garbage();<br />
<br />
new Garbage();<br />
<br />
System.gc(); //请求运行垃圾收集器<br />
<br />
}<br />
<br />
}<br />
<br />
<br />
<br />
5．Java 内存泄漏<br />
<br />
由于采用了垃圾回收机制，任何不可达对象（对象不再被引用）都可以由垃圾收集线程回收。因此通常说的Java 内存泄漏其实是指无意识的、非故意的对象引用，或者无意识的对象保持。无意识的对象引用是指代码的开发人员本来已经对对象使用完毕，却因为编码的错误而意外地保存了对该对象的引用（这个引用的存在并不是编码人员的主观意愿），从而使得该对象一直无法被垃圾回收器回收掉，这种本来以为可以释放掉的却最终未能被释放的空间可以认为是被&#8220;泄漏了&#8221;。<br />
<br />
考虑下面的程序,在ObjStack类中,使用push和pop方法来管理堆栈中的对象。两个方法中的索引(index)用于指示堆栈中下一个可用位置。push方法存储对新对象的引用并增加索引值,而pop方法减小索引值并返回堆栈最上面的元素。在main方法中,创建了容量为64的栈,并64次调用push方法向它添加对象,此时index的值为64,随后又32次调用pop方法,则index的值变为32,出栈意味着在堆栈中的空间应该被收集。但事实上,pop方法只是减小了索引值,堆栈仍然保持着对那些对象的引用。故32个无用对象不会被GC回收,造成了内存渗漏。<br />
<br />
<br />
public class ObjStack {<br />
<br />
private Object[] stack;<br />
<br />
private int index;<br />
<br />
ObjStack(int indexcount) {<br />
stack = new Object[indexcount];<br />
index = 0;<br />
}<br />
<br />
public void push(Object obj) {<br />
stack[index] = obj;<br />
index++;<br />
}<br />
<br />
public Object pop() {<br />
index--;<br />
return stack[index];<br />
}<br />
}<br />
<br />
<br />
public class Pushpop {<br />
<br />
public static void main(String[] args) {<br />
int i = 0;<br />
Object tempobj;<br />
ObjStack stack1 = new ObjStack(64);//new一个ObjStack对象，并调用有参构造函数。分配stack Obj数组的空间大小为64，可以存64个对象，从0开始存储。<br />
while (i &lt; 64)<br />
{<br />
tempobj = new Object();//循环new Obj对象，把每次循环的对象一一存放在stack Obj数组中。<br />
stack1.push(tempobj);<br />
i++;<br />
System.out.println("第" + i + "次进栈" + "t");<br />
}<br />
while (i &gt; 32)<br />
{<br />
tempobj = stack1.pop();//这里造成了空间的浪费。<br />
//正确的pop方法可改成如下所指示,当引用被返回后,堆栈删除对他们的引用,因此垃圾收集器在以后可以回收他们。<br />
/*<br />
* public Object pop() {index - -;Object temp = stack [index];stack [index]=null;return temp;}<br />
*/<br />
i--;<br />
System.out.println("第" + (64 - i) + "次出栈" + "t");<br />
}<br />
}<br />
<br />
}<br />
<br />
<br />
如何消除内存泄漏<br />
<br />
　　虽然Java虚拟机(JVM)及其垃圾收集器(garbage collector，GC)负责管理大多数的内存任务，Java软件程序中还是有可能出现内存泄漏。实际上，这在大型项目中是一个常见的问题。避免内存泄漏的第一步是要弄清楚它是如何发生的。本文介绍了编写Java代码的一些常见的内存泄漏陷阱，以及编写不泄漏代码的一些最佳实践。一旦发生了内存泄漏，要指出造成泄漏的代码是非常困难的。因此本文还介绍了一种新工具，用来诊断泄漏并指出根本原因。该工具的开销非常小，因此可以使用它来寻找处于生产中的系统的内存泄漏。<br />
<br />
垃圾收集器的作用<br />
<br />
　　虽然垃圾收集器处理了大多数内存管理问题，从而使编程人员的生活变得更轻松了，但是编程人员还是可能犯错而导致出现内存问题。简单地说，GC循环地跟踪所有来自&#8220;根&#8221;对象（堆栈对象、静态对象、JNI句柄指向的对象，诸如此类）的引用，并将所有它所能到达的对象标记为活动的。程序只可以操纵这些对象；其他的对象都被删除了。因为GC使程序不可能到达已被删除的对象，这么做就是安全的。<br />
<br />
　　虽然内存管理可以说是自动化的，但是这并不能使编程人员免受思考内存管理问题之苦。例如，分配（以及释放）内存总会有开销，虽然这种开销对编程人员来说是不可见的。创建了太多对象的程序将会比完成同样的功能而创建的对象却比较少的程序更慢一些（在其他条件相同的情况下）。<br />
<br />
　　而且，与本文更为密切相关的是，如果忘记&#8220;释放&#8221;先前分配的内存，就可能造成内存泄漏。如果程序保留对永远不再使用的对象的引用，这些对象将会占用并耗尽内存，这是因为自动化的垃圾收集器无法证明这些对象将不再使用。正如我们先前所说的，如果存在一个对对象的引用，对象就被定义为活动的，因此不能删除。为了确保能回收对象占用的内存，编程人员必须确保该对象不能到达。这通常是通过将对象字段设置为null或者从集合(collection)中移除对象而完成的。但是，注意，当局部变量不再使用时，没有必要将其显式地设置为null。对这些变量的引用将随着方法的退出而自动清除。<br />
<br />
　　概括地说，这就是内存托管语言中的内存泄漏产生的主要原因：保留下来却永远不再使用的对象引用。<br />
<br />
典型泄漏<br />
<br />
　　既然我们知道了在Java中确实有可能发生内存泄漏，就让我们来看一些典型的内存泄漏及其原因。<br />
<br />
全局集合<br />
<br />
　　在大的应用程序中有某种全局的数据储存库是很常见的，例如一个JNDI树或一个会话表。在这些情况下，必须注意管理储存库的大小。必须有某种机制从储存库中移除不再需要的数据。<br />
<br />
　　这可能有多种方法，但是最常见的一种是周期性运行的某种清除任务。该任务将验证储存库中的数据，并移除任何不再需要的数据。<br />
<br />
　　另一种管理储存库的方法是使用反向链接(referrer)计数。然后集合负责统计集合中每个入口的反向链接的数目。这要求反向链接告诉集合何时会退出入口。当反向链接数目为零时，该元素就可以从集合中移除了。<br />
<br />
缓存<br />
<br />
　　缓存是一种数据结构，用于快速查找已经执行的操作的结果。因此，如果一个操作执行起来很慢，对于常用的输入数据，就可以将操作的结果缓存，并在下次调用该操作时使用缓存的数据。<br />
<br />
　　缓存通常都是以动态方式实现的，其中新的结果是在执行时添加到缓存中的。典型的算法是：<br />
<br />
检查结果是否在缓存中，如果在，就返回结果。<br />
如果结果不在缓存中，就进行计算。<br />
将计算出来的结果添加到缓存中，以便以后对该操作的调用可以使用。<br />
　　该算法的问题（或者说是潜在的内存泄漏）出在最后一步。如果调用该操作时有相当多的不同输入，就将有相当多的结果存储在缓存中。很明显这不是正确的方法。<br />
<br />
　　为了预防这种具有潜在破坏性的设计，程序必须确保对于缓存所使用的内存容量有一个上限。因此，更好的算法是：<br />
<br />
检查结果是否在缓存中，如果在，就返回结果。<br />
如果结果不在缓存中，就进行计算。<br />
如果缓存所占的空间过大，就移除缓存最久的结果。<br />
将计算出来的结果添加到缓存中，以便以后对该操作的调用可以使用。<br />
　　通过始终移除缓存最久的结果，我们实际上进行了这样的假设：在将来，比起缓存最久的数据，最近输入的数据更有可能用到。这通常是一个不错的假设。<br />
<br />
　　新算法将确保缓存的容量处于预定义的内存范围之内。确切的范围可能很难计算，因为缓存中的对象在不断变化，而且它们的引用包罗万象。为缓存设置正确的大小是一项非常复杂的任务，需要将所使用的内存容量与检索数据的速度加以平衡。<br />
<br />
　　解决这个问题的另一种方法是使用java.lang.ref.SoftReference类跟踪缓存中的对象。这种方法保证这些引用能够被移除，如果虚拟机的内存用尽而需要更多堆的话。<br />
<br />
ClassLoader<br />
<br />
　　Java ClassLoader结构的使用为内存泄漏提供了许多可乘之机。正是该结构本身的复杂性使ClassLoader在内存泄漏方面存在如此多的问题。ClassLoader的特别之处在于它不仅涉及&#8220;常规&#8221;的对象引用，还涉及元对象引用，比如：字段、方法和类。这意味着只要有对字段、方法、类或ClassLoader的对象的引用，ClassLoader就会驻留在JVM中。因为ClassLoader本身可以关联许多类及其静态字段，所以就有许多内存被泄漏了。<br />
<br />
确定泄漏的位置<br />
<br />
　　通常发生内存泄漏的第一个迹象是：在应用程序中出现了OutOfMemoryError。这通常发生在您最不愿意它发生的生产环境中，此时几乎不能进行调试。有可能是因为测试环境运行应用程序的方式与生产系统不完全相同，因而导致泄漏只出现在生产中。在这种情况下，需要使用一些开销较低的工具来监控和查找内存泄漏。还需要能够无需重启系统或修改代码就可以将这些工具连接到正在运行的系统上。可能最重要的是，当进行分析时，需要能够断开工具而保持系统不受干扰。<br />
<br />
　　虽然OutOfMemoryError通常都是内存泄漏的信号，但是也有可能应用程序确实正在使用这么多的内存；对于后者，或者必须增加JVM可用的堆的数量，或者对应用程序进行某种更改，使它使用较少的内存。但是，在许多情况下，OutOfMemoryError都是内存泄漏的信号。一种查明方法是不间断地监控GC的活动，确定内存使用量是否随着时间增加。如果确实如此，就可能发生了内存泄漏。 
<img src ="http://www.blogjava.net/bacoo/aggbug/172047.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/bacoo/" target="_blank">bacoo</a> 2008-01-02 01:56 <a href="http://www.blogjava.net/bacoo/archive/2008/01/02/172047.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转载]详析内部类</title><link>http://www.blogjava.net/bacoo/archive/2008/01/02/172046.html</link><dc:creator>bacoo</dc:creator><author>bacoo</author><pubDate>Tue, 01 Jan 2008 17:53:00 GMT</pubDate><guid>http://www.blogjava.net/bacoo/archive/2008/01/02/172046.html</guid><wfw:comment>http://www.blogjava.net/bacoo/comments/172046.html</wfw:comment><comments>http://www.blogjava.net/bacoo/archive/2008/01/02/172046.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/bacoo/comments/commentRss/172046.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/bacoo/services/trackbacks/172046.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 本文主要参照网上的一些相关文章、以及thinking in java 第三版，对java里面的内部类进行了一个较为详细的总结内部类是指在一个外部类的内部再定义一个类。内部类作为外部类的一个成员，并且依附于外部类而存在的。内部类可为静态，可用protected和private修饰（而外部类只能使用public和缺省的包访问权限）。内部类主要有以下几类：成员内部类、局部内部类、静态内部类、匿名...&nbsp;&nbsp;<a href='http://www.blogjava.net/bacoo/archive/2008/01/02/172046.html'>阅读全文</a><img src ="http://www.blogjava.net/bacoo/aggbug/172046.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/bacoo/" target="_blank">bacoo</a> 2008-01-02 01:53 <a href="http://www.blogjava.net/bacoo/archive/2008/01/02/172046.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[改编]final关键字</title><link>http://www.blogjava.net/bacoo/archive/2008/01/01/171986.html</link><dc:creator>bacoo</dc:creator><author>bacoo</author><pubDate>Tue, 01 Jan 2008 06:16:00 GMT</pubDate><guid>http://www.blogjava.net/bacoo/archive/2008/01/01/171986.html</guid><wfw:comment>http://www.blogjava.net/bacoo/comments/171986.html</wfw:comment><comments>http://www.blogjava.net/bacoo/archive/2008/01/01/171986.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/bacoo/comments/commentRss/171986.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/bacoo/services/trackbacks/171986.html</trackback:ping><description><![CDATA[<p>1. final变量不能被改变;&nbsp; <br />
当利用final修饰一个属性（变量）的时候，此时的属性成为常量。 <br />
注意JAVA命名规范中常量全部字母大写： <br />
final int AGE=10； <br />
常量的地址不可改变，但在地址中保存的值（即对象的属性）是可以改变的。 </p>
<p>final变量是在整个类被创建时候被赋值，之后就不能改变了。 <br />
对于final变量，如果在声明的时候和构造的时候均不进行赋值，编译出错。 </p>
<p>对于利用构造方法对final变量进行赋值的时候，此时在构造之前系统设置的默认值被覆盖。 </p>
<p>常量（这里的常量指的是实例常量：即成员变量）赋值： <br />
①在初始化的时候通过显式声明赋值。final int x=3； <br />
②在构造的时候赋值。 <br />
class A{ <br />
&nbsp;final int x; <br />
&nbsp;public A(){ <br />
&nbsp;x=4; <br />
&nbsp;} <br />
} </p>
<p>2. final方法不能被改写;&nbsp; <br />
利用final定义方法：这样的方法为一个不可覆盖的方法。 <br />
下面这样就会编译出错：<br />
class A{<br />
&nbsp;public static void max(){<br />
&nbsp;&nbsp;System.out.println("A:max()");<br />
&nbsp;}<br />
}<br />
class B extends A{<br />
&nbsp;public void max(){<br />
&nbsp;}<br />
} <br />
为了保证方法的一致性（即不被改变），可将方法用final定义。 <br />
如果在父类中有final定义的方法，那么在子类中保证调用的是同一个父类方法。 <br />
如果一个方法前有修饰词private或static，则系统会自动在前面加上final。即private和static方法默认均为final方法。 </p>
<p>注：类的修饰符仅限于abstract、final、public。Final和abstract永远不会同时出现。 </p>
<p>3. final类不能被继承;&nbsp; <br />
final修饰类的时候，此类不可被继承，即final类没有子类。这样可以用final保证用户调用时动作的一致性，可以防止子类覆盖情况的发生。 <br />
String 类就是final类 ，目的是提供效率保证安全。</p>
<img src ="http://www.blogjava.net/bacoo/aggbug/171986.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/bacoo/" target="_blank">bacoo</a> 2008-01-01 14:16 <a href="http://www.blogjava.net/bacoo/archive/2008/01/01/171986.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转载]JAVA打印</title><link>http://www.blogjava.net/bacoo/archive/2007/12/31/171792.html</link><dc:creator>bacoo</dc:creator><author>bacoo</author><pubDate>Sun, 30 Dec 2007 17:32:00 GMT</pubDate><guid>http://www.blogjava.net/bacoo/archive/2007/12/31/171792.html</guid><wfw:comment>http://www.blogjava.net/bacoo/comments/171792.html</wfw:comment><comments>http://www.blogjava.net/bacoo/archive/2007/12/31/171792.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/bacoo/comments/commentRss/171792.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/bacoo/services/trackbacks/171792.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 第九章 JAVA的打印机制Java 自从问世以来在各方面发展迅速，但是一直以来，打印输出是java最弱的方面。事实上，java1.0不支持任何打印功能。Java1.1在 java.awt包里包含了一个叫做PrintJob的类，但是这个类提供的打印功能十分粗糙和不可靠。当java1.2问世，它围绕 PrinterJob设计了一个完整独立的打印机制（叫做java2D printing API），并...&nbsp;&nbsp;<a href='http://www.blogjava.net/bacoo/archive/2007/12/31/171792.html'>阅读全文</a><img src ="http://www.blogjava.net/bacoo/aggbug/171792.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/bacoo/" target="_blank">bacoo</a> 2007-12-31 01:32 <a href="http://www.blogjava.net/bacoo/archive/2007/12/31/171792.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转载]使用Regex实现的为JFileChooser使用的FileFilter对象的创建类</title><link>http://www.blogjava.net/bacoo/archive/2007/12/29/171617.html</link><dc:creator>bacoo</dc:creator><author>bacoo</author><pubDate>Sat, 29 Dec 2007 12:39:00 GMT</pubDate><guid>http://www.blogjava.net/bacoo/archive/2007/12/29/171617.html</guid><wfw:comment>http://www.blogjava.net/bacoo/comments/171617.html</wfw:comment><comments>http://www.blogjava.net/bacoo/archive/2007/12/29/171617.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/bacoo/comments/commentRss/171617.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/bacoo/services/trackbacks/171617.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 在使用swing的程序中经常用到JFileChooser，并且经常需要自定义一个FileFilter的子类来在文件列表中屏蔽不需要的文件。&nbsp;大多数情况下，该子类是这样设计的：public ImgFileFilterextends FileFilter{&nbsp;&nbsp;&nbsp; public boolean accept(File f) {&nbsp;&...&nbsp;&nbsp;<a href='http://www.blogjava.net/bacoo/archive/2007/12/29/171617.html'>阅读全文</a><img src ="http://www.blogjava.net/bacoo/aggbug/171617.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/bacoo/" target="_blank">bacoo</a> 2007-12-29 20:39 <a href="http://www.blogjava.net/bacoo/archive/2007/12/29/171617.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[改编]线程的使用！</title><link>http://www.blogjava.net/bacoo/archive/2007/12/28/171348.html</link><dc:creator>bacoo</dc:creator><author>bacoo</author><pubDate>Fri, 28 Dec 2007 15:07:00 GMT</pubDate><guid>http://www.blogjava.net/bacoo/archive/2007/12/28/171348.html</guid><wfw:comment>http://www.blogjava.net/bacoo/comments/171348.html</wfw:comment><comments>http://www.blogjava.net/bacoo/archive/2007/12/28/171348.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/bacoo/comments/commentRss/171348.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/bacoo/services/trackbacks/171348.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;一：理解多线程多线程是这样一种机制，它允许在程序中并发执行多个指令流，每个指令流都称为一个线程，彼此间互相独立。 线程又称为轻量级进程，它和进程一样拥有独立的执行控制，由操作系统负责调度，区别在于线程没有独立的存储空间，而是和所属进程中的其它线程共享一个存储空间，这使得线程间的通信远较进程简单。多个线程的执行是并发的，也就是在逻辑上&#8220;同时...&nbsp;&nbsp;<a href='http://www.blogjava.net/bacoo/archive/2007/12/28/171348.html'>阅读全文</a><img src ="http://www.blogjava.net/bacoo/aggbug/171348.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/bacoo/" target="_blank">bacoo</a> 2007-12-28 23:07 <a href="http://www.blogjava.net/bacoo/archive/2007/12/28/171348.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>有关byte转char、String的一些说明</title><link>http://www.blogjava.net/bacoo/archive/2007/12/28/171345.html</link><dc:creator>bacoo</dc:creator><author>bacoo</author><pubDate>Fri, 28 Dec 2007 14:58:00 GMT</pubDate><guid>http://www.blogjava.net/bacoo/archive/2007/12/28/171345.html</guid><wfw:comment>http://www.blogjava.net/bacoo/comments/171345.html</wfw:comment><comments>http://www.blogjava.net/bacoo/archive/2007/12/28/171345.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/bacoo/comments/commentRss/171345.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/bacoo/services/trackbacks/171345.html</trackback:ping><description><![CDATA[<p>package com.bacoo.www;</p>
<p>import java.applet.*;<br />
import java.net.*;</p>
<p>public class InetAddDemo extends Applet{<br />
&nbsp;public void test(){<br />
&nbsp;&nbsp;try{<br />
&nbsp;&nbsp;&nbsp;InetAddress add=InetAddress.getLocalHost();<br />
&nbsp;&nbsp;&nbsp;System.out.println(add.getHostAddress());<br />
&nbsp;&nbsp;&nbsp;System.out.println(add.getHostName());<br />
&nbsp;&nbsp;&nbsp;System.out.println(InetAddress.getLocalHost());<br />
&nbsp;&nbsp;&nbsp;System.out.println(add.hashCode());<br />
&nbsp;&nbsp;&nbsp;byte [] b= add.getAddress();<br />
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;/*ByteArrayInputStream bais=new ByteArrayInputStream(b);<br />
&nbsp;&nbsp;&nbsp;InputStreamReader isr=new InputStreamReader(bais);<br />
&nbsp;&nbsp;&nbsp;BufferedReader br=new BufferedReader(isr);<br />
&nbsp;&nbsp;&nbsp;char [] ch=new char[b.length];<br />
&nbsp;&nbsp;&nbsp;br.read(ch);<br />
&nbsp;&nbsp;&nbsp;System.out.println(ch);<br />
&nbsp;&nbsp;&nbsp;这段代码依然不能够打印出我们期望的结果*/<br />
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;String s = "12345abcd";<br />
&nbsp;&nbsp;&nbsp;byte b2[] = s.getBytes();<br />
&nbsp;&nbsp;&nbsp;System.out.println(b2.toString());<br />
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;String s1="d我3a你2";<br />
&nbsp;&nbsp;&nbsp;byte [] s2=s1.getBytes();<br />
&nbsp;&nbsp;&nbsp;String s3=new String (s2);<br />
&nbsp;&nbsp;&nbsp;System.out.println(s3);<br />
&nbsp;&nbsp;&nbsp;String tt=new String(b);<br />
&nbsp;&nbsp;&nbsp;System.out.println(tt);<br />
&nbsp;&nbsp;&nbsp;System.out.println(Bytes2String(b));<br />
&nbsp;&nbsp;&nbsp;System.out.println(add.toString());<br />
&nbsp;&nbsp;}catch(Exception e){<br />
&nbsp;&nbsp;&nbsp;System.out.println(e.getMessage());<br />
&nbsp;&nbsp;}<br />
&nbsp;}<br />
&nbsp;<br />
&nbsp;public void init(){<br />
&nbsp;&nbsp;test();<br />
&nbsp;}<br />
&nbsp;<br />
&nbsp;public String Bytes2String(byte [] b){<br />
&nbsp;&nbsp;String str="";<br />
&nbsp;&nbsp;for(int i=0;i&lt;b.length;i++){<br />
&nbsp;&nbsp;&nbsp;int t=(b[i]&lt;&lt;24)&gt;&gt;&gt;24;<br />
&nbsp;&nbsp;&nbsp;str+=Integer.toString(t)+".";<br />
&nbsp;&nbsp;}<br />
&nbsp;&nbsp;str=str.substring(0, str.length()-1);<br />
&nbsp;&nbsp;return str;<br />
&nbsp;}<br />
}</p>
<p>/*说明：<br />
（1）java中定义变量并不需要赋予初始值，系统自动为其赋0值或null，但是这仅限于在类中定义的属于类的类变量，<br />
而对于在类函数中定义的临时变量，则必须要赋初始值，否则会出错的！<br />
（2）位运算赋默认的两端都是int型变量，而且返回值也是int型的。如果在位运算符的两端有一个变量为long型，则返回值也为long型。<br />
（3）对于byte类型，比较特殊，首先它是整型，而且只有一个字节长度，而且是有符号的，这里需要特别说明的是<br />
java中不会区分无符号和有符号，既然byte是一个字节的有符号数，那它的表示范围就是-128~127，但是我们经常会把byte作为<br />
单字节的容器，比如在文件读写时，或作为缓冲区时都是使用byte这种类型，如果要把byte转化为字符时就会有问题，<br />
比如：例如下面一个例子:</p>
<p>&nbsp;import java.io.UnsupportedEncodingException;</p>
<p>&nbsp;public class test{<br />
&nbsp; public static void main(String g[]) {<br />
&nbsp;&nbsp; String s = "12345abcd";<br />
&nbsp;&nbsp; byte b[] = s.getBytes();<br />
&nbsp;&nbsp; String t = b.toString();</p>
<p>&nbsp;&nbsp; System.out.println(t);</p>
<p>&nbsp; }<br />
&nbsp;}<br />
&nbsp;输出字符串的结果和字符串s不一样了.<br />
&nbsp;这是因为对于byte[]类型，它也是Object的子类，但是数组这种特殊的子类并没有特别的实现自己的toString()方法，因此我们调用<br />
&nbsp;"b.toString()"后，实际上还是调用了Object父类里的toString方法&lt;函数体内的具体代码是：<br />
&nbsp;getClass().getName() + "@" + Integer.toHexString(hashCode())&gt;，该方法只是返回了该类的Name+@+hashCode而已！<br />
&nbsp;有意思的是，对于数组类，类名字是在"["后紧跟数组的类型，比如这里返回的就是"[B"，呵呵，挺有趣吧？</p>
<p>&nbsp;经过以下方式转码就可以正确转换了:</p>
<p>&nbsp;public class test{<br />
&nbsp; public static void main(String g[]) {<br />
&nbsp;&nbsp; String s = "12345abcd";<br />
&nbsp;&nbsp; byte b[] = s.getBytes();<br />
&nbsp;&nbsp; try {<br />
&nbsp;&nbsp;&nbsp; String t = new String(b);<br />
&nbsp;&nbsp;&nbsp; System.out.print(t);<br />
&nbsp;&nbsp; } catch (Exception e) {<br />
&nbsp;&nbsp;&nbsp; e.printStackTrace();<br />
&nbsp;&nbsp; }<br />
&nbsp; }<br />
&nbsp;}<br />
因此如果只是单纯的使用它来作为一个中转的用途，那就无所谓了，但是一旦涉及到和字符的转化时就会有问题，<br />
这里就暂且使用上述提到的方法，即重新构造一个String对象，但是构造String对象有着如下的从byte[]<br />
转化为String类型的潜规则：<br />
如果byte里存储的数据范围是0~127时，也就是字节的首位为0时，就会将byte[]数组中的一个字节拿出来转化为一个<br />
两个字节的char类型，并把这个字符放到String中，如果范围为-128~-1时，也就是首位为1时，就会自动的把<br />
btye[]中下一个字节也拿出来，让这两个字节组合成一个两字节的char类型，然后存放到String中。从这里<br />
也可以看出一个潜规则，汉字表示成两字节的二进制时，第一个字节肯定是负值。<br />
因此对于今天做的这个程序来说，想要把保存在byte[]中的IP地址数值直接拿出来，需要人为的把byte中存储的<br />
有符号数转化为无符号数据，用简单的位操作就可以实现了。<br />
（4）还需要说明的一点是，java中没有运算符重载，对于String类所谓的+号可以连接字符串，其实只是在编译器里面做了点手脚，<br />
并不是真正意义上的运算符重载。<br />
（5）最后，还要说明的是，要熟练的掌握String和各种数值类型之间的转化方法：<br />
举int型和String类型转化的例子吧：<br />
int b --&gt; String str：<br />
&lt;1&gt;str=""+b;<br />
&lt;2&gt;str=Integer.toString(b);//从int出发，利用Integer包装类实现<br />
&lt;3&gt;str=String.valueOf(b);//从str出发，利用String类实现<br />
String str --&gt; int b;<br />
b=Integer.parseInt(str);<br />
b=Integer.parseInt(str, int radix); <br />
最后，再对Integer.parseInt方法作一点说明，str字符串只能为三种形式之一，即"[0-9]*"、"-[0-9]*"<br />
和"\u002D[0-9]*"两种形式之一，其中负号'-'的ASCii码就是\u002D，因此这两种形式是等价的，除此之外<br />
的形式均非法，这里为了写得简洁，使用了正则表达式的写法[0-9]*表示任意长度数字序列。<br />
*/</p>
<img src ="http://www.blogjava.net/bacoo/aggbug/171345.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/bacoo/" target="_blank">bacoo</a> 2007-12-28 22:58 <a href="http://www.blogjava.net/bacoo/archive/2007/12/28/171345.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>UDP通信的一个小例子！</title><link>http://www.blogjava.net/bacoo/archive/2007/12/28/171320.html</link><dc:creator>bacoo</dc:creator><author>bacoo</author><pubDate>Fri, 28 Dec 2007 13:12:00 GMT</pubDate><guid>http://www.blogjava.net/bacoo/archive/2007/12/28/171320.html</guid><wfw:comment>http://www.blogjava.net/bacoo/comments/171320.html</wfw:comment><comments>http://www.blogjava.net/bacoo/archive/2007/12/28/171320.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/bacoo/comments/commentRss/171320.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/bacoo/services/trackbacks/171320.html</trackback:ping><description><![CDATA[<p>package com.bacoo.www;</p>
<p>import java.io.IOException;<br />
import java.net.*;</p>
<p>public class UDPServer implements Runnable{</p>
<p>&nbsp;/**<br />
&nbsp; * @param args<br />
&nbsp; */<br />
&nbsp;<br />
&nbsp;public UDPServer(){<br />
&nbsp;&nbsp;new Thread(this).start();<br />
&nbsp;&nbsp;try{<br />
&nbsp;&nbsp;&nbsp;DatagramSocket dgs=new DatagramSocket(8765);<br />
&nbsp;&nbsp;&nbsp;byte [] buf=new byte[1024];<br />
&nbsp;&nbsp;&nbsp;DatagramPacket dgp=new DatagramPacket(buf,buf.length);<br />
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;for(int i=0;i&lt;3;i++){<br />
&nbsp;&nbsp;&nbsp;&nbsp;dgs.receive(dgp);<br />
&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("The server has received the datagram!");<br />
&nbsp;&nbsp;&nbsp;&nbsp;dgs.send(dgp);<br />
&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;}catch(IOException ioe){<br />
&nbsp;&nbsp;&nbsp;ioe.printStackTrace();<br />
&nbsp;&nbsp;}<br />
&nbsp;}<br />
&nbsp;public static void main(String[] args) {<br />
&nbsp;&nbsp;// TODO Auto-generated method stub<br />
&nbsp;&nbsp;new UDPServer();<br />
&nbsp;}</p>
<p>&nbsp;public void run() {<br />
&nbsp;&nbsp;// TODO Auto-generated method stub<br />
&nbsp;&nbsp;new UDPClient();<br />
&nbsp;}</p>
<p>}<br />
/*<br />
说明：<br />
这里要对UDP方式作一个简要的说明，构成UDP通信机制的主要是两个类，即DatagramSocket和DatagramPacket，<br />
主要包括发送和接收两个方面的内容，对于发送方来说，需要：<br />
（1）建立一个DatagramSocket对象，注意建立的时候不需要指定端口，因为发送方关注的是发送成功，而不在乎是从本机的哪个端口发送出去的，<br />
而发送的具体事宜则是由DatagramPacket来完成的，包括对目的地址的指定。<br />
（2）建立一个DatagramPacket对象，注意要制定目的地址和对应的端口A。<br />
（3）调用DatagramSocket对象的send函数发送，send函数的参数就是刚建立的DatagramPacket对象。<br />
对于接收方来讲，需要：<br />
（1）建立一个DatagramSocket对象，注意要指定端口，因为作为接收方，不在乎接收的东西是从哪里来的，而只是在本机的一个指定端口进行<br />
接收就ok了，但需要注意这里的端口要与发送方投递的端口A一致。<br />
（2）建立一个DatagramPacket对象，注意不必指定地址和端口，因为这是被动的接收，而在接收过程中，该DatagramPacket对象<br />
扮演的角色仅仅是一个信息的承载者，也就是把从端口来的信息封存到它里面。<br />
（3）调用DatagramSocket对象的receive函数接收，receive函数的参数就是刚建立的DatagramPacket对象。</p>
<p>最后，还有一点需要说明，就是在刚刚指出的接受模式来说，比如说本例中，虽然未给DatagramPacket对象指定地址和端口，但是<br />
依然可以调用send函数进行发送，这是为什么呢？因为它先调用了receive函数，通过调用该函数，可以在接收过程中保存了信息的来源，<br />
也就是地址和端口，因此下次再用send发送时，就仍然往这个地址和端口发送数据，因此可以发送成功。<br />
*/</p>
<img src ="http://www.blogjava.net/bacoo/aggbug/171320.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/bacoo/" target="_blank">bacoo</a> 2007-12-28 21:12 <a href="http://www.blogjava.net/bacoo/archive/2007/12/28/171320.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[改编]AWT和Swing绘画</title><link>http://www.blogjava.net/bacoo/archive/2007/12/28/171313.html</link><dc:creator>bacoo</dc:creator><author>bacoo</author><pubDate>Fri, 28 Dec 2007 12:31:00 GMT</pubDate><guid>http://www.blogjava.net/bacoo/archive/2007/12/28/171313.html</guid><wfw:comment>http://www.blogjava.net/bacoo/comments/171313.html</wfw:comment><comments>http://www.blogjava.net/bacoo/archive/2007/12/28/171313.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/bacoo/comments/commentRss/171313.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/bacoo/services/trackbacks/171313.html</trackback:ping><description><![CDATA[<p>[改编]AWT和Swing绘画<br />
在AWT中，对于重量级组件，在绘制时按照如下的调用进行：<br />
1)因为系统触发而重绘：（说白了，就是指这种重绘不是人为的，不是我们自己写代码调用repaint()等函数进行重绘，而是系统觉得有必要进行重绘而进行的。）<br />
a.《AWT》确定是一部分还是整个部件需要绘画。<br />
b.《AWT》促使事件分派线程调用部件的paint()方法。<br />
2)因为程序触发而重绘：（人为在消息响应函数中或其他地方强制进行重绘的操作）<br />
a.《程序》确定是一部分还是全部部件需要重画以对应内部状态的改变。 <br />
b.《程序》调用部件的repaint()，该方法向《AWT》登记了一个异步的请求 －－ 当前部件需要重画。 <br />
c.《AWT》促使事件分派线程去调用部件的update() 方法。 <br />
d.如果部件没有覆盖(override)update()方法，update()的默认实现会清除部件背景（如果部件不是&#8220;轻量级&#8221;），然后只是简单地调用paint()方法。<br />
说明：不论是那种触发重绘的方式，均可以归结到paint()函数上来，那为什么对于程序触发方式还要有个中间步骤&#8220;update()&#8221;呢？这是为了让我们能够通过重写update()方法后，在里面进行我们想要的控制，也就是我们可以在这里做点文章。当然我们也可以覆盖paint()函数，但是有了update()函数之后，我们就可以不干扰paint()，让其&#8220;全身心&#8221;的负责绘制，而在update()这个地方进行我们需要的控制。比如提到的只能用到重量级组件的&#8220;增量绘制&#8221;，就是首先由系统触发paint绘制，然后在这个基础上（也就是背景下），在鼠标左键的消息响应函数中调用repaint，然后重写update函数，只是让update函数画新添加的内容，而不在update函数内部再调用paint函数了，这样就避开了paint函数，也就是实现了所谓的&#8220;增量绘制&#8221;。不过需要说明的是，增量绘制只在一些特殊的GUI部件上好用，比如我们下面给的这个例子（就是刚用来描述&#8220;增量绘制&#8221;的那个例子）中就是用的Canvas类，该类直接继承于Component类，注意不是继承自Container类，因为在Container类中又实现了自己的paint方法，有了新的机制，这就和我们上述讲的这一大套基于Component类的paint方法不一致了。</p>
<p>对于轻量级组件，都是继承于Container类的，&#8220;轻量级&#8221;部件需要一个处在容器体系上的&#8220;重量级&#8221;部件提供进行绘画的场所。当这个&#8220;重量级&#8221;的&#8220;祖宗&#8221;被告知要绘制自身的窗体时，它必须把这个绘画的请求转化为对其所有子孙的绘画请求。这是由java.awt.Container的paint()方法处理的，该方法调用包容于其内的所有可见的、并且与绘画区相交的轻量级部件的paint()方法。因此对于所有覆盖了paint()方法的Container子类（&#8220;轻量级&#8221;或&#8220;重量级&#8221;，Container的子类不一定都是轻量级组件哦，呵呵）都需要在函数的最后调用父类的paint方法，即super.paint(g)。</p>
<p>最后，对于AWT绘制，给出以下准则：<br />
a.对于大多数程序，所有的客户区绘画代码应该被放置在部件的paint()方法中。 <br />
b.通过调用repaint()方法，程序可以触发一个将来执行的paint()调用，不能直接调用paint()方法。 <br />
c.对于界面复杂的部件，应该触发带参数的repaint()方法，使用参数定义实际需要更新的区域；而不带参数调用会导致整个部件被重画。 <br />
d.因为对repaint()的调用会首先导致update()的调用，默认地会促成paint()的调用，所以重量级部件应该覆盖update()方法以实现增量绘制，如果需要的话(轻量级部件不支持增量绘制) 。 <br />
e.覆盖了paint()方法的java.awt.Container子类应当在paint()方法中调用super.paint()以保证子部件能被绘制。 <br />
f.界面复杂的部件应该灵活地使用裁剪区来把绘画范围缩小到只包括与裁剪区相交的范围。</p>
<p>==============================================================================<br />
Swing绘画的处理过程<br />
&nbsp;Swing处理"repaint"请求的方式与AWT有稍微地不同，虽然对于应用开发人员来讲其本质是相同的 -- 同样是触发paint()。Swing这么做是为了支持它的RepaintManager API (后面介绍)，就象改善绘画性能一样。在Swing里的绘画可以走两条路，如下所述：</p>
<p>(A) 绘画需求首先产生于一个重量级祖先(通常是JFrame、JDialog、JWindow或者JApplet)：<br />
1。事件分派线程调用其祖先的paint()<br />
2。Container.paint()的默认实现会递归地调用任何轻量级子孙的paint()方法。<br />
3。当到达第一个Swing部件时，JComponent.paint()的默认执行做下面的步骤：<br />
&nbsp;i.如果部件的双缓冲属性为true并且部件的RepaintManager上的双缓冲已经激活，将把Graphics对象转换为一个合适的屏外Graphics。 <br />
&nbsp;ii.调用paintComponent()(如果使用双缓冲就把屏外Graphics传递进去)。 <br />
&nbsp;iii.调用paintBorder()(如果使用双缓冲就把屏外Graphics传递进去)。<br />
&nbsp;iv.调用paintChildren()(如果使用双缓冲就把屏外Graphics传递进去)，该方法使用裁剪并且遮光和optimizedDrawingEnabled等属性来严密地判定要递归地调用哪些子孙的paint()。 <br />
&nbsp;v.如果部件的双缓冲属性为true并且在部件的RepaintManager上的双缓冲已经激活，使用最初的屏幕Graphics对象把屏外映像拷贝到部件上。</p>
<p>&nbsp;注意：JComponent.paint()步骤#1和#5在对paint()的递归调用中被忽略了(这里的JComponent指的是在paintChildren()函数中判断出的需要递归调用的组件，在步骤#4中介绍了)，因为所有在swing窗体层次中的轻量级部件将共享同一个用于双缓冲的屏外映像。 </p>
<p><br />
(B) 绘画需求从一个javax.swing.JCponent扩展类的repaint()调用上产生：<br />
1。JComponent.repaint()注册一个针对部件的RepaintManager的异步的重画需求，该操作使用invokeLater()把一个Runnable加入事件队列以便稍后执行在事件分派线程上的需求。 <br />
&nbsp;<br />
2。该Runnable在事件分派线程上执行并且导致部件的RepaintManager调用该部件上paintImmediately()，该方法执行下列步骤：</p>
<p>&nbsp;i.使用裁剪框以及遮光和optimizedDrawingEnabled属性确定&#8220;根&#8221;部件，绘画一定从这个部件开始(处理透明以及潜在的重迭部件)。 <br />
&nbsp;ii.如果根部件的双缓冲属性为true，并且根部件的RepaintManager上的双缓冲已激活，将转换Graphics对象到适当的屏外Graphics。 <br />
&nbsp;iii.调用根部件(该部件执行上述(A)中的JComponent.paint()步骤#2-4)上的paint()，导致根部件之下的、与裁剪框相交的所有部件被绘制。 <br />
&nbsp;iv.如果根部件的doubleBuffered属性为true并且根部件的RepaintManager上的双缓冲已经激活，使用原始的Graphics把屏外映像拷贝到部件。</p>
<p>&nbsp;注意：如果在重画没有完成之前，又有发生多起对部件或者任何一个其祖先的repaint()调用，所有这些调用会被折迭到一个单一的调用，即回到最上层（这里的层指的是那种Hierarchy，而不是展现给我们的最上面的那个图或者按钮）的SWing部件的paintImmediately()，调用它的repaint()。例如，如果一个JTabbedPane包含了一个JTable并且在其包容层次中的现有的重画需求完成之前两次发布对repaint()的调用，其结果将变成对该JTabbedPane部件的paintImmediately()方法的单一调用，会触发两个部件的paint()的执行。<br />
&nbsp;<br />
这意味着对于Swing部件来说，update()不再被调用。 </p>
<p>虽然repaint()方法导致了对paintImmediately()的调用，它不考虑"回调"绘图，并且客户端的绘画代码也不会放置到paintImmediately()方法里面。实际上，除非有特殊的原因，根本不需要超载paintImmediately()方法。 </p>
<p>===================================================================================<br />
Swing绘画准则<br />
Swing开发人员在写绘画代码时应该理解下面的准则：<br />
1。对于Swing部件，不管是系统－触发还是程序－触发的请求，总会调用paint()方法；而update()不再被Swing部件调用。 <br />
&nbsp;<br />
2。程序可以通过repaint()触发一个异步的paint()调用，但是不能直接调用paint()。 <br />
&nbsp;<br />
3。对于复杂的界面，应该调用带参数的repaint()，这样可以仅仅更新由该参数定义的区域；而不要调用无参数的repaint()，导致整个部件重画。 <br />
&nbsp;<br />
4。Swing中实现paint()的3个要素是调用3个分离的回调方法：<br />
&nbsp;paintComponent() <br />
&nbsp;paintBorder() <br />
&nbsp;paintChildren() <br />
&nbsp;Swing部件的子类，如果想执行自己的绘画代码，应该把自己的绘画代码放在paintComponent()方法的范围之内。(不要放在paint()里面)。 <br />
&nbsp;<br />
5。Swing引进了两个属性来最大化的改善绘画的性能︰ <br />
&nbsp;opaque: 部件是否要重画它所占据范围中的所有像素位？ <br />
&nbsp;optimizedDrawingEnabled: 是否有这个部件的子孙与之交迭？ <br />
&nbsp;<br />
6。如果Swing部件的(遮光)opaque属性设置为true，那就表示它要负责绘制它所占据的范围内的所有像素位(包括在paintComponent()中清除它自己的背景)，否则会造成屏幕垃圾。 <br />
7。如果一个部件的遮光性(opaque)和optimizedDrawingEnabled属性有一个被设置为false，将导致在每个绘画操作中要执行更多的处理，因此我们推荐的明智的方法是同时使用透明并且交迭部件。 <br />
8。使用UI代理(包括JPanel)的Swing部件的扩展类的典型作法是在它们自己的paintComponent()的实现中调用super.paintComponent()。因为UI代理可以负责清除一个遮光部件的背景，不过这一操作需要根据规则#5中的设定来决定。<br />
9。Swing通过JComponent的doubleBuffered属性支持内置的双缓冲，所有的Swing部件该属性默认值是true，然而把Swing容器的遮光设置为true有一个整体的构思，把该容器上的所有轻量级子孙的属性打开，不管它们各自的设定。 <br />
10。强烈建议为所有的Swing部件使用双缓冲。 <br />
11。界面复杂的部件应该灵活地运用剪切框来，只对那些与剪切框相交的区域进行绘画操作，从而减少工作量。 </p>
<p><br />
P.S.英文出处：http://java.sun.com/products/jfc/tsc/articles/painting/index.html</p>
<img src ="http://www.blogjava.net/bacoo/aggbug/171313.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/bacoo/" target="_blank">bacoo</a> 2007-12-28 20:31 <a href="http://www.blogjava.net/bacoo/archive/2007/12/28/171313.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转载]Java反射机制</title><link>http://www.blogjava.net/bacoo/archive/2007/12/21/169450.html</link><dc:creator>bacoo</dc:creator><author>bacoo</author><pubDate>Fri, 21 Dec 2007 13:50:00 GMT</pubDate><guid>http://www.blogjava.net/bacoo/archive/2007/12/21/169450.html</guid><wfw:comment>http://www.blogjava.net/bacoo/comments/169450.html</wfw:comment><comments>http://www.blogjava.net/bacoo/archive/2007/12/21/169450.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/bacoo/comments/commentRss/169450.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/bacoo/services/trackbacks/169450.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 摘要Reflection 是Java被视为动态（或准动态）语言的一个关键性质。这个机制允许程序在运行时透过Reflection APIs取得任何一个已知名称的class的内部信息，包括其modifiers（诸如public, static 等等）、superclass（例如Object）、实现之interfaces（例如Cloneable），也包括fields和methods的所有信息，并可于...&nbsp;&nbsp;<a href='http://www.blogjava.net/bacoo/archive/2007/12/21/169450.html'>阅读全文</a><img src ="http://www.blogjava.net/bacoo/aggbug/169450.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/bacoo/" target="_blank">bacoo</a> 2007-12-21 21:50 <a href="http://www.blogjava.net/bacoo/archive/2007/12/21/169450.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JTree学习笔记！</title><link>http://www.blogjava.net/bacoo/archive/2007/12/21/169445.html</link><dc:creator>bacoo</dc:creator><author>bacoo</author><pubDate>Fri, 21 Dec 2007 12:56:00 GMT</pubDate><guid>http://www.blogjava.net/bacoo/archive/2007/12/21/169445.html</guid><wfw:comment>http://www.blogjava.net/bacoo/comments/169445.html</wfw:comment><comments>http://www.blogjava.net/bacoo/archive/2007/12/21/169445.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/bacoo/comments/commentRss/169445.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/bacoo/services/trackbacks/169445.html</trackback:ping><description><![CDATA[<p>对于JTree比较重要的几个类或接口：<br />
1。TreeMode是一个接口，是构建树的模型，接口中比较重要的几个函数是：getChild、getChildCount、getRoot、getIndexOfChild、isLeaf。如果想把一些特殊的东西抽象成一棵树，那么就可以实现该接口，用自己构造的这个模型来创建树JTree(TreeModel newModel) <br />
2。TreeNode是一个接口，代表树的节点。DefaultMutableTreeNode是该接口的一个实现，可以直接用来创建树的节点。<br />
3。TreePath是一个类，负责节点到根的路径<br />
4。TreeSelectionModel是一个接口，表示树选择组件的当前状态。DefaultTreeSelectionModel类是该接口的一个实现类。</p>
<p>
<table cellspacing="0" cellpadding="3" width="100%" summary="" border="1">
    <tbody>
        <tr class="TableHeadingColor" bgcolor="#ccccff">
            <th align="left" colspan="2"><font size="+2"><strong>构造方法摘要</strong></font></th>
        </tr>
        <tr class="TableRowColor" bgcolor="white">
            <td><code><strong><a href="file:///D:/Program%20Files/Java/api/javax/swing/JTree.html#JTree()">JTree</a></strong>()</code> <br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;返回带有示例模型的 <code>JTree</code>。</td>
        </tr>
        <tr class="TableRowColor" bgcolor="white">
            <td><code><strong><a href="file:///D:/Program%20Files/Java/api/javax/swing/JTree.html#JTree(java.util.Hashtable)">JTree</a></strong>(<a title="java.util 中的类" href="file:///D:/Program%20Files/Java/api/java/util/Hashtable.html">Hashtable</a>&lt;?,?&gt;&nbsp;value)</code> <br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;返回从 <code>Hashtable</code> 创建的 <code>JTree</code>，它不显示根。</td>
        </tr>
        <tr class="TableRowColor" bgcolor="white">
            <td><code><strong><a href="file:///D:/Program%20Files/Java/api/javax/swing/JTree.html#JTree(java.lang.Object[])">JTree</a></strong>(<a title="java.lang 中的类" href="file:///D:/Program%20Files/Java/api/java/lang/Object.html">Object</a>[]&nbsp;value)</code> <br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;返回 <code>JTree</code>，指定数组的每个元素作为不被显示的新根节点的子节点。</td>
        </tr>
        <tr class="TableRowColor" bgcolor="white">
            <td><code><strong><a href="file:///D:/Program%20Files/Java/api/javax/swing/JTree.html#JTree(javax.swing.tree.TreeModel)">JTree</a></strong>(<a title="javax.swing.tree 中的接口" href="file:///D:/Program%20Files/Java/api/javax/swing/tree/TreeModel.html">TreeModel</a>&nbsp;newModel)</code> <br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;返回 <code>JTree</code> 的一个实例，它显示根节点 - 使用指定的数据模型创建树。</td>
        </tr>
        <tr class="TableRowColor" bgcolor="white">
            <td><code><strong><a href="file:///D:/Program%20Files/Java/api/javax/swing/JTree.html#JTree(javax.swing.tree.TreeNode)">JTree</a></strong>(<a title="javax.swing.tree 中的接口" href="file:///D:/Program%20Files/Java/api/javax/swing/tree/TreeNode.html">TreeNode</a>&nbsp;root)</code> <br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;返回 <code>JTree</code>，指定的 <code>TreeNode</code> 作为其根，它显示根节点。</td>
        </tr>
        <tr class="TableRowColor" bgcolor="white">
            <td><code><strong><a href="file:///D:/Program%20Files/Java/api/javax/swing/JTree.html#JTree(javax.swing.tree.TreeNode, boolean)">JTree</a></strong>(<a title="javax.swing.tree 中的接口" href="file:///D:/Program%20Files/Java/api/javax/swing/tree/TreeNode.html">TreeNode</a>&nbsp;root, boolean&nbsp;asksAllowsChildren)</code> <br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;返回 <code>JTree</code>，指定的 <code>TreeNode</code> 作为其根，它用指定的方式显示根节点，并确定节点是否为叶节点。</td>
        </tr>
        <tr class="TableRowColor" bgcolor="white">
            <td><code><strong><a href="file:///D:/Program%20Files/Java/api/javax/swing/JTree.html#JTree(java.util.Vector)">JTree</a></strong>(<a title="java.util 中的类" href="file:///D:/Program%20Files/Java/api/java/util/Vector.html">Vector</a>&lt;?&gt;&nbsp;value)</code> <br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;返回 <code>JTree</code>，指定 <code>Vector</code> 的每个元素作为不被显示的新根节点的子节点。</td>
        </tr>
    </tbody>
</table>
</p>
<p>常用方法：<br />
1。得到模型：<br />
getModel()或(DefaultTreeModel)getModel()<br />
2。得到根：<br />
getModel().getRoot()或(DefaultMutableTreeNode)getModel().getRoot()<br />
3。根据node得到path：<br />
TreePath visiblePath = new TreePath(((DefaultTreeModel)getModel()).getPathToRoot(node))<br />
4。根据Path展开到该节点：<br />
makeVisible(visiblePath)<br />
5。根据path设定该节点选定<br />
tree.setSelectionPath(visiblePath)<br />
6。滚动到可见位置：<br />
scrollRowToVisible(int row)<br />
7。展开树&lt;从根展开或从某一个节点展开&gt;<br />
关于JTree的展开<br />
&nbsp;&nbsp; // If expand is true, expands all nodes in the tree.<br />
&nbsp;&nbsp; // Otherwise, collapses all nodes in the tree.<br />
&nbsp;public static void expandAll(JTree tree, boolean expand) {<br />
&nbsp;&nbsp;TreeNode root = (TreeNode) tree.getModel().getRoot();</p>
<p>&nbsp;&nbsp;// Traverse tree from root<br />
&nbsp;&nbsp;expandAll(tree, new TreePath(root), expand);<br />
&nbsp;}</p>
<p>&nbsp;private static void expandAll(JTree tree, TreePath parent, boolean expand) {<br />
&nbsp;&nbsp;// Traverse children<br />
&nbsp;&nbsp;TreeNode node = (TreeNode) parent.getLastPathComponent();<br />
&nbsp;&nbsp;if (node.getChildCount() &gt;= 0) {<br />
&nbsp;&nbsp;&nbsp;for (Enumeration e = node.children(); e.hasMoreElements();) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;TreeNode n = (TreeNode) e.nextElement();<br />
&nbsp;&nbsp;&nbsp;&nbsp;TreePath path = parent.pathByAddingChild(n);<br />
&nbsp;&nbsp;&nbsp;&nbsp;expandAll(tree, path, expand);<br />
&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;// Expansion or collapse must be done bottom-up<br />
&nbsp;&nbsp;if (expand) {<br />
&nbsp;&nbsp;&nbsp;tree.expandPath(parent);<br />
&nbsp;&nbsp;} else {<br />
&nbsp;&nbsp;&nbsp;tree.collapsePath(parent);<br />
&nbsp;&nbsp;}<br />
&nbsp;}<br />
8。遍历树的所有节点&lt;从根遍历或从某一个节点遍历&gt;<br />
public static void visitAllNodes(JTree tree) {<br />
&nbsp;&nbsp;TreeNode root = (TreeNode) tree.getModel().getRoot();<br />
&nbsp;&nbsp;visitAllNodes(tree,root);<br />
&nbsp;}</p>
<p>&nbsp;public static void visitAllNodes(JTree tree,TreeNode node) {<br />
&nbsp;&nbsp;// node is visited exactly once<br />
&nbsp;&nbsp;//you can do your things about this node,such as:<br />
&nbsp;&nbsp;tree.makeVisible(new TreePath(<br />
&nbsp;&nbsp;&nbsp;&nbsp;((DefaultTreeModel)tree.getModel()).getPathToRoot(node)));</p>
<p>&nbsp;&nbsp;if (node.getChildCount() &gt;= 0) {<br />
&nbsp;&nbsp;&nbsp;for (Enumeration e = node.children(); e.hasMoreElements();) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;TreeNode n = (TreeNode) e.nextElement();<br />
&nbsp;&nbsp;&nbsp;&nbsp;visitAllNodes(tree,n);<br />
&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;}<br />
&nbsp;}<br />
9。遍历树已经展开的节点&lt;从根遍历或从某一个节点遍历&gt;<br />
// Traverse all expanded nodes in tree<br />
&nbsp;public static void visitAllExpandedNodes(JTree tree) {<br />
&nbsp;&nbsp;TreeNode root = (TreeNode) tree.getModel().getRoot();<br />
&nbsp;&nbsp;visitAllExpandedNodes(tree, new TreePath(root));<br />
&nbsp;}</p>
<p>&nbsp;public static void visitAllExpandedNodes(JTree tree, TreePath parent) {<br />
&nbsp;&nbsp;// Return if node is not expanded<br />
&nbsp;&nbsp;if (!tree.isVisible(parent)) {<br />
&nbsp;&nbsp;&nbsp;return;<br />
&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;// node is visible and is visited exactly once<br />
&nbsp;&nbsp;TreeNode node = (TreeNode) parent.getLastPathComponent();<br />
&nbsp;&nbsp;//you can do your things about this node,such as:<br />
&nbsp;&nbsp;System.out.println(node.toString());</p>
<p>&nbsp;&nbsp;// Visit all children<br />
&nbsp;&nbsp;if (node.getChildCount() &gt;= 0) {<br />
&nbsp;&nbsp;&nbsp;for (Enumeration e = node.children(); e.hasMoreElements();) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;TreeNode n = (TreeNode) e.nextElement();<br />
&nbsp;&nbsp;&nbsp;&nbsp;TreePath path = parent.pathByAddingChild(n);<br />
&nbsp;&nbsp;&nbsp;&nbsp;visitAllExpandedNodes(tree, path);<br />
&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;}<br />
&nbsp;}</p>
<p>一个较为完整的练习：<br />
import java.awt.Dimension;<br />
import java.awt.Color;<br />
import java.awt.event.MouseAdapter;<br />
import java.awt.event.MouseEvent;<br />
import java.util.Enumeration;<br />
import javax.swing.JFrame;<br />
import javax.swing.JPanel;<br />
import javax.swing.JScrollPane;<br />
import javax.swing.JTree;<br />
import javax.swing.BoxLayout;<br />
import javax.swing.tree.DefaultMutableTreeNode;<br />
import javax.swing.tree.DefaultTreeModel;<br />
import javax.swing.tree.TreeNode;<br />
import javax.swing.tree.TreePath;</p>
<p>public class JTreeDemo {</p>
<p>&nbsp;public static void expandAll(JTree tree, boolean expand) {<br />
&nbsp;&nbsp;TreeNode root = (TreeNode) tree.getModel().getRoot();</p>
<p>&nbsp;&nbsp;// Traverse tree from root<br />
&nbsp;&nbsp;expandAll(tree, new TreePath(root), expand);<br />
&nbsp;}</p>
<p>&nbsp;private static void expandAll(JTree tree, TreePath parent, boolean expand) {<br />
&nbsp;&nbsp;// Traverse children<br />
&nbsp;&nbsp;TreeNode node = (TreeNode) parent.getLastPathComponent();<br />
&nbsp;&nbsp;if (node.getChildCount() &gt;= 0) {<br />
&nbsp;&nbsp;&nbsp;for (Enumeration e = node.children(); e.hasMoreElements();) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;TreeNode n = (TreeNode) e.nextElement();<br />
&nbsp;&nbsp;&nbsp;&nbsp;TreePath path = parent.pathByAddingChild(n);<br />
&nbsp;&nbsp;&nbsp;&nbsp;expandAll(tree, path, expand);<br />
&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;// Expansion or collapse must be done bottom-up<br />
&nbsp;&nbsp;if (expand) {<br />
&nbsp;&nbsp;&nbsp;tree.expandPath(parent);<br />
&nbsp;&nbsp;} else {<br />
&nbsp;&nbsp;&nbsp;tree.collapsePath(parent);<br />
&nbsp;&nbsp;}<br />
&nbsp;}</p>
<p>&nbsp;<br />
&nbsp;public static void visitAllNodes(JTree tree) {<br />
&nbsp;&nbsp;TreeNode root = (TreeNode) tree.getModel().getRoot();<br />
&nbsp;&nbsp;visitAllNodes(tree,root);<br />
&nbsp;}</p>
<p>&nbsp;public static void visitAllNodes(JTree tree,TreeNode node) {<br />
&nbsp;&nbsp;// node is visited exactly once<br />
&nbsp;&nbsp;//you can do your things about this node,such as:<br />
&nbsp;&nbsp;tree.makeVisible(new TreePath(<br />
&nbsp;&nbsp;&nbsp;&nbsp;((DefaultTreeModel)tree.getModel()).getPathToRoot(node)));</p>
<p>&nbsp;&nbsp;if (node.getChildCount() &gt;= 0) {<br />
&nbsp;&nbsp;&nbsp;for (Enumeration e = node.children(); e.hasMoreElements();) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;TreeNode n = (TreeNode) e.nextElement();<br />
&nbsp;&nbsp;&nbsp;&nbsp;visitAllNodes(tree,n);<br />
&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;}<br />
&nbsp;}</p>
<p>&nbsp;// Traverse all expanded nodes in tree<br />
&nbsp;public static void visitAllExpandedNodes(JTree tree) {<br />
&nbsp;&nbsp;TreeNode root = (TreeNode) tree.getModel().getRoot();<br />
&nbsp;&nbsp;visitAllExpandedNodes(tree, new TreePath(root));<br />
&nbsp;}</p>
<p>&nbsp;public static void visitAllExpandedNodes(JTree tree, TreePath parent) {<br />
&nbsp;&nbsp;// Return if node is not expanded<br />
&nbsp;&nbsp;if (!tree.isVisible(parent)) {<br />
&nbsp;&nbsp;&nbsp;return;<br />
&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;// node is visible and is visited exactly once<br />
&nbsp;&nbsp;TreeNode node = (TreeNode) parent.getLastPathComponent();<br />
&nbsp;&nbsp;//you can do your things about this node,such as:<br />
&nbsp;&nbsp;System.out.println(node.toString());</p>
<p>&nbsp;&nbsp;// Visit all children<br />
&nbsp;&nbsp;if (node.getChildCount() &gt;= 0) {<br />
&nbsp;&nbsp;&nbsp;for (Enumeration e = node.children(); e.hasMoreElements();) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;TreeNode n = (TreeNode) e.nextElement();<br />
&nbsp;&nbsp;&nbsp;&nbsp;TreePath path = parent.pathByAddingChild(n);<br />
&nbsp;&nbsp;&nbsp;&nbsp;visitAllExpandedNodes(tree, path);<br />
&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;}<br />
&nbsp;}<br />
&nbsp;public static JTree tr;<br />
&nbsp;public static void main(String[] args) {</p>
<p>&nbsp;&nbsp;// 构造函数：JTree()<br />
&nbsp;&nbsp;JTree example1 = new JTree();<br />
&nbsp;&nbsp;tr=example1;<br />
&nbsp;&nbsp;example1.setBackground(Color.lightGray);<br />
&nbsp;&nbsp;example1.addMouseListener(new MouseAdapter(){<br />
&nbsp;&nbsp;&nbsp;public void mouseClicked(MouseEvent me){<br />
&nbsp;&nbsp;&nbsp;&nbsp;try{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;visitAllNodes(tr);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread.sleep(2000);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(tr.getPathForRow(1).toString());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;expandAll(tr,tr.getPathForRow(1),false);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread.sleep(2000);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;visitAllExpandedNodes(tr);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}catch(InterruptedException e){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;});</p>
<p>&nbsp;&nbsp;// 构造函数：JTree(Object[] value)<br />
&nbsp;&nbsp;Object[] letters = { " a ", " b ", " c ", " d ", " e " };<br />
&nbsp;&nbsp;JTree example2 = new JTree(letters);</p>
<p>&nbsp;&nbsp;// 构造函数：JTree(TreeNode root)(TreeNode空)<br />
&nbsp;&nbsp;// 用空结点创建树<br />
&nbsp;&nbsp;DefaultMutableTreeNode node1 = new DefaultMutableTreeNode(); // 定义树结点<br />
&nbsp;&nbsp;JTree example3 = new JTree(node1); // 用此树结点做参数调用 JTree的构造函数创建含有一个根结点的树</p>
<p>&nbsp;&nbsp;// 构造函数：JTree(TreeNode root)(同上,只是TreeNode非空)<br />
&nbsp;&nbsp;// 用一个根结点创建树<br />
&nbsp;&nbsp;DefaultMutableTreeNode node2 = new DefaultMutableTreeNode(" Color ");<br />
&nbsp;&nbsp;JTree example4 = new JTree(node2); // 结点不可以颜色,默认为白面黑字<br />
&nbsp;&nbsp;example4.setBackground(Color.lightGray);</p>
<p>&nbsp;&nbsp;// 构造函数：JTree(TreeNode root, boolean<br />
&nbsp;&nbsp;// asksAllowsChildren)(同上,只是TreeNode又有不同)<br />
&nbsp;&nbsp;// 使用DefaultMutableTreeNode类先用一个根结点创建树，设置为可添加孩子结点,再添加孩子结点<br />
&nbsp;&nbsp;DefaultMutableTreeNode color = new DefaultMutableTreeNode(" Color ",<br />
&nbsp;&nbsp;&nbsp;&nbsp;true);<br />
&nbsp;&nbsp;DefaultMutableTreeNode gray = new DefaultMutableTreeNode(" Gray ");<br />
&nbsp;&nbsp;color.add(gray);<br />
&nbsp;&nbsp;color.add(new DefaultMutableTreeNode(" Red "));<br />
&nbsp;&nbsp;gray.add(new DefaultMutableTreeNode(" Lightgray "));<br />
&nbsp;&nbsp;gray.add(new DefaultMutableTreeNode(" Darkgray "));<br />
&nbsp;&nbsp;color.add(new DefaultMutableTreeNode(" Green "));<br />
&nbsp;&nbsp;JTree example5 = new JTree(color);</p>
<p>&nbsp;&nbsp;// 构造函数：JTree(TreeNode root)(同上,只是TreeNode非空)<br />
&nbsp;&nbsp;// 通过逐个添加结点创建树<br />
&nbsp;&nbsp;DefaultMutableTreeNode biology = new DefaultMutableTreeNode(" Biology ");<br />
&nbsp;&nbsp;DefaultMutableTreeNode animal = new DefaultMutableTreeNode(" Animal ");<br />
&nbsp;&nbsp;DefaultMutableTreeNode mammal = new DefaultMutableTreeNode(" Mammal ");<br />
&nbsp;&nbsp;DefaultMutableTreeNode horse = new DefaultMutableTreeNode(" Horse ");<br />
&nbsp;&nbsp;mammal.add(horse);<br />
&nbsp;&nbsp;animal.add(mammal);<br />
&nbsp;&nbsp;biology.add(animal);<br />
&nbsp;&nbsp;JTree example6 = new JTree(biology);<br />
&nbsp;&nbsp;horse.isLeaf();<br />
&nbsp;&nbsp;horse.isRoot();</p>
<p>&nbsp;&nbsp;// 构造函数:JTree(TreeModel newModel)<br />
&nbsp;&nbsp;// 用DefaultMutableTreeNodel类定义一个结点再用这个结点做参数定义一个用DefaultTreeMode<br />
&nbsp;&nbsp;// 创建一个树的模型,再用JTree的构造函数创建一个树</p>
<p>&nbsp;&nbsp;DefaultMutableTreeNode root = new DefaultMutableTreeNode(" Root1 ");<br />
&nbsp;&nbsp;DefaultMutableTreeNode child1 = new DefaultMutableTreeNode(" Child1 ");<br />
&nbsp;&nbsp;DefaultMutableTreeNode child11 = new DefaultMutableTreeNode(" Child11 ");<br />
&nbsp;&nbsp;DefaultMutableTreeNode child111 = new DefaultMutableTreeNode(<br />
&nbsp;&nbsp;&nbsp;&nbsp;" Child111 ");<br />
&nbsp;&nbsp;root.add(child1);<br />
&nbsp;&nbsp;child1.add(child11);<br />
&nbsp;&nbsp;child11.add(child111);</p>
<p>&nbsp;&nbsp;DefaultTreeModel model = new DefaultTreeModel(root);</p>
<p>&nbsp;&nbsp;JTree example7 = new JTree(model);</p>
<p>&nbsp;&nbsp;JPanel panel = new JPanel();<br />
&nbsp;&nbsp;panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));<br />
&nbsp;&nbsp;panel.setPreferredSize(new Dimension(700, 400));<br />
&nbsp;&nbsp;panel.add(new JScrollPane(example1)); // JTree必须放在JScrollPane上<br />
&nbsp;&nbsp;panel.add(new JScrollPane(example2));<br />
&nbsp;&nbsp;panel.add(new JScrollPane(example3));<br />
&nbsp;&nbsp;panel.add(new JScrollPane(example4));<br />
&nbsp;&nbsp;panel.add(new JScrollPane(example5));<br />
&nbsp;&nbsp;panel.add(new JScrollPane(example6));<br />
&nbsp;&nbsp;panel.add(new JScrollPane(example7));</p>
<p>&nbsp;&nbsp;JFrame frame = new JFrame(" JTreeDemo ");<br />
&nbsp;&nbsp;frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);<br />
&nbsp;&nbsp;frame.setContentPane(panel);<br />
&nbsp;&nbsp;frame.pack();<br />
&nbsp;&nbsp;frame.setVisible(true);<br />
&nbsp;}<br />
}</p>
<p>另外一个例子，在该例子中笔者使用基于本机目录构建的模型来构建树：<br />
</p>
<p>/** <br />
&nbsp;* 查API时发现1.4FileSystemView这个东东多了一些功能, <br />
&nbsp;* 无聊地写了这个文件目录树 <br />
&nbsp;* <br />
&nbsp;* 声明：使用j2sdk1.4 <br />
&nbsp;* 建议:实现自己的File类，以过滤掉一般文件，只剩下目录 <br />
&nbsp;* 缺点：gui慢得要死,swing的通病?(my pc==256ddr,thunderbird900,xp) <br />
&nbsp;*/</p>
<p>import java.awt.Component;<br />
import java.io.*;<br />
import javax.swing.*;<br />
import javax.swing.event.TreeModelListener;<br />
import javax.swing.filechooser.FileSystemView;<br />
import javax.swing.tree.*;</p>
<p>public class Test {</p>
<p>&nbsp;/** <br />
&nbsp; * javax.swing.filechooser.FileSystemView在这个程序里很重要， <br />
&nbsp; * 用法参考j2sdk1.4 API文档 <br />
&nbsp; * 切记，1.4 not 1.3!!!!!!!! <br />
&nbsp; */<br />
&nbsp;private static FileSystemView fileView;<br />
&nbsp;int a=BB;<br />
&nbsp;static int BB=34;</p>
<p>&nbsp;/** <br />
&nbsp; *在这里使用了Singleton模式 <br />
&nbsp; * 不过似乎没什么破用 <br />
&nbsp; */<br />
&nbsp;static FileSystemView getFileView() {<br />
&nbsp;&nbsp;if (fileView == null)<br />
&nbsp;&nbsp;&nbsp;fileView = FileSystemView.getFileSystemView();<br />
&nbsp;&nbsp;return fileView;<br />
&nbsp;}<br />
&nbsp;&nbsp;<br />
&nbsp;public static void main(String[] args) throws Exception {<br />
&nbsp;&nbsp;//如果加入下面这句,会乱码.i wonder why <br />
&nbsp;&nbsp;UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName()); </p>
<p>&nbsp;&nbsp;//initial frame <br />
&nbsp;&nbsp;JFrame frame = new JFrame();<br />
&nbsp;&nbsp;frame.setSize(400, 300);<br />
&nbsp;&nbsp;//关闭窗口时退出程序 <br />
&nbsp;&nbsp;frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);</p>
<p>&nbsp;&nbsp;//initial tree with customer TreeModel <br />
&nbsp;&nbsp;<br />
&nbsp;&nbsp;JTree tree = new JTree(new CustomTreeModel());</p>
<p>&nbsp;&nbsp;//set customer TreeCellRenderer <br />
&nbsp;&nbsp;tree.setCellRenderer(new CustomTreeCellRenderer());<br />
&nbsp;&nbsp;frame.getContentPane().add(new JScrollPane(tree));<br />
&nbsp;&nbsp;frame.setVisible(true);<br />
&nbsp;}<br />
}</p>
<p>class CustomTreeModel implements TreeModel {<br />
&nbsp;private FileSystemView fileView;</p>
<p>&nbsp;public CustomTreeModel() {<br />
&nbsp;&nbsp;fileView = Test.getFileView();<br />
&nbsp;}</p>
<p>&nbsp;//返回根节点 <br />
&nbsp;public Object getRoot() {<br />
&nbsp;&nbsp;return fileView.getRoots()[0];<br />
&nbsp;}</p>
<p>&nbsp;//返回父节点parent的第index个子节点,index以0开始 <br />
&nbsp;public Object getChild(Object _parent, int index) {<br />
&nbsp;&nbsp;File parent = (File) _parent;<br />
&nbsp;&nbsp;return parent.listFiles()[index];<br />
&nbsp;}</p>
<p>&nbsp;//返回父节点parent下,子节点child的位置,与上面的方法正好相反 <br />
&nbsp;public int getIndexOfChild(Object parent, Object child) {<br />
&nbsp;&nbsp;File[] files = ((File) parent).listFiles();<br />
&nbsp;&nbsp;for (int i = 0; i &lt; files.length; i++) {<br />
&nbsp;&nbsp;&nbsp;if (files[i].equals(child))<br />
&nbsp;&nbsp;&nbsp;&nbsp;return i;<br />
&nbsp;&nbsp;}<br />
&nbsp;&nbsp;return -1;<br />
&nbsp;}</p>
<p>&nbsp;//返回父节点parent的子节点数 <br />
&nbsp;public int getChildCount(Object parent) {<br />
&nbsp;&nbsp;File[] files = ((File) parent).listFiles();<br />
&nbsp;&nbsp;/** <br />
&nbsp;&nbsp; *maybe driver not ready,ie cdrom <br />
&nbsp;&nbsp; *then files is null <br />
&nbsp;&nbsp; */<br />
&nbsp;&nbsp;if (files == null)<br />
&nbsp;&nbsp;&nbsp;return -1;</p>
<p>&nbsp;&nbsp;return files.length;<br />
&nbsp;}</p>
<p>&nbsp;//是否叶节点 <br />
&nbsp;public boolean isLeaf(Object node) {<br />
&nbsp;&nbsp;return ((File) node).isFile();<br />
&nbsp;}</p>
<p>&nbsp;public void valueForPathChanged(TreePath path, Object newValue) {<br />
&nbsp;}</p>
<p>&nbsp;/** <br />
&nbsp; *下面的方法要实现,则要涉及比较复杂的事件处理 <br />
&nbsp; *如果有兴趣, <br />
&nbsp; *可以简单的使用javax.swing.EventListenerList来实现 <br />
&nbsp; */<br />
&nbsp;public void addTreeModelListener(TreeModelListener l) {<br />
&nbsp;}</p>
<p>&nbsp;public void removeTreeModelListener(TreeModelListener l) {<br />
&nbsp;}</p>
<p>}</p>
<p>/** <br />
&nbsp;* 如果没有安装自己的CellRenderer <br />
&nbsp;* JTree默认的CellRenderer就是JLabel <br />
&nbsp;* 它只是简单的setText(node.toString) <br />
&nbsp;* CustomeTreeCellRenderer也只是简单取回 <br />
&nbsp;* windows默认的文件图标和文件名,装到JLabel上去 <br />
&nbsp;*/</p>
<p>class CustomTreeCellRenderer extends DefaultTreeCellRenderer {<br />
&nbsp;/**<br />
&nbsp; * <br />
&nbsp; */<br />
&nbsp;private static final long serialVersionUID = 3892593039200536416L;<br />
&nbsp;private FileSystemView fileView;</p>
<p>&nbsp;public CustomTreeCellRenderer() {<br />
&nbsp;&nbsp;fileView = Test.getFileView();<br />
&nbsp;}</p>
<p>&nbsp;public Component getTreeCellRendererComponent(JTree tree, Object value,<br />
&nbsp;&nbsp;&nbsp;boolean selected, boolean expanded, boolean leaf, int row,<br />
&nbsp;&nbsp;&nbsp;boolean hasFocus) {<br />
&nbsp;&nbsp;super.getTreeCellRendererComponent(tree, value, selected, expanded,<br />
&nbsp;&nbsp;&nbsp;&nbsp;leaf, row, hasFocus);<br />
&nbsp;&nbsp;File file = (File) value;<br />
&nbsp;&nbsp;setIcon(fileView.getSystemIcon(file));<br />
&nbsp;&nbsp;setText(fileView.getSystemDisplayName(file));<br />
&nbsp;&nbsp;return this;<br />
&nbsp;}<br />
}</p>
<img src ="http://www.blogjava.net/bacoo/aggbug/169445.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/bacoo/" target="_blank">bacoo</a> 2007-12-21 20:56 <a href="http://www.blogjava.net/bacoo/archive/2007/12/21/169445.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>jdbc的一些事儿！</title><link>http://www.blogjava.net/bacoo/archive/2007/12/20/169194.html</link><dc:creator>bacoo</dc:creator><author>bacoo</author><pubDate>Thu, 20 Dec 2007 15:48:00 GMT</pubDate><guid>http://www.blogjava.net/bacoo/archive/2007/12/20/169194.html</guid><wfw:comment>http://www.blogjava.net/bacoo/comments/169194.html</wfw:comment><comments>http://www.blogjava.net/bacoo/archive/2007/12/20/169194.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/bacoo/comments/commentRss/169194.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/bacoo/services/trackbacks/169194.html</trackback:ping><description><![CDATA[<p>数据库分为两类，一类是可以自己本地管理的，例如Access、FoxBase等；另一类是供PC机通过服务器访问的数据库，例如Oracle、MS SQL Server等大型数据库。为了让数据库提供给用户统一的GUI和API，产生了标准ODBC。
<p>&nbsp;
<p>JDBC是一个通用的底层的、支持基本SQL功能的Java API。它提供了两部分与数据库独立的API，即JDBC API和JDBC Driver API。
<p>&nbsp;
<p>Java程序通过JDBC API访问JDBC Driver Manager，JDBC Driver Manager再通过JDBC Driver API 访问不同的JDBC驱动程序，从而实现对不同数据库的访问。说白了就是底层是数据库，上层是用户的访问请求，中间层包括各个数据库的各自的驱动程序、用户调用的API函数，只不过这里的API有两个子层，中间加入了一个JDBC Driver Manager来进行管理。整个链是这样的：DB--〉DB Driver--〉JDBC Driver API--〉JDBC Driver Manager--〉JDBC API--〉用户
<p>&nbsp;
<p>JDBC URL结构：
<p>jdbc:&lt;子协议&gt;:&lt;子名称&gt;
<p>例如：
<p>jdbc:odbc:test
<p>Tips:
<p>(1)
<p>如果通过网络来访问数据库，则将网络地址的放在子名称部分，格式为：//hostname:port/sub protocol
<p>例如：
<p>jdbc:dbnet://ant:356/fred
<p>(2)
<p>对于odbc子协议，比较特殊，可以在子名称后面接任意多个属性值的特征。因此odbc子协议的完整语法为：
<p>jdbc:odbc:&lt;数据源名称&gt;[;&lt;属性名&gt;=&lt;属性值&gt;;......]
<p>例如：
<p>jdbc:odbc:mydb;UID=bacoo;PWD=bacoo</p>
<img src ="http://www.blogjava.net/bacoo/aggbug/169194.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/bacoo/" target="_blank">bacoo</a> 2007-12-20 23:48 <a href="http://www.blogjava.net/bacoo/archive/2007/12/20/169194.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JDBC的那些事儿！（2）</title><link>http://www.blogjava.net/bacoo/archive/2007/12/20/169193.html</link><dc:creator>bacoo</dc:creator><author>bacoo</author><pubDate>Thu, 20 Dec 2007 15:47:00 GMT</pubDate><guid>http://www.blogjava.net/bacoo/archive/2007/12/20/169193.html</guid><wfw:comment>http://www.blogjava.net/bacoo/comments/169193.html</wfw:comment><comments>http://www.blogjava.net/bacoo/archive/2007/12/20/169193.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/bacoo/comments/commentRss/169193.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/bacoo/services/trackbacks/169193.html</trackback:ping><description><![CDATA[<h1>连接数据库</h1>
<p>所有与数据库有关的对象和方法都在 java.sql 包中，因此在使用 JDBC 的程序中必须加入 <tt>"import java.sql.* "</tt>。 JDBC 要连接 ODBC 数据库，您必须首先加载 JDBC-ODBC 桥驱动程序
<pre>Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");</pre>
<p>该语句加载驱动程序，并创建该类的一个实例。然后，要连接一个特定的数据库，您必须创建 Connect 类的一个实例，并使用 URL 语法连接数据库。
<pre>String url = "jdbc:odbc:Grocery prices";</pre>
<pre>Connection con = DriverManager.getConnection(url);</pre>
<p>请注意，您使用的数据库名是您在 ODBC 设置面板中输入的&#8220;数据源&#8221;名称。
<p>URL 语法可能因数据库类型的不同而变化极大。
<pre>jdbc:<em>subprotocol</em>:<em>subname</em></pre>
<p>第一组字符代表连接<em>协议</em>，并且始终是 <tt>jdbc</tt>。还可能有一个<em>子协议</em>，在此处，子协议被指定为 <tt>odbc</tt>。它规定了一类数据库的连通性机制。如果您要连接其它机器上的数据库服务器，可能也要指定该机器和一个子目录：
<pre>jdbc:bark//doggie/elliott</pre>
<p>最后，您可能要指定用户名和口令，作为连接字符串的一部分：
<pre>jdbc:bark//doggie/elliot;UID=GoodDog;PWD=woof</pre>
<pre>*******************************************************************************************</pre>
<pre>*******************************************************************************************</pre>
<p>上面给出了连接数据库的一种方法，其实还有另外一种方法，如下：
<p>System.setProperty("jdbc.drivers","sun.jdbc.odbc.JdbcOdbcDriver");
<p>String url = "jdbc:odbc:Grocery prices";
<p>Connection con=DriverManager.getConnection(url);
<p>说明：
<p>我们可以用System.getProperty("jdbc.drivers")对设定的System属性值进行查询。其实，对于System属性，系统认可的属性如下：
<p>java.version&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Java Runtime Environment version<br />
java.vendor&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Java Runtime Environment vendor<br />
java.vendor.url&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Java vendor URL<br />
java.home&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Java installation directory<br />
java.vm.specification.version&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Java Virtual Machine specification version<br />
java.vm.specification.vendor&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Java Virtual Machine specification vendor<br />
java.vm.specification.name&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Java Virtual Machine specification name<br />
java.vm.version&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Java Virtual Machine implementation version<br />
java.vm.vendor&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Java Virtual Machine implementation vendor<br />
java.vm.name&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Java Virtual Machine implementation name<br />
java.specification.version&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Java Runtime Environment specification version<br />
java.specification.vendor&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Java Runtime Environment specification vendor<br />
java.specification.name&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Java Runtime Environment specification name<br />
java.class.version&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Java class format version number<br />
java.class.path&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Java class path<br />
java.library.path&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; List of paths to search when loading libraries<br />
java.io.tmpdir&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Default temp file path<br />
java.compiler&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Name of JIT compiler to use<br />
java.ext.dirs&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Path of extension directory or directories<br />
os.name&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Operating system name<br />
os.arch&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Operating system architecture<br />
os.version&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Operating system version<br />
file.separator&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; File separator ("/" on UNIX)<br />
path.separator&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Path separator (":" on UNIX)<br />
line.separator&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Line separator ("\n" on UNIX)<br />
user.name&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; User's account name<br />
user.home&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; User's home directory<br />
user.dir&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; User's current working directory
<p>大家可以看到其中并没有jdbc.drivers这一个属性，但是System的属性可以随意的由我们来添加，比如我们用setProperty设定了一个名为&#8220;bacoo&#8221;的属性，并指定该属性值为&#8220;test&#8221;的话，那么当我们用getProperty时就可以检索到属性bacoo的值为test。这里之所以要加入&#8220;jdbc.drivers&#8221;这个属性值，是因为DriverManager这个类默认的会在初始化时去System中搜索这一属性的值，在这个属性值中我们可以将多个需要加载的驱动用冒号&#8220;:&#8221;隔开，又由于DriverManager是一个静态类（其实在定义一个类时，不允许用static修饰，只允许public、final、abstract三个修饰符，这里说其是静态类指的是该类的所有方法和属性&lt;其实该类也没有属性，连构造函数都没有&gt;均是静态的），因此在调用DriverManager.getConnection(url)时，DriverManager需要先初始化，就会加载驱动了。
<h1>访问数据库</h1>
<p>一旦连接到数据库，就可以请求表名以及表列的名称和内容等信息，而且您可以运行 SQL 语句来查询数据库或者添加或修改其内容。可用来从数据库中获取信息的对象有：
<h3><strong><u>DatabaseMetaData</u></strong></h3>
<p>有关整个数据库的信息：表名、表的索引、数据库产品的名称和版本、数据库支持的操作。
<p>DatabaseMetaData dbmd;
<p>dbmd=con.getMetaData();
<p>下面重点介绍一下DatabaseMetaDat中的两个重要函数getTables和getColumns：
<p><code><a href="http://bacoox.spaces.live.com/java/sql/ResultSet.html">ResultSet</a>&nbsp;</code><code><strong><a href="http://bacoox.spaces.live.com/java/sql/DatabaseMetaData.html#getTables(java.lang.String, java.lang.String, java.lang.String, java.lang.String[])"><font color="#ff0000">getTables</font></a></strong>(<a href="http://bacoox.spaces.live.com/java/lang/String.html">String</a> catalog, <a href="http://bacoox.spaces.live.com/java/lang/String.html">String</a> schemaPattern, <a href="http://bacoox.spaces.live.com/java/lang/String.html">String</a> tableNamePattern, <a href="http://bacoox.spaces.live.com/java/lang/String.html">String</a>[] types)</code>
<p>仅返回与目录、模式、表名称和（表）类型标准匹配的表描述。
<pre>catalog：要在其中查找表名的目录名。对于 JDBC-ODBC 数据库以及许多其他数据库而言，可将其设置为 <tt>null</tt>。这些数据库的目录项实际上是它在文件系统中的绝对路径名称。</pre>
<pre>schemaPattern：要包括的数据库&#8220;方案&#8221;。许多数据库不支持方案，而对另一些数据库而言，它代表数据库所有者的用户名。一般将它设置为 <tt>null</tt>。</pre>
<pre>tableNamePattern：一个掩码，用来描述您要检索的表的名称。如果您希望检索所有表名，则将其设为通配符 <tt>%</tt>。<em>请注意，</em><em>SQL 中的通配符是<strong> </strong><strong>%</strong> 符号，而不是一般 PC 用户的 * 符号。</em></pre>
<pre>types[]：这是描述您要检索的表的类型的 String 数组。数据库中通常包括许多用于内部处理的表，而对作为用户的您没什么价值。如果它是空值，则您会得到所有这些表。如果您将其设为包含字符串&#8220;<tt>TABLES</tt>&#8221;的单元素数组，您将仅获得对用户有用的表格。</pre>
<p><strong>例子：</strong>
<p>String [] types=new String[1];<br />
types[0]="TABLE";
<p>rs=dbmd.getTables(null, null, "%", types);
<p>Java Doc中说该函数返回的表描述信息都包括以下10种信息，TABLE_CAT、TABLE_SCHEM、TABLE_NAME、TABLE_TYPE、REMARKS、TYPE_CAT、TYPE_SCHEM、TYPE_NAME、SELF_REFERENCING_COL_NAME、REF_GENERATION，但是在实际测试时，返回的结果中只有TABLE_CAT、TABLE_SCHEM、TABLE_NAME、TABLE_TYPE、REMARKS这5项。顺便要说一声的是，变量types可以取的值有："TABLE"、"VIEW"、"SYSTEM TABLE"、"GLOBAL TEMPORARY"、"LOCAL TEMPORARY"、"ALIAS" 和 "SYNONYM"，通常只取TABLE。
<p>*************************************************************************************************************************************************************************************************
<p><code><a href="http://bacoox.spaces.live.com/java/sql/ResultSet.html">ResultSet</a>&nbsp;</code><code><strong><a href="http://bacoox.spaces.live.com/java/sql/DatabaseMetaData.html#getColumns(java.lang.String, java.lang.String, java.lang.String, java.lang.String)"><font color="#ff0000">getColumns</font></a></strong>(<a href="http://bacoox.spaces.live.com/java/lang/String.html">String</a> catalog, <a href="http://bacoox.spaces.live.com/java/lang/String.html">String</a> schemaPattern, <a href="http://bacoox.spaces.live.com/java/lang/String.html">String</a> tableNamePattern, <a href="http://bacoox.spaces.live.com/java/lang/String.html">String</a> columnNamePattern)</code>
<p>仅返回与目录、模式、表和列名称标准匹配的列描述。
<p>通常在得到有关指定表（比如我们这里指定了表名为FoodPrice）的列的描述信息的结果集（rs）之后，我们重点关心的是<strong>COLUMN_NAME</strong>、<strong>DATA_TYPE（数据类型占用的字节数，比如整型就是4）</strong>、<strong>TYPE_NAME（INTEGER、CURRENCY之类的类型名称），</strong>当然最关心的肯定是COLUMN_NAME了。下面把结果集中所有可以得到的信息列给出如下：
<p>TABLE_CAT、TABLE_SCHEM、TABLE_NAME、COLUMN_NAME、DATA_TYPE、TYPE_NAME、COLUMN_SIZE、BUFFER_LENGTH、DECIMAL_DIGITS、NUM_PREC_RADIX、NULLABLE、REMARKS、COLUMN_DEF、SQL_DATA_TYPE、SQL_DATETIME_SUB、CHAR_OCTET_LENGTH、ORDINAL_POSITION、IS_NULLABLE、ORDINAL。
<p>例子：
<p>rs=dbmd.getColumns(null, null, "FoodPrice", null);
<p>因此我们通常用
<p>while(rs.next()){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.print(rs.getString("COLUMN_NAME")+"\t");<br />
}来得到该表中所有的列名称。<strong>其实这就是一个从结果集中检索的结果</strong>。
<p>&nbsp;
<h3><strong><u>ResultSet</u></strong></h3>
<p>关于某个表的信息或一个查询的结果。您必须逐行访问数据行，但是您可以任何顺序访问列。
<p>对于数据库中表的描述信息的结果集可以这样得到：rs=dbmd.getTables(null, null, "%", null);
<p>对于某张表中的列的描述信息的结果集可以这样得到：rs=dbmd.getColumns(null, null, "FoodPrice", null);
<p>对于要从表中检索具体的符合要求的结果集（而不仅仅是一些描述信息了）就必须使用如下的方法：
<p>Statement st=con.createStatement();
<p>String query="SELECT FoodName FROM FOOD;";//注意字符串中要包含&#8220;;&#8221;！<br />
rs=st.executeQuery(query);
<p>&nbsp;
<h3><strong><u>ResultSetMetaData</u></strong></h3>
<p>有关 ResultSet 中列的名称和类型的信息。
<p>ResultSetMetaData rsmd;
<p>rsmd = rs.getMetaData();
<p>numCols = rsmd.getColumnCount();
<p>// 打印列名<br />
for (i = 1; i &lt;= numCols; i++)
<blockquote>
<p>System.out.print(rsmd.getColumnName(i) + "&nbsp;&nbsp;&nbsp;&nbsp; ");</p>
</blockquote>
<p>System.out.println();
<p>&nbsp;
<p>最后，给出一些零散的知识：
<p>（1）对于数据库的连接、访问等等操作都需要放在try和catch块中进行，都有可能抛出SQLException异常，使用该异常类需要import java.sql.*;
<p>（2）前面提到的DatabaseMetaDat、ResultSet、ResultSetMetaData均是接口，而不是类，在下面的例子中，通过跟踪调试，可以发现在程序运行过程中产生的都是基于JdbcOdbc驱动的类，即JdbcOdbcResultSet等类，把这些类（它们都实现了相应的接口）实例化后赋值给ResultSet接口，如ResultSet rs=dbmd.getColumns(null, null, "FoodPrice", null);因此，我们们不难推断出对于其他类型的数据库驱动，均是这样一个原理，同时也理解了为什么Java中有许多接口，而并没有与这些接口对应的实现了它们的类，再一次验证了接口就是一种标准，一种规范。
<p>给出一个完整的例子：
<p>package com.bacoo.www;
<p>import java.sql.*;<br />
public class JdbcOdbcTest {
<p>&nbsp;&nbsp;&nbsp; ResultSet rs;<br />
&nbsp;&nbsp;&nbsp; ResultSetMetaData rsmd;<br />
&nbsp;&nbsp;&nbsp; DatabaseMetaData dbmd;<br />
&nbsp;&nbsp;&nbsp; Connection con;<br />
&nbsp;&nbsp;&nbsp; int numCols,i;<br />
&nbsp;&nbsp;&nbsp; public JdbcOdbcTest(){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.setProperty("jdbc.drivers","sun.jdbc.odbc.JdbcOdbcDriver");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String url="jdbc:odbc:Groceries";<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String query="SELECT DISTINCTROW FoodName FROM Food " +<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "WHERE (FoodName like 'C%');";<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; con=DriverManager.getConnection(url);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dbmd=con.getMetaData();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("Connected to:"+dbmd.getURL());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("Driver "+ dbmd.getDriverName());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String [] types=new String[1];<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; types[0]="TABLE";<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rs=dbmd.getTables(null, null, "%", null);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dumpResults("--Tables--");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rs.close();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }catch(Exception e){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(e);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("--Column Names--");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rs=dbmd.getColumns(null, null, "FoodPrice", null);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while(rs.next()){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.print(rs.getString("COLUMN_NAME")+" ");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rs.close();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }catch(Exception e){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(e);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Statement st=con.createStatement();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rs=st.executeQuery("SELECT FoodName FROM FOOD;");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }catch(Exception e){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("query exception");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dumpResults("--contents of FoodName column--");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Statement st=con.createStatement();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rs=st.executeQuery(query);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }catch(Exception e){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("query exception");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dumpResults("--Results of Query--");<br />
&nbsp;&nbsp;&nbsp; }
<p>&nbsp;&nbsp;&nbsp; private void dumpResults(String head) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 这是打印列标头和每列的内容的<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 通用方法<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(head);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 从元数据中获取列数<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rsmd = rs.getMetaData();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; numCols = rsmd.getColumnCount();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 打印列名<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (i = 1; i &lt;= numCols; i++)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.print(rsmd.getColumnName(i) + "、");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 打印列内容<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (rs.next()) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (i = 1; i &lt;= numCols; i++)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.print(rs.getString(i) + "\t");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (Exception e) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(e.getMessage());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; }
<p>&nbsp;&nbsp;&nbsp; public static void main(String[] args) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // TODO Auto-generated method stub<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new JdbcOdbcTest();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(System.getProperty("jdbc.drivers"));<br />
&nbsp;&nbsp;&nbsp; }
<p>}
<p>&nbsp;
<p>运行的结果是：
<p>Connected to:jdbc:odbc:Groceries<br />
Driver JDBC-ODBC Bridge (odbcjt32.dll)<br />
--Tables--<br />
TABLE_CAT、TABLE_SCHEM、TABLE_NAME、TABLE_TYPE、REMARKS、<br />
C:\Documents and Settings\Administrator\桌面\db1&nbsp;&nbsp;&nbsp; null&nbsp;&nbsp;&nbsp; MSysAccessObjects&nbsp;&nbsp;&nbsp; SYSTEM TABLE&nbsp;&nbsp;&nbsp; null&nbsp;&nbsp;&nbsp; <br />
C:\Documents and Settings\Administrator\桌面\db1&nbsp;&nbsp;&nbsp; null&nbsp;&nbsp;&nbsp; MSysAccessXML&nbsp;&nbsp;&nbsp; SYSTEM TABLE&nbsp;&nbsp;&nbsp; null&nbsp;&nbsp;&nbsp; <br />
C:\Documents and Settings\Administrator\桌面\db1&nbsp;&nbsp;&nbsp; null&nbsp;&nbsp;&nbsp; MSysACEs&nbsp;&nbsp;&nbsp; SYSTEM TABLE&nbsp;&nbsp;&nbsp; null&nbsp;&nbsp;&nbsp; <br />
C:\Documents and Settings\Administrator\桌面\db1&nbsp;&nbsp;&nbsp; null&nbsp;&nbsp;&nbsp; MSysObjects&nbsp;&nbsp;&nbsp; SYSTEM TABLE&nbsp;&nbsp;&nbsp; null&nbsp;&nbsp;&nbsp; <br />
C:\Documents and Settings\Administrator\桌面\db1&nbsp;&nbsp;&nbsp; null&nbsp;&nbsp;&nbsp; MSysQueries&nbsp;&nbsp;&nbsp; SYSTEM TABLE&nbsp;&nbsp;&nbsp; null&nbsp;&nbsp;&nbsp; <br />
C:\Documents and Settings\Administrator\桌面\db1&nbsp;&nbsp;&nbsp; null&nbsp;&nbsp;&nbsp; MSysRelationships&nbsp;&nbsp;&nbsp; SYSTEM TABLE&nbsp;&nbsp;&nbsp; null&nbsp;&nbsp;&nbsp; <br />
C:\Documents and Settings\Administrator\桌面\db1&nbsp;&nbsp;&nbsp; null&nbsp;&nbsp;&nbsp; Food&nbsp;&nbsp;&nbsp; TABLE&nbsp;&nbsp;&nbsp; null&nbsp;&nbsp;&nbsp; <br />
C:\Documents and Settings\Administrator\桌面\db1&nbsp;&nbsp;&nbsp; null&nbsp;&nbsp;&nbsp; FoodPrice&nbsp;&nbsp;&nbsp; TABLE&nbsp;&nbsp;&nbsp; null&nbsp;&nbsp;&nbsp; <br />
C:\Documents and Settings\Administrator\桌面\db1&nbsp;&nbsp;&nbsp; null&nbsp;&nbsp;&nbsp; Stores&nbsp;&nbsp;&nbsp; TABLE&nbsp;&nbsp;&nbsp; null&nbsp;&nbsp;&nbsp; <br />
--Column Names--<br />
FSKey StoreKey FoodKey Price <br />
--contents of FoodName column--<br />
FoodName、<br />
Apples&nbsp;&nbsp;&nbsp; <br />
Oranges&nbsp;&nbsp;&nbsp; <br />
Hamburger&nbsp;&nbsp;&nbsp; <br />
Butter&nbsp;&nbsp;&nbsp; <br />
Milk&nbsp;&nbsp;&nbsp; <br />
Coca Cola&nbsp;&nbsp;&nbsp; <br />
Green beans&nbsp;&nbsp;&nbsp; <br />
--Results of Query--<br />
FoodName、<br />
Coca Cola&nbsp;&nbsp;&nbsp; <br />
sun.jdbc.odbc.JdbcOdbcDriver
<p>当然使用该例子，必须要先建立一个数据源。</p>
<img src ="http://www.blogjava.net/bacoo/aggbug/169193.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/bacoo/" target="_blank">bacoo</a> 2007-12-20 23:47 <a href="http://www.blogjava.net/bacoo/archive/2007/12/20/169193.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java系统属性</title><link>http://www.blogjava.net/bacoo/archive/2007/12/20/169191.html</link><dc:creator>bacoo</dc:creator><author>bacoo</author><pubDate>Thu, 20 Dec 2007 15:46:00 GMT</pubDate><guid>http://www.blogjava.net/bacoo/archive/2007/12/20/169191.html</guid><wfw:comment>http://www.blogjava.net/bacoo/comments/169191.html</wfw:comment><comments>http://www.blogjava.net/bacoo/archive/2007/12/20/169191.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/bacoo/comments/commentRss/169191.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/bacoo/services/trackbacks/169191.html</trackback:ping><description><![CDATA[<div>1.&nbsp;&nbsp;java.runtime.name:java的运行环境名称。 <br />
2.&nbsp;&nbsp;sun.boot.library.path:jdk\jre中的bin的路径 <br />
3.&nbsp;&nbsp;java.vm.version:虚拟机的版本号 <br />
4.&nbsp;&nbsp;java.vm.vendor:java虚拟机的发行者 <br />
5.&nbsp;&nbsp;java.vendor.url:java发行者的网络地址 <br />
6.&nbsp;&nbsp;path.separator:路径分隔符，常为&#8221;;&#8221; <br />
7.&nbsp;&nbsp;java.vm.name:虚拟机名字 <br />
8.&nbsp;&nbsp;file.encoding.pkg=&#8221;sun.io&#8221; <br />
9.&nbsp;&nbsp;sun.java.launcher:java的发行版本 <br />
10.&nbsp;&nbsp;user.country:用户的国家 <br />
11.&nbsp;&nbsp;sun.os.patch.level:操作系统的版本号 <br />
12.&nbsp;&nbsp;java.vm.specification.name:虚拟机的规则说明文档的名字 <br />
13.&nbsp;&nbsp;user.dir：用户路径（window 下为&#8221;c:\&#8221;） <br />
14.&nbsp;&nbsp;java.runtime.version:jdk的版本号 <br />
15.&nbsp;&nbsp;java.awt.graphicsenv:awt的图形环境（window下为：（&#8221;sun.awt.Win32GraphicsEnvironment&#8221;）） <br />
16.&nbsp;&nbsp;java.endorsed.dirs:java签注文件的路径 <br />
17.&nbsp;&nbsp;os.arch:操作系统支持的cpu型号 <br />
18.&nbsp;&nbsp;java.io.tmpdir:io操作的临时文件路径 <br />
19.&nbsp;&nbsp;line.separator:换行符 <br />
20.&nbsp;&nbsp;java.vm.specification.vendor:虚拟机规则说明文档的发行者 <br />
21.&nbsp;&nbsp;user.variant:用户变量 <br />
22.&nbsp;&nbsp;os.name:操作系统的名称 <br />
23.&nbsp;&nbsp;sun.jnu.encoding:&#8221;GBK&#8221; <br />
24.&nbsp;&nbsp;java.library.path:库的路径jdk\bin&#8230;&#8230;即path的内容 <br />
25.&nbsp;&nbsp;java.specification.name:java的规则说明文档的名称 <br />
26.&nbsp;&nbsp;java.class.version: <br />
27.&nbsp;&nbsp;sun.management.compiler:&#8221;HotSpot Client Compiler&#8221; <br />
28.&nbsp;&nbsp;os.version: <br />
29.&nbsp;&nbsp;user.home:用户文件的路径 <br />
30.&nbsp;&nbsp;user.timezon:时区 <br />
31.&nbsp;&nbsp;java.awt.printerjob:&#8221;sun.awt.windows.WprinterJob&#8221; <br />
32.&nbsp;&nbsp;file.encoding:文件编码&#8221;GBK&#8221; <br />
33.&nbsp;&nbsp;java.specification.version:java规则号 <br />
34.&nbsp;&nbsp;java.class.path:classpath <br />
35.&nbsp;&nbsp;user.name:用户名 <br />
36.&nbsp;&nbsp;java.vm.specificaton.version:虚拟机的版本 <br />
37.&nbsp;&nbsp;java.home:&#8221;C:\java\jdk\jre&#8221; <br />
38.&nbsp;&nbsp;sun.arch.data.model:cpu数据位数 <br />
39.&nbsp;&nbsp;user.language:&#8221;zh&#8221; <br />
40.&nbsp;&nbsp;java.specification.vendor:java的发行者 <br />
41.&nbsp;&nbsp;awt.toolkit:&#8221;sun.awt.windows.WToolkit&#8221; <br />
42.&nbsp;&nbsp;java.vm.info:&#8221;mixed mode, sharing&#8221; <br />
43.&nbsp;&nbsp;java.version:jdk版本 <br />
44.&nbsp;&nbsp;java.ext.dirs:ext的路径 <br />
45.&nbsp;&nbsp;sun.boot.class.path:类文件的path <br />
46.&nbsp;&nbsp;java.vendor：java的发行者 <br />
47.&nbsp;&nbsp;file.separator:文件分隔符 <br />
48.&nbsp;&nbsp;java.vendor.url.bug:java发行者的urlhttp://java.sun.com/cgi-bin/bugreport.cgi <br />
49.&nbsp;&nbsp;sun.io.unicode.encoding:&#8221;UnicodeLittle&#8221; <br />
50.&nbsp;&nbsp;sun.cpu.endian:&#8221;little&#8221; <br />
51.&nbsp;&nbsp;sun.desktop:&#8221;windows&#8221;,所在的环境 <br />
52.&nbsp;&nbsp;sun.cpu.isalist:&#8221;Pentium_pro+mmx Pentium_pro pentium+mmx Pentium i486 i386 i86&#8221;</div>
<div>&nbsp;</div>
<div>如果想自己测试一下本机器内的所有系统属性，可以使用如下的代码：</div>
<div>
<p>import java.util.Iterator;<br />
import java.util.Properties;
<p>public class sysEnv {<br />
&nbsp;<br />
&nbsp;public static void main(String args[])<br />
&nbsp;{<br />
&nbsp;&nbsp;Properties props=System.getProperties();<br />
&nbsp;&nbsp;Iterator iter=props.keySet().iterator();<br />
&nbsp;&nbsp;while(iter.hasNext())<br />
&nbsp;&nbsp;{<br />
&nbsp;&nbsp;String key=(String)iter.next();<br />
&nbsp;&nbsp;System.out.println(key+" = "+ props.get(key));<br />
&nbsp;&nbsp;}<br />
&nbsp;}<br />
}<br />
</p>
</div>
<img src ="http://www.blogjava.net/bacoo/aggbug/169191.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/bacoo/" target="_blank">bacoo</a> 2007-12-20 23:46 <a href="http://www.blogjava.net/bacoo/archive/2007/12/20/169191.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转载]J2DK 1.5、1.6 &amp; 中文版API（全）</title><link>http://www.blogjava.net/bacoo/archive/2007/12/20/169188.html</link><dc:creator>bacoo</dc:creator><author>bacoo</author><pubDate>Thu, 20 Dec 2007 15:45:00 GMT</pubDate><guid>http://www.blogjava.net/bacoo/archive/2007/12/20/169188.html</guid><wfw:comment>http://www.blogjava.net/bacoo/comments/169188.html</wfw:comment><comments>http://www.blogjava.net/bacoo/archive/2007/12/20/169188.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/bacoo/comments/commentRss/169188.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/bacoo/services/trackbacks/169188.html</trackback:ping><description><![CDATA[<div>
<div>&nbsp;<a href="http://lavasoft.blog.51cto.com/"><u><font color="#0000ff">leizhimin 51cto技术博客</font></u></a></div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <font color="#008000">Sun 公司提供的Java API Docs是学习和使用Java语言中最经常使用的参考资料之一。但是长期以来此文档只有英文版，对于中国地区的Java开发者来说相当的不便。目前Sun 公司正在组织多方力量将此文档翻译成中文，并于2005年10月31日在Sun 中国技术社区（<a href="http://gceclub.sun.com.cn/" target="_blank"><u><font color="#800080">http://gceclub.sun.com.cn/</font></u></a>） 正式发布第一批中文版Java API文档（包括java.lang和java.util类库API 文档的中文版）。经过将近10个月的努力，目前我们已经将Java SE 5.0的全部API文档中文化。开发人员可以通过Sun 中国技术社区的网站在线浏览相关文档，也可以将全部文档下载到本地以方便检索和使用。</font><a href="http://lavasoft.blog.51cto.com/"><u><font color="#0000ff">leizhimin 51cto技术博客</font></u></a></div>
<div>&nbsp;<a href="http://lavasoft.blog.51cto.com/"><u><font color="#0000ff">leizhimin 51cto技术博客</font></u></a></div>
<div><font size="2"><font color="#ff1493"><strong><font color="#0000ff">J2SE DK &amp; API下载</font></strong><br />
</font>-------------------------<br />
<a href="http://java.sun.com/j2se/1.3/download.html" target="_blank"><font color="#0000ff"><u>http://java.sun.com/j2se/1.3/download.html</u></font></a><br />
<a href="http://java.sun.com/j2se/1.4.2/download.html" target="_blank"><font color="#0000ff"><u>http://java.sun.com/j2se/1.4.2/download.html</u></font></a><br />
<a href="http://java.sun.com/javase/downloads/index_jdk5.jsp" target="_blank"><font color="#0000ff"><u>http://java.sun.com/javase/downloads/index_jdk5.jsp</u></font></a><br />
<a href="http://java.sun.com/javase/downloads/index.jsp" target="_blank"><font color="#0000ff"><u>http://java.sun.com/javase/downloads/index.jsp</u></font></a></font><a href="http://lavasoft.blog.51cto.com/"><u><font color="#0000ff">leizhimin 51cto技术博客</font></u></a></div>
<div>&nbsp;<a href="http://lavasoft.blog.51cto.com/"><u><font color="#0000ff">leizhimin 51cto技术博客</font></u></a></div>
<div><font size="2"><strong><font color="#0000ff">J2EE DK &amp; API下载</font></strong>&nbsp; <br />
-------------------------<br />
<a href="http://java.sun.com/j2ee/1.3/index.jsp" target="_blank"><font color="#0000ff"><u>http://java.sun.com/j2ee/1.3/index.jsp</u></font></a><br />
<a href="http://java.sun.com/j2ee/1.3/download.html" target="_blank"><font color="#0000ff"><u>http://java.sun.com/j2ee/1.3/download.html</u></font></a><br />
<a href="http://java.sun.com/j2ee/1.4/index.jsp" target="_blank"><font color="#0000ff"><u>http://java.sun.com/j2ee/1.4/index.jsp</u></font></a><br />
<a href="http://java.sun.com/j2ee/1.4/download.html" target="_blank"><font color="#0000ff"><u>http://java.sun.com/j2ee/1.4/download.html</u></font></a><br />
<a href="http://java.sun.com/javaee/downloads/index.jsp" target="_blank"><font color="#0000ff"><u>http://java.sun.com/javaee/downloads/index.jsp</u></font></a></font><a href="http://lavasoft.blog.51cto.com/"><u><font color="#0000ff">leizhimin 51cto技术博客</font></u></a></div>
<div>&nbsp;<a href="http://lavasoft.blog.51cto.com/"><u><font color="#0000ff">leizhimin 51cto技术博客</font></u></a></div>
<div><font size="2"><strong><font color="#0000ff">JDK1.6API中文版（全）</font></strong><br />
-------------------------<br />
* HTML 格式(在线英文) <a href="http://java.sun.com/javase/6/docs/" target="_blank"><u><font color="#0000ff">http://java.sun.com/javase/6/docs/</font></u></a><br />
* HTML 格式(在线中文) <a href="http://download.java.net/jdk/jdk-api-localizations/jdk-api-zh-cn/publish/1.6.0/html/zh_CN/api/index.html" target="_blank"><u><font color="#800080">http://download.java.net/jdk/jdk-api-localizations/jdk-api-zh-cn/publish/1.6.0/html/zh_CN/api/index.html</font></u></a><br />
* zip 格式(中文) <a href="http://download.java.net/jdk/jdk-api-localizations/jdk-api-zh-cn/publish/1.6.0/html_zh_CN.zip" target="_blank"><u><font color="#800080">http://download.java.net/jdk/jdk-api-localizations/jdk-api-zh-cn/publish/1.6.0/html_zh_CN.zip</font></u></a><br />
* CHM 格式(中文)&nbsp; <a href="http://download.java.net/jdk/jdk-api-localizations/jdk-api-zh-cn/publish/1.6.0/chm/JDK_API_1_6_zh_CN.CHM" target="_blank"><font color="#0000ff"><u>http://download.java.net/jdk/jdk-api-localizations/jdk-api-zh-cn/publish/1.6.0/chm/JDK_API_1_6_zh_CN.CHM</u></font></a><br />
</font><a href="http://lavasoft.blog.51cto.com/"><u><font color="#0000ff">leizhimin 51cto技术博客</font></u></a></div>
<div><font size="2"><strong></strong></font>&nbsp;<a href="http://lavasoft.blog.51cto.com/"><u><font color="#0000ff">leizhimin 51cto技术博客</font></u></a></div>
<div><font size="2"><strong><font color="#0000ff">JDK1.5API中文版（全）</font></strong><br />
-------------------------<br />
* HTML 格式(在线英文) <a href="http://java.sun.com/javase/5/docs/" target="_blank"><u><font color="#0000ff">http://java.sun.com/javase/5/docs/</font></u></a><br />
* HTML 格式(在线中文)&nbsp; <a href="http://gceclub.sun.com.cn/Java_Docs/html/zh_CN/api/index.html" target="_blank"><u><font color="#800080">http://gceclub.sun.com.cn/Java_Docs/html/zh_CN/api/index.html</font></u></a><br />
* zip 格式(中文) <a href="http://gceclub.sun.com.cn/Java_Docs/html_zh_CN.zip" target="_blank"><u><font color="#0000ff">http://gceclub.sun.com.cn/Java_Docs/html_zh_CN.zip</font></u></a><br />
* CHM 格式(中文) <a href="http://download.java.net/jdk/jdk-api-localizations/jdk-api-zh-cn/builds/JDK_API_1_5_zh_CN.CHM" target="_blank"><font color="#0000ff"><u>http://download.java.net/jdk/jdk-api-localizations/jdk-api-zh-cn/builds/JDK_API_1_5_zh_CN.CHM</u></font></a><br />
</font><a href="http://lavasoft.blog.51cto.com/"><u><font color="#0000ff">leizhimin 51cto技术博客</font></u></a></div>
<div>&nbsp;<a href="http://lavasoft.blog.51cto.com/"><u><font color="#0000ff">leizhimin 51cto技术博客</font></u></a></div>
<div><font size="2"><strong><font color="#0000ff">相关网站<br />
</font></strong>-------------------------<br />
<a href="http://java.sun.com/" target="_blank"><font color="#0000ff"><u>http://java.sun.com</u></font></a><br />
<a href="http://gceclub.sun.com.cn/" target="_blank"><u><font color="#0000ff">http://gceclub.sun.com.cn/</font></u></a><br />
<a href="http://developers.sun.com/downloads/" target="_blank"><font color="#0000ff"><u>http://developers.sun.com/downloads/</u></font></a><br />
<a href="http://java.sun.com/javaee/downloads/" target="_blank"><font color="#0000ff"><u>http://java.sun.com/javaee/downloads/</u></font></a><br />
<a href="http://java.sun.com/javase/downloads/" target="_blank"><font color="#0000ff"><u>http://java.sun.com/javase/downloads/</u></font></a><br />
<a href="http://www.netbeans.info/downloads/" target="_blank"><font color="#0000ff"><u>http://www.netbeans.info/downloads/</u></font></a></font></div>
<div><font size="2"><a href="http://java.sun.com/docs/books/tutorial/index.html"><u><font color="#0000ff">http://java.sun.com/docs/books/tutorial/index.html</font></u></a><br />
</font><a href="http://lavasoft.blog.51cto.com/"><u><font color="#0000ff">leizhimin 51cto技术博客</font></u></a></div>
</div>
<img src ="http://www.blogjava.net/bacoo/aggbug/169188.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/bacoo/" target="_blank">bacoo</a> 2007-12-20 23:45 <a href="http://www.blogjava.net/bacoo/archive/2007/12/20/169188.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java中窗体的创建！</title><link>http://www.blogjava.net/bacoo/archive/2007/12/20/169190.html</link><dc:creator>bacoo</dc:creator><author>bacoo</author><pubDate>Thu, 20 Dec 2007 15:45:00 GMT</pubDate><guid>http://www.blogjava.net/bacoo/archive/2007/12/20/169190.html</guid><wfw:comment>http://www.blogjava.net/bacoo/comments/169190.html</wfw:comment><comments>http://www.blogjava.net/bacoo/archive/2007/12/20/169190.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/bacoo/comments/commentRss/169190.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/bacoo/services/trackbacks/169190.html</trackback:ping><description><![CDATA[<div>一般来讲，在java中要完成一个Frame或者JFrame的显示，需要以下步骤，通常都将主类(定义为public的类)继承于Frame或者JPanel。<br />
（一）如果是继承自Frame，则：<br />
设置标题：setTitle("Your Title");<br />
设置大小：setSize(int width,int height)或者pack()<br />
使窗口显示：setVisible(true)<br />
使窗口居中显示：setLocationRelativeTo(null)<br />
使窗口的关闭动作有效：<br />
addWindowListener(new WindowAdapter(){<br />
public void windowClosing(WindowEvent e){<br />
System.exit(0);<br />
}<br />
});<br />
（二）如果是继承自JPanel，则：<br />
设置标题：setTitle("Your Title");<br />
设置外观：JFrame.setDefaultLookAndFeelDecorated(true);</div>
<div>得到内容面板的内容：JComponent jc=new 主类名();</div>
<div>设置内容不透明：jc.setOpaque(true);<br />
设置内容面板：setContentPane(jc);<br />
设置大小：setSize(int width,int height)或者pack()<br />
使窗口显示：setVisible(true)<br />
使窗口居中显示：setLocationRelativeTo(null)<br />
使窗口的关闭动作有效：setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE)；</div>
<div>此外，还有另外一个设置窗口大小的函数是setPreferredSize(new Dimension(int width,int height))，但是调用该函数后必须再调用pack()函数才行。而且，该函数比setSize函数的优先级高，如果同时设置了setPreferredSize和setSize两个函数，那么setSize函数将不发挥作用。</div>
<img src ="http://www.blogjava.net/bacoo/aggbug/169190.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/bacoo/" target="_blank">bacoo</a> 2007-12-20 23:45 <a href="http://www.blogjava.net/bacoo/archive/2007/12/20/169190.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>使用JTabbedPane遇到的问题！</title><link>http://www.blogjava.net/bacoo/archive/2007/12/20/169187.html</link><dc:creator>bacoo</dc:creator><author>bacoo</author><pubDate>Thu, 20 Dec 2007 15:44:00 GMT</pubDate><guid>http://www.blogjava.net/bacoo/archive/2007/12/20/169187.html</guid><wfw:comment>http://www.blogjava.net/bacoo/comments/169187.html</wfw:comment><comments>http://www.blogjava.net/bacoo/archive/2007/12/20/169187.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/bacoo/comments/commentRss/169187.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/bacoo/services/trackbacks/169187.html</trackback:ping><description><![CDATA[<p>对于JTabbedPane，其实用起来很简单，<br />
1。创建<br />
2。调用addTab(String title, Component component)//这里的component一般是用JPanel<br />
但是在同一个容器中，不允许把同一个panel放在JTabbedPane中后再接着add到容器中来，比如我们在JTabbedPane中放置了panel1和panel2，然后又把panel1添加到容器中了，则实际显示的效果为JTabbedPane中只有panel2一个属性页，因为panel1已经在容器中了，这一点容易被忽略，请注意。<br />
</p>
<p>其实，不光是JTabbedPane有这种问题，任何一个组件都不能在同一个容器（或面板）中被加载两次，不论以何种方式。</p>
<img src ="http://www.blogjava.net/bacoo/aggbug/169187.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/bacoo/" target="_blank">bacoo</a> 2007-12-20 23:44 <a href="http://www.blogjava.net/bacoo/archive/2007/12/20/169187.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JScrollPane的简单用法！</title><link>http://www.blogjava.net/bacoo/archive/2007/12/20/169186.html</link><dc:creator>bacoo</dc:creator><author>bacoo</author><pubDate>Thu, 20 Dec 2007 15:42:00 GMT</pubDate><guid>http://www.blogjava.net/bacoo/archive/2007/12/20/169186.html</guid><wfw:comment>http://www.blogjava.net/bacoo/comments/169186.html</wfw:comment><comments>http://www.blogjava.net/bacoo/archive/2007/12/20/169186.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/bacoo/comments/commentRss/169186.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/bacoo/services/trackbacks/169186.html</trackback:ping><description><![CDATA[<div>1。定义实例：JScrollPane jsp=new JScrollPane(某个继承自JPanel类的实例 pane);<br />
2。设置初始大小：jsp.setPreferredSize(new Dimension(200,200));<br />
3。在适当的时候（已经判断出jsp容纳不下里面的内容时）重新设置大小：jsp.setPreferredSize(一个新的Dimension);<br />
4。调用jsp.revalidate();<br />
5。调用jsp.repaint();<br />
Tips:<br />
有一个JScrollPane的成员函数是scrollRectToVisible(Rectangle rect)；该成员函数能够使某一块rect在当前的滚动面板内可见，即滚动面板能够通过滚动来使得需要显示的区域（由rect界定出的那块区域）被显示。</div>
<img src ="http://www.blogjava.net/bacoo/aggbug/169186.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/bacoo/" target="_blank">bacoo</a> 2007-12-20 23:42 <a href="http://www.blogjava.net/bacoo/archive/2007/12/20/169186.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转载]Java批注的发明起因及代码应用实例</title><link>http://www.blogjava.net/bacoo/archive/2007/12/20/169185.html</link><dc:creator>bacoo</dc:creator><author>bacoo</author><pubDate>Thu, 20 Dec 2007 15:39:00 GMT</pubDate><guid>http://www.blogjava.net/bacoo/archive/2007/12/20/169185.html</guid><wfw:comment>http://www.blogjava.net/bacoo/comments/169185.html</wfw:comment><comments>http://www.blogjava.net/bacoo/archive/2007/12/20/169185.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/bacoo/comments/commentRss/169185.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/bacoo/services/trackbacks/169185.html</trackback:ping><description><![CDATA[&nbsp;
<div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 批注能够消除样板代码，让源代码的可读性更高，并能提供级别更高的错误检查。从EJB3到JUnit4，哪里都在使用它。本文就将告诉你如何使用它。<br />
　　Java 5向Java引入了批注(Annotations)，它的使用迅速成为现代Java开发中不可缺少的一部分。在正式开始介绍它之前，看看为什么要发明批注，这是非常值得的。<br />
　　自从Java诞生之日起，人们就一直在解决它初期忽视了的一些问题：缺少元数据；缺乏将Java以外的代码嵌入到Java源代码文件里的能力等。当 Java面市的时候，针对这些问题而推出的JavaDoc终于让它变完整了。JavaDoc使用了在代码里专门标记注释的概念，从而让它能够提取出额外的信息，说具体点就是文档，并将它转换成为我们熟悉的JavaDoc文档。这是一项简单的技术，人人都可以使用。首先会有Doclet，目的是让人们扩展文档的输出。然后是Xdoclet，它像使用标记一样使用JavaDoc来生成代码，从而将整个过程变得轻而易举。这部分是对J2EE的复杂性的回应。 J2EE原来依靠很多样板代码(boilerplate code)把对象捆绑到J2EE框架里。但是这些方案都有一些问题。首先，注释里的标记从来都不会进入最终的源代码，所以除非你生成代码来反映这些标记，否则你无法在运行期间查找到它。其次，它会把整个预处理层加到(在理想情况下应该是)一个简单编译过程里。最后，基于注释的标记在编译期间并不是很容易检查，也无法轻易被很多IDE检查；如果你把注释标记拼写错了，编译器是不会注意到的，编译器只会关注那些它知道确切名字的标记。<br />
　　要解决这所有的问题，Java新增了批注。批注是用于Java语言的本机元数据标记。它们的输入严格与Java语言的其他部分类似，可以通过反映被发现，更容易地让 IDE和编译器的编写者管理。现在就让我们看一些被批注的代码吧；我们先从BaseExample开始，它是一个简单类，只带有一个方法—— myMethod：</div>
<div><br />
　　public class BaseExample {<br />
<br />
　　public BaseExample() {} <br />
<br />
　　public void myMethod() { <br />
<br />
　　System.out.println("This is the BaseExample"); <br />
<br />
　　} <br />
<br />
　　} <br />
<br />
　　现在，我们想要扩展BaseExample并替代myMethod。下面就是完成这一任务的Example1代码：<br />
<br />
　　public class Example1 extends BaseExample {<br />
<br />
　　public Example1() {} <br />
<br />
　　@Overridepublic void myMethod() {<br />
<br />
　　System.out.println("This is the Example1");<br />
<br />
　　}<br />
<br />
　　} <br />
<br />
　　这样我们就有了第一个关于myMethod的批注<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#8212;&#8212;&#64;&#79;&#118;&#101;&#114;&#114;&#105;&#100;&#101;"><u><font color="#0000ff">——@Override</font></u></a>。这是一系列内置的批注之一。@Override的意思是&#8220;方法必须替代其超类中的一个方法；如果做不到这一点，那么就会有东西出错，使得编译器产生错误&#8221;。没有@Override，代码照样会正常工作，但是假设有人修改BaseExample，让myMethod带有参数。如果你没有使用@Override批注，代码仍然会被编译，隐藏了子类没有替代超类方法的问题。如果有@Override的话，你会在编译期间看到发生错误。<br />
　　你可能会认为&#8220;难道语言的扩展没有解决这个问题，额外的关键字可能会吗&#8221;，是的，它可能已经实现了这一点，但是这不仅没有给语言带来任何灵活性，还会导致很多源代码兼容性的问题。批注这种方式避免了改变Java语言本身(当然除了增加了@markup)，并且还能够放在代码的不同部分里，而不仅仅是在标记方法里。<br />
　　关于批注还有一点是，你可以创建自己的批注标记，这正是我们马上要讨论的内容。想一想下面这个问题：我们有一些简单的Java Beans程序，它们都带有不同的字符串字段。我们希望能够有一些通用窗体显示代码，它们能够用其他显示提示(比如宽度)来正确地标示这些字段。现在我们可以编写一个超类，它能够提取出这个数据，比如说从一个在每个类里都带有一些静态支持方法的静态数组里，但是这也意味着要强制给代码分层。利用批注做到这一点就要简单得多了。现在让我们从定义FormLabel.java里的FormLabel的批注开始：<br />
<br />
　　import java.lang.annotation.*; <br />
<br />
　　@Retention(RetentionPolicy.RUNTIME)<br />
<br />
　　@Target(ElementType.METHOD)<br />
<br />
　　public@interface FormLabel {String label();<br />
<br />
　　int width() default 40;<br />
<br />
　　} <br />
<br />
　　你应该注意到的第一件事是Java使用了它自己内置的一些批注来定批注：@Retention和@Target。@Retention用来定义通过设置 RetentionPolicy的值批注能够在构建-运行过程中存留多久。这里我们使用了RUNTIME，这意味着我们定义的批注将会在运行期间被保留在代码里。RetentionPolicy.SOURCE将被用于一个我们希望被编译器使用然后抛弃的批注。RetentionPolicy.CLASS让它们保留在生成的类文件里，但是能够在运行期间被Java虚拟机(JVM)访问到。<br />
　　在默认情况下，你可以在代码里的任何地方都应用批注。 @Target批注让你能够将它限制在代码的特定部分里。在本文里，我们把目标瞄准了ElementType.METHOD，这意味着它只能够与方法关联在一起。其他ElementTypes有CONSTRUCTOR、FIELD、LOCAL_VARIABLE、PACKAGE、PARAMETER和 TYPE，每个都能够把批注限制到该种类型的Java语言元素，所以例如，设置TYPE将只允许批注为定义过的这种类型，比如：<br />
<br />
　　@OurAnnotation<br />
<br />
　　public class OurAnnotatedClass {&#8230; <br />
<br />
　　值得注意的是，@Target批注能够接受单个ElementType或者一个ElementType数组，如果你想要将批注限制为一系列语言元素的话。<br />
　　下面一部分是批注接口的定义；这就像是一个普通的接口声明，除了我们用@interface将其标记为一个批注。在这个接口里，我们然后定义批注的方法，就像我们希望用在与批注相关联的信息上的抽象方法，所以我们就有了String label()，用于一个叫做label的字符串属性。如果我们没有方法，那么批注就只能用于&#8220;做标记&#8221;，而@Overrides注释就是这样一个例子。如果你只有一个属性，它最好被命名为&#8220;value&#8221;，因为当带有一个未命名参数的批注在设置这个值时，它工作得最好。属性还可以有默认值，比如&#8220;int width() default 40;&#8221;就是在定义一个默认值为40的整数属性。<br />
　　这就是批注定义。我们现在就可以在代码里使用它了。下面一个SimpleData类就用到了它。<br />
<br />
　　public class SimpleData { <br />
<br />
　　private String firstname;<br />
<br />
　　private String lastname;<br />
<br />
　　private String postcode; <br />
<br />
　　public SimpleData() {} <br />
<br />
　　@FormLabel(label="First Name")<br />
<br />
　　public String getFirstname() { return firstname; } <br />
<br />
　　public void<br />
<br />
　　setFirstname(String firstname) {this.firstname = firstname;} <br />
<br />
　　@FormLabel(label="Last Name",width=80)<br />
<br />
　　public String getLastname() { return lastname; }<br />
<br />
　　public void setLastname(String lastname) {<br />
<br />
　　this.lastname = lastname;<br />
<br />
　　} <br />
<br />
　　@FormLabel(label="Postal code",width=10)<br />
<br />
　　public String getPostcode() { return postcode; } <br />
<br />
　　public void setPostcode(String postcode) {<br />
<br />
　　this.postcode = postcode;<br />
<br />
　　}<br />
<br />
　　} <br />
<br />
　　当然，如果我们不查找批注，那么它们对代码的执行就不会造成任何不同。我们所需要的是在运行期间使用批注的方式；我们通过Reflection API来达到这一目的。现在就让我们创建一个简单的processForm方法，它能够在任何对象里查找批注。<br />
<br />
　　public void processForm(Object o) {<br />
<br />
　　for(Method m:o.getClass().getMethods()) { <br />
<br />
　　我们将在传递给方法的对象的类里定义所有的方法。现在，我们需要检查每个方法，看看它们是否有FormLabel批注，以及是否返回一个String(为了简单地说明问题，我们给所有的结果多返回一些代码)：<br />
<br />
　　if(m.isAnnotationPresent(FormLabel.class) &amp;&amp;<br />
<br />
　　m.getReturnType()==String.class) { <br />
<br />
　　现在我们可以通过使用Method的getAnnotation()方法来提取FormLabel批注：<br />
<br />
　　FormLabel formLabel=<br />
<br />
　　m.getAnnotation(FormLabel.class); <br />
<br />
　　现在我们执行方法来取得其字符串值，并通过在批注接口里定义的方法访问批注属性。下面我们就把它们打印出来：<br />
<br />
　　try {<br />
<br />
　　String value=(String)m.invoke(o);<br />
<br />
　　String label=formLabel.label();<br />
<br />
　　int width=formLabel.width(); <br />
<br />
　　System.out.printf("%s[%d]:%s\n",label,width,value);<br />
<br />
　　} catch (IllegalArgumentException ex) {<br />
<br />
　　ex.printStackTrace();<br />
<br />
　　}<br />
<br />
　　catch (IllegalAccessException ex) {<br />
<br />
　　ex.printStackTrace();}<br />
<br />
　　catch (InvocationTargetException ex) {<br />
<br />
　　ex.printStackTrace();<br />
<br />
　　}<br />
<br />
　　}<br />
<br />
　　}<br />
<br />
　　} <br />
<br />
　　现在我们可以创建含有@FormLabel批注的新类，并把它们传递给processForm方法。这是在运行期间访问你自己的批注的基础。<br />
　　现在这个时候，我们回头看看Java 5里面其他关于批注的内容。首先是编译器指令——@Deprecated和<a></a><strong style="color: black; background-color: rgb(255,255,102)">@SuppressWarnings</strong>。@Deprecated是把方法标示为被否定的增强方法；不推荐把它用在新代码里，以防止以后删除。用@Deprecated可以生成一个来自编译器的相关警告。<br />
<br />
　　<strong style="color: black; background-color: rgb(255,255,102)">@SuppressWarnings</strong>会阻止编译器在封闭代码元素里警告你，所以你可以在类定义的开始或者对特定的方法使用<strong style="color: black; background-color: rgb(255,255,102)">@SuppressWarnings</strong>。它可以带参数，用来指定需要取消的错误的类型，例如：<br />
<br />
　　<strong style="color: black; background-color: rgb(255,255,102)">@SuppressWarnings</strong>("unchecked")<br />
<br />
　　public List getList() {<br />
<br />
　　List l=new LinkedList();<br />
<br />
　　return l;<br />
<br />
　　} <br />
<br />
　　这里我们取消了一个关于在List和List之间的&#8220;未检查&#8221;的强制转换。当你开始用Java编程但是没有非一般代码的时候，这就非常有用。在取消警告的时候，尽可能地缩小取消的范围是值得的；在上面的例子里，我们取消了整个代码。我们可以把它变紧凑，只隐藏一个语句的错误：<br />
<br />
　　public List <br />
<br />
　　getListToo() { <br />
<br />
　　<strong style="color: black; background-color: rgb(255,255,102)">@SuppressWarnings</strong>("unchecked")<br />
<br />
　　List l=new LinkedList(); <br />
<br />
　　return l; <br />
<br />
　　} <br />
<br />
　　要注意的是，你需要在Java2SE 1.5.06或者以上的版本上进行这项工作；这之前的版本没有提供对@SuppressWarning支持。<br />
　　Java 5里其他内置的批注都与对批注的支持有关<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#8212;&#8212;&#64;&#68;&#111;&#99;&#117;&#109;&#101;&#110;&#116;&#101;&#100;"><font color="#000000">——@Documented</font></a>和@Inherited。它们都可以被加到批注定义里。@Documented的作用是，批注的使用应该在所有生成的JavaDoc文档里都反映出来。正如你可能看到的，批注和JavaDoc标记是互补的。@Inherited的意思是，当另外一个类用类来扩展批注时，批注应该是可继承的；在默认情况下，批注是不能被继承的。<br />
<br />
　　你可能很希望在自己的开发项目里使用Java批注的方法。就像我在引言里讲到的，批注已经成为现代Java框架和应用程序的重要一部分；就拿 JUnit4举个例子，Java批注已经允许JUnit的开发人员有了以更丰富的方式表示测试的方法，而不用要求测试编写者强制使用统一的命名规则。还有 Grails，这里批注可以被用来向&#8220;类似铁轨(rails-like)&#8221;的框架提供信息。批注的能力有很多，但是要记住，能力越大，责任也越大。批注是为了给开发人员提供标记信息，而不是用来隐藏运行配置。</div>
<div><font color="#ff0000"></font>&nbsp;</div>
<div><font color="#ff0000">完整的Java代码例子：</font></div>
<div><font color="#ff0000"></font>&nbsp;</div>
<div>package com.shou.www;</div>
<div>import java.lang.annotation.ElementType;<br />
import java.lang.annotation.Retention;<br />
import java.lang.annotation.RetentionPolicy;<br />
import java.lang.annotation.Target;<br />
import java.lang.reflect.InvocationTargetException;<br />
import java.lang.reflect.Method;</div>
<div>@Retention(RetentionPolicy.RUNTIME)<br />
@Target(ElementType.METHOD)<br />
@interface FormLabel {<br />
&nbsp;String label();<br />
&nbsp;int width() default 40;<br />
}</div>
<div>public class AnnotationDemo {</div>
<div>&nbsp;private String firstname="Zhao";<br />
&nbsp;private String lastname="Bacoo";<br />
&nbsp;private String postcode="116023";</div>
<div>&nbsp;public AnnotationDemo() {<br />
&nbsp;}</div>
<div>&nbsp;@FormLabel(label = "First Name")<br />
&nbsp;public String getFirstname() {<br />
&nbsp;&nbsp;return firstname;<br />
&nbsp;}</div>
<div>&nbsp;public void&nbsp;setFirstname(String firstname) {<br />
&nbsp;&nbsp;this.firstname = firstname;<br />
&nbsp;}</div>
<div>&nbsp;@FormLabel(label = "Last Name", width = 80)<br />
&nbsp;public String getLastname() {<br />
&nbsp;&nbsp;return lastname;<br />
&nbsp;}</div>
<div>&nbsp;public void setLastname(String lastname) {<br />
&nbsp;&nbsp;this.lastname = lastname;<br />
&nbsp;}</div>
<div>&nbsp;@FormLabel(label = "Postal code", width = 10)<br />
&nbsp;public String getPostcode() {<br />
&nbsp;&nbsp;return postcode;<br />
&nbsp;}</div>
<div>&nbsp;public void setPostcode(String postcode) {<br />
&nbsp;&nbsp;this.postcode = postcode;<br />
&nbsp;}</div>
<div>&nbsp;public void processForm(Object o) {<br />
&nbsp;&nbsp;for (Method m : o.getClass().getMethods()) {<br />
&nbsp;&nbsp;&nbsp;if (m.isAnnotationPresent(FormLabel.class) &amp;&amp;<br />
&nbsp;&nbsp;&nbsp;m.getReturnType() == String.class) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;FormLabel formLabel = m.getAnnotation(FormLabel.class);<br />
&nbsp;&nbsp;&nbsp;&nbsp;try {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String value = (String) m.invoke(o);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String label = formLabel.label();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int width = formLabel.width();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.printf("%s[%d]:%s\n", label, width, value);<br />
&nbsp;&nbsp;&nbsp;&nbsp;} catch (IllegalArgumentException ex) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ex.printStackTrace();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;catch (IllegalAccessException ex) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ex.printStackTrace();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;catch (InvocationTargetException ex) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ex.printStackTrace();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;}<br />
&nbsp;}</div>
<div>&nbsp;public static void main(String[] args) {<br />
&nbsp;&nbsp;// TODO Auto-generated method stub<br />
&nbsp;&nbsp;AnnotationDemo ad=new AnnotationDemo();<br />
&nbsp;&nbsp;ad.processForm(ad);<br />
&nbsp;}<br />
&nbsp;<br />
}<br />
//程序运行的结果如下：<br />
//First Name[40]:Zhao<br />
//Last Name[80]:Bacoo<br />
//Postal code[10]:116023</div>
<div>最后，在IBM的网站上还有翻译过来的两篇不错的关于java注释方面的讲解，但是那两篇文章比较基本，不如上面这篇文章这样经典和深刻，有兴趣的读者可以参考：<br />
<a href="http://www.ibm.com/developerworks/cn/java/j-annotate1/">http://www.ibm.com/developerworks/cn/java/j-annotate1/</a><br />
<a href="http://www.ibm.com/developerworks/cn/java/j-annotate2.html">http://www.ibm.com/developerworks/cn/java/j-annotate2.html</a></div>
</div>
<img src ="http://www.blogjava.net/bacoo/aggbug/169185.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/bacoo/" target="_blank">bacoo</a> 2007-12-20 23:39 <a href="http://www.blogjava.net/bacoo/archive/2007/12/20/169185.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转载]java设计模式之Bridge(抽象和行为分开)</title><link>http://www.blogjava.net/bacoo/archive/2007/12/20/169184.html</link><dc:creator>bacoo</dc:creator><author>bacoo</author><pubDate>Thu, 20 Dec 2007 15:38:00 GMT</pubDate><guid>http://www.blogjava.net/bacoo/archive/2007/12/20/169184.html</guid><wfw:comment>http://www.blogjava.net/bacoo/comments/169184.html</wfw:comment><comments>http://www.blogjava.net/bacoo/archive/2007/12/20/169184.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/bacoo/comments/commentRss/169184.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/bacoo/services/trackbacks/169184.html</trackback:ping><description><![CDATA[<div><strong>Bridge定义 :<br />
</strong>　　将抽象和行为划分开来,各自独立,但能动态的结合.<br />
　　<br />
　　<strong>为什么使用?</strong><br />
　　通常,当一个抽象类或接口有多个具体实现(concrete subclass),这些concrete之间关系可能有以下两种:<br />
　　1. 这多个具体实现之间恰好是并列的,如前面举例,打桩,有两个concrete class:方形桩和圆形桩;这两个形状上的桩是并列的,没有概念上的重复,那么我们只要使用继承就可以了.<br />
　　<br />
　　2.实际应用上,常常有可能在这多个concrete class之间有概念上重叠.那么需要我们把抽象共同部分和行为共同部分各自独立开来,原来是准备放在一个接口里,现在需要设计两个接口,分别放置抽象和行为.<br />
　　<br />
　　例如,一杯咖啡为例,有中杯和大杯之分,同时还有加奶 不加奶之分. 如果用单纯的继承,这四个具体实现(中杯 大杯 加奶 不加奶)之间有概念重叠,因为有中杯加奶,也有中杯不加奶, 如果再在中杯这一层再实现两个继承,很显然混乱,扩展性极差.那我们使用Bridge模式来实现它.<br />
　　<br />
　　<strong>如何实现?</strong><br />
　　以上面提到的咖啡 为例. 我们原来打算只设计一个接口(抽象类),使用Bridge模式后,我们需要将抽象和行为分开,加奶和不加奶属于行为,我们将它们抽象成一个专门的行为接口.<br />
　　<br />
　　先看看抽象部分的接口代码:<br />
　　<br />
　　public abstract class Coffee<br />
　　{<br />
　　　　CoffeeImp coffeeImp;<br />
　　<br />
　　　　public void setCoffeeImp() {<br />
　　　　　　this.CoffeeImp = CoffeeImpSingleton.getTheCoffeImp();<br />
　　　　}<br />
　　<br />
　　　　public CoffeeImp getCoffeeImp() {return this.CoffeeImp;}<br />
　　<br />
　　　　public abstract void pourCoffee();<br />
　　} <br />
　　<br />
　　其中CoffeeImp 是加不加奶的行为接口,看其代码如下:<br />
　　<br />
　　public abstract class CoffeeImp<br />
　　{<br />
　　　　public abstract void pourCoffeeImp();<br />
　　}<br />
　　　<br />
　　现在我们有了两个抽象类,下面我们分别对其进行继承,实现concrete class:<br />
　　<br />
　　//中杯<br />
　　public class MediumCoffee extends Coffee<br />
　　{<br />
　　　　public MediumCoffee() {setCoffeeImp();}<br />
　　<br />
　　　　public void pourCoffee()<br />
　　　　{<br />
　　　　　　CoffeeImp coffeeImp = this.getCoffeeImp();<br />
　　　　　　//我们以重复次数来说明是冲中杯还是大杯 ,重复2次是中杯<br />
　　　　　　for (int i = 0; i &lt; 2; i++)<br />
　　　　　　{<br />
　　<br />
　　　　　　　　coffeeImp.pourCoffeeImp();<br />
　　　　　　}<br />
　　　　<br />
　　　　}<br />
　　}<br />
　　<br />
　　//大杯<br />
　　public class SuperSizeCoffee extends Coffee<br />
　　{<br />
　　　　public SuperSizeCoffee() {setCoffeeImp();}<br />
　　<br />
　　　　public void pourCoffee()<br />
　　　　{<br />
　　　　　　CoffeeImp coffeeImp = this.getCoffeeImp();<br />
　　　　　　//我们以重复次数来说明是冲中杯还是大杯 ,重复5次是大杯<br />
　　　　　　for (int i = 0; i &lt; 5; i++)<br />
　　　　　　{<br />
　　<br />
　　　　　　　　coffeeImp.pourCoffeeImp();<br />
　　　　　　}<br />
　　　　<br />
　　　　}<br />
　　} <br />
　　<br />
　　上面分别是中杯和大杯的具体实现.下面再对行为CoffeeImp进行继承:<br />
　　<br />
　　//加奶<br />
　　public class MilkCoffeeImp extends CoffeeImp<br />
　　{<br />
　　　　MilkCoffeeImp() {}<br />
　　<br />
　　　　public void pourCoffeeImp()<br />
　　　　{<br />
　　　　　　System.out.println("加了美味的牛奶");<br />
　　　　}<br />
　　}<br />
　　<br />
　　//不加奶<br />
　　public class FragrantCoffeeImp extends CoffeeImp<br />
　　{<br />
　　　　FragrantCoffeeImp() {}<br />
　　<br />
　　　　public void pourCoffeeImp()<br />
　　　　{<br />
　　　　　　System.out.println("什么也没加,清香");<br />
　　　　}<br />
　　} <br />
　　<br />
　　Bridge模式的基本框架我们已经搭好了,别忘记定义中还有一句:动态结合,我们现在可以喝到至少四种咖啡:<br />
　　1.中杯加奶<br />
　　2.中杯不加奶<br />
　　3.大杯加奶<br />
　　4.大杯不加奶<br />
　　<br />
　　看看是如何动态结合的,在使用之前,我们做个准备工作,设计一个单态类(Singleton)用来hold当前的CoffeeImp:<br />
　　<br />
　　public class CoffeeImpSingleton<br />
　　{<br />
　　　　private static CoffeeImp coffeeImp;<br />
　　<br />
　　　　public CoffeeImpSingleton(CoffeeImp coffeeImpIn)<br />
　　　　 {this.coffeeImp = coffeeImpIn;}<br />
　　<br />
　　　　public static CoffeeImp getTheCoffeeImp()<br />
　　　　{<br />
　　　　　　return coffeeImp;<br />
　　　　}<br />
　　} <br />
　　<br />
　　看看中杯加奶 和大杯加奶 是怎么出来的:<br />
　　<br />
　　//拿出牛奶<br />
　　CoffeeImpSingleton coffeeImpSingleton = new CoffeeImpSingleton(new MilkCoffeeImp());<br />
　　<br />
　　//中杯加奶<br />
　　MediumCoffee mediumCoffee = new MediumCoffee();<br />
　　mediumCoffee.pourCoffee();<br />
　　<br />
　　//大杯加奶<br />
　　SuperSizeCoffee superSizeCoffee = new SuperSizeCoffee();<br />
　　superSizeCoffee.pourCoffee();<br />
　　<br />
　　注意: Bridge模式的执行类如CoffeeImp和Coffee是一对一的关系, 正确创建CoffeeImp是该模式的关键,<br />
　　<br />
　　Bridge模式在EJB中的应用<br />
　　EJB中有一个Data Access Object (DAO)模式,这是将商业逻辑和具体数据资源分开的,因为不同的数据库有不同的数据库操作.将操作不同数据库的行为独立抽象成一个行为接口DAO.如下:<br />
　　<br />
　　1.Business Object (类似Coffee)<br />
　　<br />
　　实现一些抽象的商业操作:如寻找一个用户下所有的订单<br />
　　<br />
　　涉及数据库操作都使用DAOImplementor.<br />
　　<br />
　　2.Data Access Object (类似CoffeeImp)<br />
　　<br />
　　一些抽象的对数据库资源操作<br />
　　<br />
　　3.DAOImplementor 如OrderDAOCS, OrderDAOOracle, OrderDAOSybase(类似MilkCoffeeImp FragrantCoffeeImp)<br />
　　<br />
　　具体的数据库操作,如"INSERT INTO "等语句,OrderDAOOracle是Oracle OrderDAOSybase是Sybase数据库.<br />
　　<br />
　　4.数据库 (Cloudscape, Oracle, or Sybase database via JDBC API) </div>
<img src ="http://www.blogjava.net/bacoo/aggbug/169184.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/bacoo/" target="_blank">bacoo</a> 2007-12-20 23:38 <a href="http://www.blogjava.net/bacoo/archive/2007/12/20/169184.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转载]设计模式学习笔记(四)—Bridge桥接模式</title><link>http://www.blogjava.net/bacoo/archive/2007/12/20/169183.html</link><dc:creator>bacoo</dc:creator><author>bacoo</author><pubDate>Thu, 20 Dec 2007 15:37:00 GMT</pubDate><guid>http://www.blogjava.net/bacoo/archive/2007/12/20/169183.html</guid><wfw:comment>http://www.blogjava.net/bacoo/comments/169183.html</wfw:comment><comments>http://www.blogjava.net/bacoo/archive/2007/12/20/169183.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/bacoo/comments/commentRss/169183.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/bacoo/services/trackbacks/169183.html</trackback:ping><description><![CDATA[<div><font face="宋体">《设计模式》一书对Bridge是这样描述的：</font>
<p style="text-indent: 21pt"><span style="font-family: 宋体">将抽象与其实现解耦，使它们都可以独立地变化。</span>
<p style="text-indent: 21pt"><span style="font-family: 宋体">大致意思是说：将一组实现与另一组使用他们的对象分离。这里的实现指的是抽象类及其</span>
<p><span style="font-family: 宋体">派生类用来实现自己的对象（而不是抽象类的派生类，这些派生类被称为具体类）。下面</span>
<p><span style="font-family: 宋体">是《Design Patterns Explained》书中的例子。其结构图如下：<br />
<span style="font-size: 10pt; font-family: 宋体">&nbsp;<span style="font-size: 10pt; font-family: 宋体">&nbsp;<img height="368" alt="" src="http://www.blogjava.net/images/blogjava_net/flustar/clip_image001.gif" width="501" border="0" /></span></span><br />
</span>
<p><span style="font-family: 宋体">下面是它的实现：</span>
<p style="text-align: left" align="left"><span style="color: #7f0055; font-family: 宋体">abstract　</span><span style="color: #7f0055; font-family: 宋体">class</span><span style="color: black; font-family: 宋体"> Shape{</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">&nbsp;&nbsp;&nbsp; </span><span style="color: #7f0055; font-family: 宋体">protected</span><span style="color: black; font-family: 宋体"> <span style="background: silver">Drawing</span> </span><span style="color: #0000c0; font-family: 宋体">myDrawing</span><span style="color: black; font-family: 宋体">;</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">&nbsp;&nbsp;&nbsp; </span><span style="color: #7f0055; font-family: 宋体">abstract　</span><span style="color: #7f0055; font-family: 宋体">public　</span><span style="color: #7f0055; font-family: 宋体">void</span><span style="color: black; font-family: 宋体"> draw();</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">&nbsp;&nbsp;&nbsp; Shape(<span style="background: silver">Drawing</span> drawing){</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: #0000c0; font-family: 宋体">myDrawing</span><span style="color: black; font-family: 宋体">=drawing;</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">&nbsp;&nbsp;&nbsp; </span><span style="color: black; font-family: 宋体">}</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">&nbsp;&nbsp;&nbsp; </span><span style="color: #7f0055; font-family: 宋体">protected　</span><span style="color: #7f0055; font-family: 宋体">void</span><span style="color: black; font-family: 宋体"> drawLine(){</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: #0000c0; font-family: 宋体">myDrawing</span><span style="color: black; font-family: 宋体">.drawLine();</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">&nbsp;&nbsp;&nbsp; }</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">&nbsp;&nbsp;&nbsp; </span><span style="color: #7f0055; font-family: 宋体">protected　</span><span style="color: #7f0055; font-family: 宋体">void</span><span style="color: black; font-family: 宋体"> drawCircle(){</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: #0000c0; font-family: 宋体">myDrawing</span><span style="color: black; font-family: 宋体">.drawCircle();</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">&nbsp;&nbsp;&nbsp; }</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">}</span>
<p style="text-align: left" align="left"><span style="color: #7f0055; font-family: 宋体">class</span><span style="color: black; font-family: 宋体"> Rectangle </span><span style="color: #7f0055; font-family: 宋体">extends</span><span style="color: black; font-family: 宋体"> Shape{</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">&nbsp;&nbsp;&nbsp; </span><span style="color: #7f0055; font-family: 宋体">public</span><span style="color: black; font-family: 宋体"> Rectangle(<span style="background: silver">Drawing</span> darw){</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: #7f0055; font-family: 宋体">super</span><span style="color: black; font-family: 宋体">(darw);</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">&nbsp;&nbsp;&nbsp; }</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">&nbsp;&nbsp;&nbsp; </span><span style="color: #7f0055; font-family: 宋体">public　</span><span style="color: #7f0055; font-family: 宋体">void</span><span style="color: black; font-family: 宋体"> draw(){</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; drawLine();</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; drawLine();</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; drawLine();</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; drawLine();</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">&nbsp;&nbsp;&nbsp; }</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">}</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">&nbsp;</span><span style="color: #7f0055; font-family: 宋体">class</span><span style="color: black; font-family: 宋体"> Circle </span><span style="color: #7f0055; font-family: 宋体">extends</span><span style="color: black; font-family: 宋体"> Shape{</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">&nbsp;&nbsp;&nbsp; </span><span style="color: #7f0055; font-family: 宋体">public</span><span style="color: black; font-family: 宋体"> Circle(<span style="background: silver">Drawing</span> draw){</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: #7f0055; font-family: 宋体">super</span><span style="color: black; font-family: 宋体">(draw);</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">&nbsp;&nbsp;&nbsp; }</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">&nbsp;&nbsp;&nbsp; </span><span style="color: #7f0055; font-family: 宋体">public</span><span style="color: #7f0055; font-family: 宋体">void</span><span style="color: black; font-family: 宋体"> draw(){</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: #0000c0; font-family: 宋体">myDrawing</span><span style="color: black; font-family: 宋体">.drawCircle();</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">&nbsp;&nbsp;&nbsp; }</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">}</span>
<p style="text-align: left" align="left"><span style="color: #7f0055; font-family: 宋体">abstract　</span><span style="color: #7f0055; font-family: 宋体">class</span><span style="color: black; font-family: 宋体"> <span style="background: silver">Drawing</span>{</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">&nbsp;&nbsp;&nbsp; </span><span style="color: #7f0055; font-family: 宋体">abstract　</span><span style="color: #7f0055; font-family: 宋体">public　</span><span style="color: #7f0055; font-family: 宋体">void</span><span style="color: black; font-family: 宋体"> drawLine();</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">&nbsp;&nbsp;&nbsp; </span><span style="color: #7f0055; font-family: 宋体">abstract　</span><span style="color: #7f0055; font-family: 宋体">public　</span><span style="color: #7f0055; font-family: 宋体">void</span><span style="color: black; font-family: 宋体"> drawCircle();</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">}</span>
<p style="text-align: left" align="left"><span style="color: #7f0055; font-family: 宋体">class</span><span style="color: black; font-family: 宋体"> V1Drawing </span><span style="color: #7f0055; font-family: 宋体">extends</span><span style="color: black; font-family: 宋体"> <span style="background: silver">Drawing</span>{</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">&nbsp;&nbsp;&nbsp; </span><span style="color: #7f0055; font-family: 宋体">public　</span><span style="color: #7f0055; font-family: 宋体">void</span><span style="color: black; font-family: 宋体"> drawLine(){</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DP1.draw_a_line();</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">&nbsp;&nbsp;&nbsp; }</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">&nbsp;&nbsp;&nbsp; </span><span style="color: #7f0055; font-family: 宋体">public　</span><span style="color: #7f0055; font-family: 宋体">void</span><span style="color: black; font-family: 宋体"> drawCircle(){</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DP1.draw_a_circle();</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">&nbsp;&nbsp;&nbsp; }</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">}</span>
<p style="text-align: left" align="left"><span style="color: #7f0055; font-family: 宋体">class</span><span style="color: black; font-family: 宋体"> V2Drawing </span><span style="color: #7f0055; font-family: 宋体">extends</span><span style="color: black; font-family: 宋体"> <span style="background: silver">Drawing</span>{</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">&nbsp;&nbsp;&nbsp; </span><span style="color: #7f0055; font-family: 宋体">public　</span><span style="color: #7f0055; font-family: 宋体">void</span><span style="color: black; font-family: 宋体"> drawLine(){</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DP2.drawLine();</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">&nbsp;&nbsp;&nbsp; }</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">&nbsp;&nbsp;&nbsp; </span><span style="color: #7f0055; font-family: 宋体">public　</span><span style="color: #7f0055; font-family: 宋体">void</span><span style="color: black; font-family: 宋体"> drawCircle(){</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DP2.drawCircle();</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">&nbsp;&nbsp;&nbsp; </span><span style="color: black; font-family: 宋体">}</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">}</span>
<p style="text-align: left" align="left"><span style="color: #7f0055; font-family: 宋体">class</span><span style="color: black; font-family: 宋体"> DP1{</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">&nbsp;&nbsp;&nbsp; </span><span style="color: #7f0055; font-family: 宋体">public　</span><span style="color: #7f0055; font-family: 宋体">static　</span><span style="color: #7f0055; font-family: 宋体">void</span><span style="color: black; font-family: 宋体"> draw_a_line(){</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: black; font-family: 宋体">System.</span><span style="color: #0000c0; font-family: 宋体">out</span><span style="color: black; font-family: 宋体">.println(</span><span style="color: #2a00ff; font-family: 宋体">"使用DP1的draw_a_line()画线"</span><span style="color: black; font-family: 宋体">);</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">&nbsp;&nbsp;&nbsp; </span><span style="color: black; font-family: 宋体">}</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">&nbsp;&nbsp;&nbsp; </span><span style="color: #7f0055; font-family: 宋体">public　</span><span style="color: #7f0055; font-family: 宋体">static　</span><span style="color: #7f0055; font-family: 宋体">void</span><span style="color: black; font-family: 宋体"> draw_a_circle(){</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: black; font-family: 宋体">System.</span><span style="color: #0000c0; font-family: 宋体">out</span><span style="color: black; font-family: 宋体">.println(</span><span style="color: #2a00ff; font-family: 宋体">"使用DP1的draw_a_circle()画圆"</span><span style="color: black; font-family: 宋体">);</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">&nbsp;&nbsp;&nbsp; }</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">}</span>
<p style="text-align: left" align="left"><span style="color: #7f0055; font-family: 宋体">class</span><span style="color: black; font-family: 宋体"> DP2{</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">&nbsp;&nbsp;&nbsp; </span><span style="color: #7f0055; font-family: 宋体">public　</span><span style="color: #7f0055; font-family: 宋体">static　</span><span style="color: #7f0055; font-family: 宋体">void</span><span style="color: black; font-family: 宋体"> drawLine(){</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.</span><span style="color: #0000c0; font-family: 宋体">out</span><span style="color: black; font-family: 宋体">.println(</span><span style="color: #2a00ff; font-family: 宋体">"使用DP2的drawLine()画线"</span><span style="color: black; font-family: 宋体">);</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">&nbsp;&nbsp;&nbsp; }</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">&nbsp;&nbsp;&nbsp; </span><span style="color: #7f0055; font-family: 宋体">public　</span><span style="color: #7f0055; font-family: 宋体">static　</span><span style="color: #7f0055; font-family: 宋体">void</span><span style="color: black; font-family: 宋体"> drawCircle(){</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.</span><span style="color: #0000c0; font-family: 宋体">out</span><span style="color: black; font-family: 宋体">.println(</span><span style="color: #2a00ff; font-family: 宋体">"使用DP2的drawCircle()画圆"</span><span style="color: black; font-family: 宋体">);</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">&nbsp;&nbsp;&nbsp; }</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">}</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">&nbsp;</span><span style="color: #7f0055; font-family: 宋体">public　</span><span style="color: #7f0055; font-family: 宋体">class</span><span style="color: black; font-family: 宋体"> BridgeClient {</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">&nbsp;&nbsp;&nbsp; </span><span style="color: #7f0055; font-family: 宋体">public　</span><span style="color: #7f0055; font-family: 宋体">static　</span><span style="color: #7f0055; font-family: 宋体">void</span><span style="color: black; font-family: 宋体"> main(String[] args) {</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="background: silver">Drawing</span> draw1=</span><span style="color: #7f0055; font-family: 宋体">new</span><span style="color: black; font-family: 宋体"> V1Drawing();</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="background: silver">Drawing</span> draw2=</span><span style="color: #7f0055; font-family: 宋体">new</span><span style="color: black; font-family: 宋体"> V2Drawing();</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Shape shape1=</span><span style="color: #7f0055; font-family: 宋体">new</span><span style="color: black; font-family: 宋体"> Rectangle(draw1);</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; shape1.draw();</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Shape shape2=</span><span style="color: #7f0055; font-family: 宋体">new</span><span style="color: black; font-family: 宋体"> Circle(draw2);</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; shape2.draw();</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">&nbsp;&nbsp;&nbsp; }</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">}</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">输出结果如下</span><span style="color: black; font-family: 宋体">：</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">使用</span><span style="color: black; font-family: 宋体">DP1</span><span style="color: black; font-family: 宋体">的</span><span style="color: black; font-family: 宋体">draw_a_line()</span><span style="color: black; font-family: 宋体">画线</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">使用</span><span style="color: black; font-family: 宋体">DP1</span><span style="color: black; font-family: 宋体">的</span><span style="color: black; font-family: 宋体">draw_a_line()</span><span style="color: black; font-family: 宋体">画线</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">使用</span><span style="color: black; font-family: 宋体">DP1</span><span style="color: black; font-family: 宋体">的</span><span style="color: black; font-family: 宋体">draw_a_line()</span><span style="color: black; font-family: 宋体">画线</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">使用</span><span style="color: black; font-family: 宋体">DP1</span><span style="color: black; font-family: 宋体">的</span><span style="color: black; font-family: 宋体">draw_a_line()</span><span style="color: black; font-family: 宋体">画线</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">使用</span><span style="color: black; font-family: 宋体">DP2</span><span style="color: black; font-family: 宋体">的</span><span style="color: black; font-family: 宋体">drawCircle()</span><span style="color: black; font-family: 宋体">画圆</span>
<p style="text-align: left" align="left"><span style="color: black; font-family: 宋体">在这个例子中</span><span style="color: black; font-family: 宋体">Shape</span><span style="color: black; font-family: 宋体">对象实际上是一个</span><span style="color: black; font-family: 宋体">Retangle</span><span style="color: black; font-family: 宋体">或</span><span style="color: black; font-family: 宋体">Circle</span><span style="color: black; font-family: 宋体">对象</span><span style="color: black; font-family: 宋体">，</span><span style="color: black; font-family: 宋体">但</span><span style="color: black; font-family: 宋体">Client</span><span style="color: black; font-family: 宋体">并不知道到底是那个</span><span style="color: black; font-family: 宋体">，</span><span style="color: black; font-family: 宋体">因为它们看起来都一样。</span><span style="color: black; font-family: 宋体">Drawing</span><span style="color: black; font-family: 宋体">实际上是一个</span><span style="color: black; font-family: 宋体">V1Drawing</span><span style="color: black; font-family: 宋体">或</span><span style="color: black; font-family: 宋体">V2Drawing,</span><span style="color: black; font-family: 宋体">但</span><span style="color: black; font-family: 宋体">Shape</span><span style="color: black; font-family: 宋体">对象</span><span style="font-family: 宋体">并知道到底是哪个</span><span style="font-family: 宋体">，</span><span style="font-family: 宋体">因为它们看起来都一样。DP1或DP2使用它的Drawing对象知道是哪一个。Shape是事物的抽象，Drawing是实现或者操作事物方法的抽象。他们两个都可以独立地变化。正如例子中所说那样，我们可以输出一个矩形可以使用V1Drawing也可以使用V2Drawing来完成，输出一个圆形也是一样都有两种方法。Bridge模式遵循了设计模式中两条基本策略：找出变化并封装之和优先使用对象聚集，而不是类继承。</span>
<p><span style="font-family: 宋体">&nbsp;&nbsp;&nbsp; 小结：Bridge模式是一种抽象与其实现相分离的模式。它主要应用于：当事物是一组变化量，和对这些事物的操作方法(实现)也是一组变化量的情况，也就是说它们都是多变的。</span></p>
</div>
<img src ="http://www.blogjava.net/bacoo/aggbug/169183.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/bacoo/" target="_blank">bacoo</a> 2007-12-20 23:37 <a href="http://www.blogjava.net/bacoo/archive/2007/12/20/169183.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转载]singleton(单态模式)</title><link>http://www.blogjava.net/bacoo/archive/2007/12/20/169180.html</link><dc:creator>bacoo</dc:creator><author>bacoo</author><pubDate>Thu, 20 Dec 2007 15:21:00 GMT</pubDate><guid>http://www.blogjava.net/bacoo/archive/2007/12/20/169180.html</guid><wfw:comment>http://www.blogjava.net/bacoo/comments/169180.html</wfw:comment><comments>http://www.blogjava.net/bacoo/archive/2007/12/20/169180.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/bacoo/comments/commentRss/169180.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/bacoo/services/trackbacks/169180.html</trackback:ping><description><![CDATA[<div>
<p><strong>单态定义</strong>:<br />
Singleton模式主要作用是保证在Java应用程序中，一个类Class只有一个实例存在。
<p>在很多操作中，比如建立目录 数据库连接都需要这样的单线程操作。
<p>还有, singleton能够被状态化; 这样，多个单态类在一起就可以作为一个状态仓库一样向外提供服务，比如，你要论坛中的帖子计数器，每次浏览一次需要计数，单态类能否保持住这个计数，并且能synchronize的安全自动加1，如果你要把这个数字永久保存到数据库，你可以在不修改单态接口的情况下方便的做到。
<p>另外方面，Singleton也能够被无状态化。提供工具性质的功能，<br />
<br />
Singleton模式就为我们提供了这样实现的可能。使用Singleton的好处还在于可以节省内存，因为它限制了实例的个数，有利于Java垃圾回收（garbage collection）。<br />
<br />
我们常常看到工厂模式中类装入器(class loader)中也用Singleton模式实现的,因为被装入的类实际也属于资源。<br />
<p><strong>如何使用?</strong><br />
一般Singleton模式通常有几种形式:
<table cellspacing="3" cellpadding="3" width="100%" border="0">
    <tbody>
        <tr>
            <td bgcolor="#cccccc">
            <p>public class Singleton {
            <p>　　private Singleton(){}
            <p>　　//在自己内部定义自己一个实例，是不是很奇怪？<br />
            　　//注意这是private 只供内部调用
            <p>　　private static Singleton instance = new Singleton();
            <p>　　//这里提供了一个供外部访问本class的静态方法，可以直接访问　　<br />
            　　public static Singleton getInstance() {<br />
            　　　　return instance; 　　<br />
            　　 } <br />
            }
            <p>&nbsp;</p>
            </td>
        </tr>
    </tbody>
</table>
<p>第二种形式:
<table cellspacing="3" cellpadding="3" width="100%" border="0">
    <tbody>
        <tr>
            <td bgcolor="#cccccc">public class Singleton {
            <p>　　private static Singleton instance = null;<br />
            <br />
            　　public static synchronized Singleton getInstance() {<br />
            <br />
            　　//这个方法比上面有所改进，不用每次都进行生成对象，只是第一次　　　 　<br />
            　　//使用时生成实例，提高了效率！<br />
            　　if (instance==null)<br />
            　　　　instance＝new Singleton();<br />
            　　return instance; 　　}
            <p>}
            <p>&nbsp;</p>
            </td>
        </tr>
    </tbody>
</table>
<p>使用Singleton.getInstance()可以访问单态类。
<p>上面第二中形式是lazy initialization，也就是说第一次调用时初始Singleton，以后就不用再生成了。
<p>注意到lazy initialization形式中的synchronized，这个synchronized很重要，如果没有synchronized，那么使用getInstance()是有可能得到多个Singleton实例。关于lazy initialization的Singleton有很多涉及double-checked locking (DCL)的讨论，有兴趣者进一步研究。
<p>一般认为第一种形式要更加安全些。<br />
<p><strong>使用Singleton注意事项</strong>：<br />
有时在某些情况下，使用Singleton并不能达到Singleton的目的，如有多个Singleton对象同时被不同的类装入器装载；在EJB这样的分布式系统中使用也要注意这种情况，因为EJB是跨服务器，跨JVM的。
<p>我们以SUN公司的宠物店源码(Pet Store 1.3.1)的ServiceLocator为例稍微分析一下：<br />
<br />
在Pet Store中ServiceLocator有两种，一个是EJB目录下；一个是WEB目录下，我们检查这两个ServiceLocator会发现内容差不多，都是提供EJB的查询定位服务，可是为什么要分开呢？仔细研究对这两种ServiceLocator才发现区别：在WEB中的ServiceLocator的采取Singleton模式，ServiceLocator属于资源定位，理所当然应该使用Singleton模式。但是在EJB中，Singleton模式已经失去作用，所以ServiceLocator才分成两种，一种面向WEB服务的，一种是面向EJB服务的。
<p>Singleton模式看起来简单，使用方法也很方便，但是真正用好，是非常不容易，需要对Java的类 线程 内存等概念有相当的了解。
<p>总之：如果你的应用基于容器，那么Singleton模式少用或者不用，可以使用相关替代技术。
<p>
<p>进一步深入可参考：
<p><a href="http://www-106.ibm.com/developerworks/java/library/j-dcl.html?dwzone=java" target="_blank"><font color="#333333"><u>Double-checked locking and the Singleton pattern</u></font></a>
<p><a href="http://www.javaworld.com/javaworld/jw-01-2001/jw-0112-singleton-p3.html#resources" target="_blank"><u><font color="#333333">When is a singleton not a singleton?</font></u></a>
<p>设计模式如何在具体项目中应用见<a href="http://www.jdon.com/mybook/index.htm" target="_blank"><u><font color="#333333">《Java实用系统开发指南》</font></u></a>
<p>&nbsp;
<p>Singleton模式的要点：<br />
1、某个类只能有一个实例<br />
2、必须自行创建这个实例<br />
3、必须向整个系统提供这个实例
<p>
<p>Singleton模式的实现方法<br />
1、饿汉式singleton<br />
public class EagerSingleton<br />
{<br />
private static final EagerSingleton m_instance = new Eagersingleton();<br />
private Eagersingleton(){}
<p>public static EagerSingleton getInstance()<br />
{<br />
return m_instance;<br />
}<br />
<br />
}
<p>2、懒汉式singleton<br />
public class LazySingleton<br />
{<br />
private static LazySingleton m_instance = null;<br />
private LazySingleton(){};<br />
synchronized public static LazySingleton getInstance()<br />
{<br />
if( m_instance == null )<br />
{<br />
m_instance = new LazySingleton();<br />
}<br />
return m_instance;<br />
}<br />
}
<p>3、登记式singleton<br />
import java.util.HashMap;<br />
public class RegSingleton<br />
{<br />
static private HashMap m_registry = new HashMap();<br />
static <br />
{<br />
RegSingleton x = new regSingleton();<br />
m_registry.put(x.getClass().getName(), x);<br />
}<br />
protect RegSingleton(){}<br />
static public RegSingleton getInstance(String name)<br />
{<br />
if(name == null )<br />
{<br />
name = "RegSingleton";<br />
}<br />
if(m_registry.get(name ) == null )<br />
{<br />
m_registry.put(name, Class.forName(name).newInstance();<br />
}<br />
catch(Exception e)<br />
{<br />
System.out.println("Error happened.");<br />
}<br />
return (RegSingleton)(m_registry.get(name));<br />
}<br />
}<br />
<br />
<strong>三种Singleton模式的比较</strong><br />
<br />
饿汉式 类被加载时就被实例化。<br />
懒汉式 类加载时，不被实例化，在第一次引用时实例化。
<p>
<p>饿汉式、懒汉式都不能被继承<br />
而登记式可以被继承。</p>
</div>
<img src ="http://www.blogjava.net/bacoo/aggbug/169180.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/bacoo/" target="_blank">bacoo</a> 2007-12-20 23:21 <a href="http://www.blogjava.net/bacoo/archive/2007/12/20/169180.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JTable学习笔记</title><link>http://www.blogjava.net/bacoo/archive/2007/12/20/169178.html</link><dc:creator>bacoo</dc:creator><author>bacoo</author><pubDate>Thu, 20 Dec 2007 15:20:00 GMT</pubDate><guid>http://www.blogjava.net/bacoo/archive/2007/12/20/169178.html</guid><wfw:comment>http://www.blogjava.net/bacoo/comments/169178.html</wfw:comment><comments>http://www.blogjava.net/bacoo/archive/2007/12/20/169178.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/bacoo/comments/commentRss/169178.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/bacoo/services/trackbacks/169178.html</trackback:ping><description><![CDATA[<p>构建一个JTable之前，应该设计好表格的列头以及行数据，分别用final数组保存之：<br />
final String [] names={"First Name","Last Name","Favorite Color",<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "Favorite Number","Vegetarian"};<br />
final Object [][] data={<br />
&nbsp;&nbsp;&nbsp; {"Mark","Andrews","Red",new Integer(2),new Boolean(true)},<br />
&nbsp;&nbsp;&nbsp; {"Tom","Chung","Green",new Integer(99),new Boolean(false)}<br />
&nbsp;&nbsp;&nbsp; };<br />
接下来，在创建JTable之前，需要构建一个实现了TableModel接口的AbstractTableModel类的实例，TableModel接口规定了JTable如何访问表格中数据的模型。示例如下：<br />
TableModel dataModel =new AbstractTableModel(){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public int getColumnCount(){return names.length;}//实现这个函数是必须的，因为抽象类AbstractTableModel中并没有实现该函数<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public int getRowCount(){return data.length;}//实现这个函数是必须的，因为抽象类AbstractTableModel中并没有实现该函数<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public Object getValueAt(int row,int col){return data[row][col];}//实现这个函数是必须的，因为抽象类AbstractTableModel中并没有实现该函数<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public String getColumnName(int column){return names[column];}//如果需要自己来命名列名称，就必须override该方法<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; @SuppressWarnings("unchecked")<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public Class getColumnClass(int col){return getValueAt(0,col).getClass();}//这个方法也因该重写，因为AbstractTableModel中的实现仅仅是&#8220;return Object.class;&#8221;，因此我们需要override该方法<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public boolean isCellEditable(int row,int col){return true;}//默认均返回false，因此如果希望表格的cell能够被编辑，就需要override这个函数<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void setValueAt(Object aValue,int row,int col){//默认情况下，该函数的函数体是空的，因此如果希望表格的cell中的值能够被更改，就必须override该函数<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("Setting value to: "+aValue);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; data[row][col]=aValue;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
};<br />
接下来就可以创建JTable了：<br />
JTable tableView=new JTable(dataModel);<br />
至此，表格已经创建起来了。如果需要能够对表格进行更进一步的操作，比如允许用户编辑表格中各个单元格的内容，就需要看看下面的内容喽：<br />
我个人认为编辑表格是以列为单位的，<br />
第一步，需要得到某一列：<br />
TableColumn colorColumn=tableView.getColumn(names[2]);<br />
第二步，需要给该列指定一个实现了TableCellEditor接口的编辑类，DefaultCellEditor类实现了该接口，因此直接构建DefaultCellEditor类的一个实例就ok了，需要说明的是，该类的实现方法只有三种，而且分别对应需要JCheckBox、JComboBox、JTextField三种类的实例：<br />
colorColumn.setCellEditor(new DefaultCellEditor(comboBox));<br />
第三步，给该列指定一个实现了TableCellRenderer接口的的渲染类（或称作呈现/表现类），DefaultTableCellRenderer类实现了该接口，因此直接构建DefaultTableCellRenderer的一个实例就ok了：<br />
DefaultTableCellRenderer colorColumnRenderer=new DefaultTableCellRenderer();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; colorColumnRenderer.setBackground(Color.pink);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; colorColumnRenderer.setHorizontalAlignment(JLabel.RIGHT);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; colorColumnRenderer.setToolTipText("Click for combo box");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; colorColumn.setCellRenderer(colorColumnRenderer);<br />
需要说明的是，DefaultTableCellRenderer能够设置的内容当然不局限于上述列出的这三个，还有很多，但是有一点很重要，就是如果你希望单元格的内容能够按照某种方式来改变，比如用户自己编辑了单元格内容后，我们如果希望单元格呈现的内容能够根据用户的输入做更多的变化（而不仅仅是简单的字符串替换，如果仅仅是字符串替换的话，那就不必废这么多事了，DefaultTableCellRenderer类自带的setValue实现方法就能够完成任务了），而不在希望单元格的内容一成不变了，此时就不能简单的创建一个DefaultTableCellRenderer类的实例了，而是需要创建一个DefaultTableCellRenderer类的派生类，而且需要override里面的setValue方法，通常我们都这样做：<br />
DefaultTableCellRenderer numberColumnRenderer=new DefaultTableCellRenderer(){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void setValue(Object value){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int cellValue=(value instanceof Number) ? ((Number)value).intValue() : 0;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.setForeground((cellValue &gt; 30) ? Color.black : Color.red);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; super.setValue(value);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
};<br />
在DefaultTableCellRenderer类中setValue方法的修饰符为protected，因此我们不能直接用DefaultTableCellRenderer的实例来使用该方法，而只能通过继承DefaultTableCellRenderer类，然后在类的内部override该方法来实现定制特定的功能，从这里我们也能够更深刻的理解为什么有些方法要定义成protected了，目的就是为了对外不可见，但是又能够通过继承的手段来实现用户自己的定制，而且有些情况这是很必须的，比如在该处，我们可以试想一下，如果用public来修饰，则用户可以直接通过产生实例来引用该方法，那么由于该类是作用于整个列的，而不仅仅是一个单元格，那么当你设定了setValue后，到底是该对列中所有的单元格都有效呢，还是该只对某一个单元格有效呢，这就很难说了。</p>
<img src ="http://www.blogjava.net/bacoo/aggbug/169178.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/bacoo/" target="_blank">bacoo</a> 2007-12-20 23:20 <a href="http://www.blogjava.net/bacoo/archive/2007/12/20/169178.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[改编]深入equals方法，讨论instanceof的使用！</title><link>http://www.blogjava.net/bacoo/archive/2007/12/20/169176.html</link><dc:creator>bacoo</dc:creator><author>bacoo</author><pubDate>Thu, 20 Dec 2007 15:19:00 GMT</pubDate><guid>http://www.blogjava.net/bacoo/archive/2007/12/20/169176.html</guid><wfw:comment>http://www.blogjava.net/bacoo/comments/169176.html</wfw:comment><comments>http://www.blogjava.net/bacoo/archive/2007/12/20/169176.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/bacoo/comments/commentRss/169176.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/bacoo/services/trackbacks/169176.html</trackback:ping><description><![CDATA[<p>equals方法的重要性毋须多言,只要你想比较的两个对象不仅仅局限在只是同一对象（即它们的引用相同）,你就应该实现equals方法,让对象用你认为相等的条件来进行比较。
<p>　　下面的内容只是API的规范,没有什么太高深的意义,但我之所以最先把它列在这儿,是因为这些规范在事实中并不是真正能保证得到实现。
<p>1。自反性：对于任何引用类型, o.equals(o) == true成立。 <br />
2。对称性：如果 o.equals(o1) == true 成立,那么o1.equals(o)==true也一定要成立。 <br />
3。传递性：如果 o.equals(o1) == true 成立且&nbsp; o1.equals(o2) == true 成立,那么o.equals(o2) == true 也成立。 <br />
4。一致性：如果第一次调用o.equals(o1) == true成立再o和o1没有改变的情况下以后的任何次调用都成立。 <br />
5。o.equals(null) == true 任何时间都不成立。 <br />
　　以上几条规则并不是最完整的表述,详细的请参见API文档。<br />
&nbsp;&nbsp;&nbsp; 但是在hashCode()函数的协定中，要求&#8220;如果根据 equals(Object) 方法，两个对象是相等的，那么对这两个对象中的每个对象调用 hashCode 方法都必须生成相同的整数结果。&#8221;，因此我个人认为equals方法还应该加上这第6条规定：<br />
6。如果 o.equals(o1) == true 成立,那么必须有o.hashCode==o1.hashCode()。
<p>　　对于Object类,它提供了一个最最严密的实现,那就是只有是同一对象是,equals方法才返回true,也就是人们常说的引用比较而不是值比较。这个实现严密得已经没有什么实际的意义,所以在具体子类(相对于Object来说)中,如果我们要进行对象的值比较,就必须实现自己的equals方法。
<p>　　先来看一下以下这段引自于JDK中的程序:<br />
（说明：attribute在FieldPosition中有这样的定义：private Format.Field attribute;）<br />
&nbsp;&nbsp;&nbsp; public boolean equals(Object obj)<br />
&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (obj == null) return false;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!(obj instanceof FieldPosition))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return false;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FieldPosition other = (FieldPosition) obj;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (attribute == null) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (other.attribute != null) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return false;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else if (!attribute.equals(other.attribute)) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return false;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return (beginIndex == other.beginIndex<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;&amp; endIndex == other.endIndex<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;&amp; field == other.field);<br />
&nbsp;&nbsp;&nbsp; }<br />
　　这是JDK中java.text.FieldPosition的标准实现,似乎没有什么可说的. 我相信大多数或绝大多数程序员认为,这是正确的合法的equals实现.毕竟它是JDK的API实现啊. 还是让我们以事实来说话吧:
<p>package debug;<br />
import java.text.*;<br />
public class Test {<br />
&nbsp; public static void main(String[] args) {<br />
&nbsp;&nbsp;&nbsp; FieldPosition fp = new FieldPosition(10);<br />
&nbsp;&nbsp;&nbsp; FieldPosition fp1 = new MyTest(10);<br />
&nbsp;&nbsp;&nbsp; System.out.println(fp.equals(fp1));<br />
&nbsp;&nbsp;&nbsp; System.out.println(fp1.equals(fp));<br />
&nbsp; }<br />
}<br />
class MyTest extends FieldPosition{<br />
&nbsp; int x = 10;<br />
&nbsp; public MyTest(int x){<br />
&nbsp;&nbsp;&nbsp; super(x);<br />
&nbsp;&nbsp;&nbsp; this.x = x;<br />
&nbsp; }<br />
&nbsp; public boolean equals(Object o){<br />
&nbsp;&nbsp;&nbsp; if(o==null) return false;<br />
&nbsp;&nbsp;&nbsp; if(!(o instanceof MyTest )) return false;<br />
&nbsp;&nbsp;&nbsp; return ((MyTest)o).x == this.x;<br />
&nbsp; }<br />
}<br />
　　 运行一下看看会打印出什么:
<p>System.out.println(fp.equals(fp1));打印true<br />
System.out.println(fp1.equals(fp));打印flase　　<br />
　　两个对象,出现了不对称的equals算法.问题出在哪里(脑筋急转弯：当然出在JDK实现的固有BUG，看来JDK中的东西未必就完全都是最最最正确的，我们要敢于怀疑它！)?
<p>　　我相信有太多的程序员在实现equals方法时都用过instanceof运行符来进行短路优化的，实事求是地说很长一段时间我也这么用过。太多的教程，文档都给了我们这样的误导。而有些稍有了解的程序员可能知道这样的优化可能有些不对但找不出问题的关键。另外一种极端是知道这个技术缺陷的骨灰级专家就提议不要这样应用。
<p>　　我们知道，"通常"要对两个对象进行比较，那么它们"应该"是同一类型。所以首先利用nstanceof运行符进行短路优化（&#8220;短路&#8221;《Short-circuiting》，而短路的最大好处就是能够优化性能。所谓的短路就是当第一个被运算的表达式的结果已经能够决定运算的最终结果时，就不会再去计算其他的表达式，因此可以避免掉额外且不必要的运算操作，尤其是当所略过的是复杂或含有过程调用的表达式时，短路的性能提升幅度更为明显。比如我们在if中同时用&amp;&amp;判断多个条件的时候，遇到第一个false的时候就不会再计算后面的表达式是否为true了），如果被比较的对象不和当前对象是同一类型则不用比较返回false,但事实上，"子类是父类的一个实例"，所以如果 子类 instanceof 父类，始终返回true,这时肯定不会发生短路优化，下面的比较有可能出现多种情况，一种是父类不能造型成子类而抛出异常（比如子类.equals(父类)后，在equals内部会进行试图将父类向下造型成子类的操作），另一种是父类的private 成员没有被子类继承而不能进行比较，还有就是形成上面这种不对称比较。可能会出现太多的情况。
<p>　　那么，是不是就不能用 instanceof运行符来进行优化？答案是否定的，JDK中仍然有很多实现是正确的，如果一个class是final的，明知它不可能有子类，为什么不用instanceof来优化呢？（可见对于不涉及子类的问题时，用instanceof进行短路优化还是很可行的）
<p>　　为了维护SUN的开发小组的声誉，我不说明哪个类中，但有一个小组成员在用这个方法优化时在后加加上了加上了这样的注释：
<p>if (this == obj)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // quick check（也就是短路优化）<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return true;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!(obj instanceof XXXXClass))&nbsp; // (1) same object?<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return false;　　可能是有些疑问，但不知道如何做（不知道为什么没有打电话给我......）
<p>　　那么对于非final类，如何进行类型的quick check呢？
<p>if(obj.getClass() != XXXClass.class) return false;<br />
　　用被比较对象的class对象和当前对象的class比较，看起来是没有问题，但是，如果这个类的子类没有重新实现equals方法，那么当子类.equals(子类)比较时，也就是要使用&#8220;if(obj.getClass() != XXXClass.class) return false;&#8221;来进行比较了，显然obj.getClass()《这个是字类》 肯定不等于XXXCalss.class《这个是父类》,从这里就直接返回得到false的结果了，因此子类中定义的equals实际上根本没发挥出应有的效力来，所以if(obj.getClass() != this.getClass()) return false;才是正确的比较。 呵呵，看到了没？我们首先否定了instanceof，接下来又否定了&#8220;obj.getClass() != XXXClass.class&#8221;这种错误的比较做法，最后才给出了正确的比较方法。<br />
另外一个quick check是if(this==obj) return true;而且这个短路优化应该放在&#8220;obj.getClass() != XXXClass.class&#8221;优化的前面。
<p>　　是否equals方法一定比较的两个对象就一定是要同一类型？上面我用了"通常"，这也是绝大多数程序员的愿望，但是有些特殊的情况，我们可以进行不同类型的比较，这并不违反规范。但这种特殊情况是非常罕见的，一个不恰当的例子是，Integer类的equals可以和Sort做比较，比较它们的value是不是同一数学值。（事实上JDK的API中并没有这样做，所以我才说是不恰当的例子）。在完成quick check以后，我们就要真正实现你认为的&#8220;相等&#8221;。对于如果实现对象相等，没有太高的要求，比如你自己实现的&#8220;人&#8221;类，你可以认为只要name相同即认为它们是相等的，其它的sex,ago都可以不考虑。这是不完全实现，但是如果是完全实现，即要求所有的属性都是相同的，那么如何实现equals方法？
<p>class Human{<br />
private String name;<br />
private int ago;<br />
private String sex;<br />
&nbsp; ....................<br />
&nbsp; public boolean equals(Object obj){<br />
&nbsp; quick check.......<br />
&nbsp; Human other = (Human)ojb;<br />
&nbsp; return this.name.equals(other.name) <br />
&nbsp;&nbsp; &amp;&amp; this.ago == ohter.ago<br />
&nbsp;&nbsp; &amp;&amp; this.sex.equals(other.sex);<br />
}<br />
}<br />
　　 这是一个完全实现，但是，有时equals实现是在父类中实现的，而且要求被子类继承后，父类的equals能正确的工作，这时父类中的equals并不事实知道子类到底扩展了哪些属性，所以用上面的方法无法使equals得到完全实现。
<p>　　一个好的方法是利用反射来对equals进行完全实现： 给出一个完整的在父类中定义的equals方法（只是比较字段）的实现：<br />
public boolean equals(Object obj){<br />
&nbsp; if(obj == this)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return true;<br />
&nbsp; if(obj.getClass() != this.getClass())<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return false;<br />
&nbsp; Class c = this.getClass();<br />
&nbsp; Filed[] fds = c.getDeclaredFields();<br />
&nbsp; for(Filed f:fds){<br />
&nbsp;&nbsp; if(!f.get(this).equals(f.get(obj)))<br />
&nbsp;&nbsp;&nbsp; return false;<br />
&nbsp; }<br />
&nbsp; return true;<br />
}<br />
　　为了说明的方便，上明的实现省略了异常，这样的实现放在父类中，可以保证你的子类的equals可以按你的愿望正确地工作。当然这里只是考虑了基于字段相等的比较，如何还涉及到基于方法等其他方面的相等比较，则应该扩展上面的代码，反射出更多的东西（比如方法）来加以比较判断。
<p>　　关于equals方法的最后一点是：如果你要是自己重写（正确说应该是履盖）了equals方法，那同时就一定要重写hashCode()，否则.............
<p>　　我们还是看一下这个例子：
<p>public final class PhoneNumber {<br />
&nbsp;&nbsp;&nbsp; private final int areaCode;<br />
&nbsp;&nbsp;&nbsp; private final int exchange;<br />
&nbsp;&nbsp;&nbsp; private final int extension;<br />
&nbsp;&nbsp;&nbsp; public PhoneNumber(int areaCode, int exchange, int extension) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rangeCheck(areaCode, 999, "area code");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rangeCheck(exchange, 99999999, "exchange");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rangeCheck(extension, 9999, "extension");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.areaCode = areaCode;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.exchange = exchange;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.extension = extension;<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; private static void rangeCheck(int arg, int max, String name) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(arg &lt; 0 || arg &gt; max)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw new IllegalArgumentException(name + ": " + arg);<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; public boolean equals(Object o) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(o == this)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return true;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(!(o instanceof PhoneNumber))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return false;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PhoneNumber pn = (PhoneNumber)o;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return pn.extension == extension &amp;&amp; pn.exchange == exchange &amp;&amp; pn.areaCode == areaCode;<br />
&nbsp;&nbsp;&nbsp; }<br />
}<br />
　　注意这个类是final的，所以这个equals实现没有什么问题。
<p>　　我们来测试一下:
<p>&nbsp;&nbsp;&nbsp; public static void main(String[] args) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Map hm = new HashMap();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PhoneNumber pn = new PhoneNumber(123, 38942, 230);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hm.put(pn, "I love you");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PhoneNumber pn1 = new PhoneNumber(123, 38942, 230);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(pn);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("pn.equals(pn1) is " + pn.equals(pn1));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(hm.get(pn1));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(hm.get(pn));<br />
&nbsp;&nbsp;&nbsp; }<br />
　　既然pn.equals(pn1),那么我put(pn,"I love you");后，get(pn1)这什么是null呢？
<p>　　答案是因为pn和pn1的hashCode不一样，而hashMap就是以hashCode为主键的。
<p>　　所以根据规范要求（在文章最开始部分提到的标准equals方法需要满足的6条性质），如果两个对象进行equals比较时如果返回true,那么它们的hashcode要求返回相等的值。
<p>此外，在写hashCode函数时，需要注意：<br />
随便你怎么写，只要保证A.equals(B)一定可以推出A.hashCode()==B.hashCode()就行；当然，应该尽量使得A.equals(B)==false的时候，使得A.hashCode()尽量不等于B.hashCode()，绝对不会相等是不可能的，但是要尽量降低概率。
<p>比如：<br />
public int hashCode() { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int result; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; result = getName().hashCode(); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; result = 29 * result + getBirthday().hashCode(); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return result; <br />
&nbsp;&nbsp;&nbsp; } <br />
其时就是需要你根据自己的类给出特有的一种算法，能够满足通过该算法得到的这个整数值（也就是hashCode）能够区别该类的各个实例。</p>
<img src ="http://www.blogjava.net/bacoo/aggbug/169176.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/bacoo/" target="_blank">bacoo</a> 2007-12-20 23:19 <a href="http://www.blogjava.net/bacoo/archive/2007/12/20/169176.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转载]轻松语言比喻java的32种模式</title><link>http://www.blogjava.net/bacoo/archive/2007/12/20/169175.html</link><dc:creator>bacoo</dc:creator><author>bacoo</author><pubDate>Thu, 20 Dec 2007 15:18:00 GMT</pubDate><guid>http://www.blogjava.net/bacoo/archive/2007/12/20/169175.html</guid><wfw:comment>http://www.blogjava.net/bacoo/comments/169175.html</wfw:comment><comments>http://www.blogjava.net/bacoo/archive/2007/12/20/169175.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/bacoo/comments/commentRss/169175.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/bacoo/services/trackbacks/169175.html</trackback:ping><description><![CDATA[<p>java与模式&nbsp; <br />
在java版看见了这篇文章，作者以轻松的语言比喻了java的32种模式，有很好的启发作用，但可惜没有给出具体的意思，这些都是最简单的介绍，要学习的话建议你看一下《ajva与模式》这本书。 <br />
创建型模式
<p>1、FACTORY—追MM少不了请吃饭了，麦当劳的鸡翅和肯德基的鸡翅都是MM爱吃的东西，虽然口味有所不同，但不管你带MM去麦当劳或肯德基，只管向服务员说&#8220;来四个鸡翅&#8221;就行了。麦当劳和肯德基就是生产鸡翅的Factory
<p>工厂模式：客户类和工厂类分开。消费者任何时候需要某种产品，只需向工厂请求即可。消费者无须修改就可以接纳新产品。缺点是当产品修改时，工厂类也要做相应的修改。如：如何创建及如何向客户端提供。
<p>2、BUILDER—MM最爱听的就是&#8220;我爱你&#8221;这句话了，见到不同地方的MM,要能够用她们的方言跟她说这句话哦，我有一个多种语言翻译机，上面每种语言都有一个按键，见到MM我只要按对应的键，它就能够用相应的语言说出&#8220;我爱你&#8221;这句话了，国外的MM也可以轻松搞掂，这就是我的&#8220;我爱你&#8221;builder。（这一定比美军在伊拉克用的翻译机好卖）
<p>建造模式：将产品的内部表象和产品的生成过程分割开来，从而使一个建造过程生成具有不同的内部表象的产品对象。建造模式使得产品内部表象可以独立的变化，客户不必知道产品内部组成的细节。建造模式可以强制实行一种分步骤进行的建造过程。
<p>3、FACTORY METHOD—请MM去麦当劳吃汉堡，不同的MM有不同的口味，要每个都记住是一件烦人的事情，我一般采用Factory Method模式，带着MM到服务员那儿，说&#8220;要一个汉堡&#8221;，具体要什么样的汉堡呢，让MM直接跟服务员说就行了。
<p>工厂方法模式：核心工厂类不再负责所有产品的创建，而是将具体创建的工作交给子类去做，成为一个抽象工厂角色，仅负责给出具体工厂类必须实现的接口，而不接触哪一个产品类应当被实例化这种细节。
<p>4、PROTOTYPE—跟MM用QQ聊天，一定要说些深情的话语了，我搜集了好多肉麻的情话，需要时只要copy出来放到QQ里面就行了，这就是我的情话prototype了。（100块钱一份，你要不要）
<p>原始模型模式：通过给出一个原型对象来指明所要创建的对象的类型，然后用复制这个原型对象的方法创建出更多同类型的对象。原始模型模式允许动态的增加或减少产品类，产品类不需要非得有任何事先确定的等级结构，原始模型模式适用于任何的等级结构。缺点是每一个类都必须配备一个克隆方法。
<p>5、SINGLETON—俺有6个漂亮的老婆，她们的老公都是我，我就是我们家里的老公Sigleton，她们只要说道&#8220;老公&#8221;，都是指的同一个人，那就是我(刚才做了个梦啦，哪有这么好的事)
<p>单例模式：单例模式确保某一个类只有一个实例，而且自行实例化并向整个系统提供这个实例单例模式。单例模式只应在有真正的&#8220;单一实例&#8221;的需求时才可使用。
<p>结构型模式
<p>6、ADAPTER—在朋友聚会上碰到了一个美女Sarah，从香港来的，可我不会说粤语，她不会说普通话，只好求助于我的朋友kent了，他作为我和Sarah之间的Adapter，让我和Sarah可以相互交谈了(也不知道他会不会耍我)
<p>适配器（变压器）模式：把一个类的接口变换成客户端所期待的另一种接口，从而使原本因接口原因不匹配而无法一起工作的两个类能够一起工作。适配类可以根据参数返还一个合适的实例给客户端。
<p>7、BRIDGE—早上碰到MM，要说早上好，晚上碰到MM，要说晚上好；碰到MM穿了件新衣服，要说你的衣服好漂亮哦，碰到MM新做的发型，要说你的头发好漂亮哦。不要问我&#8220;早上碰到MM新做了个发型怎么说&#8221;这种问题，自己用BRIDGE组合一下不就行了
<p>桥梁模式：将抽象化与实现化脱耦，使得二者可以独立的变化，也就是说将他们之间的强关联变成弱关联，也就是指在一个软件系统的抽象化和实现化之间使用组合/聚合关系而不是继承关系，从而使两者可以独立的变化。
<p>8、COMPOSITE—Mary今天过生日。&#8220;我过生日，你要送我一件礼物。&#8221;&#8220;嗯，好吧，去商店，你自己挑。&#8221;&#8220;这件T恤挺漂亮，买，这条裙子好看，买，这个包也不错，买。&#8221;&#8220;喂，买了三件了呀，我只答应送一件礼物的哦。&#8221;&#8220;什么呀，T恤加裙子加包包，正好配成一套呀，小姐，麻烦你包起来。&#8221;&#8220;&#8230;&#8230;&#8221;，MM都会用Composite模式了，你会了没有？
<p>合成模式：合成模式将对象组织到树结构中，可以用来描述整体与部分的关系。合成模式就是一个处理对象的树结构的模式。合成模式把部分与整体的关系用树结构表示出来。合成模式使得客户端把一个个单独的成分对象和由他们复合而成的合成对象同等看待。
<p>9、DECORATOR—Mary过完轮到Sarly过生日，还是不要叫她自己挑了，不然这个月伙食费肯定玩完，拿出我去年在华山顶上照的照片，在背面写上&#8220;最好的的礼物，就是爱你的Fita&#8221;，再到街上礼品店买了个像框（卖礼品的MM也很漂亮哦），再找隔壁搞美术设计的Mike设计了一个漂亮的盒子装起来&#8230;&#8230;，我们都是Decorator，最终都在修饰我这个人呀，怎么样，看懂了吗？
<p>装饰模式：装饰模式以对客户端透明的方式扩展对象的功能，是继承关系的一个替代方案，提供比继承更多的灵活性。动态给一个对象增加功能，这些功能可以再动态的撤消。增加由一些基本功能的排列组合而产生的非常大量的功能。
<p>10、FACADE—我有一个专业的Nikon相机，我就喜欢自己手动调光圈、快门，这样照出来的照片才专业，但MM可不懂这些，教了半天也不会。幸好相机有Facade设计模式，把相机调整到自动档，只要对准目标按快门就行了，一切由相机自动调整，这样MM也可以用这个相机给我拍张照片了。
<p>&nbsp;&nbsp;&nbsp; 门面模式：外部与一个子系统的通信必须通过一个统一的门面对象进行。门面模式提供一个高层次的接口，使得子系统更易于使用。每一个子系统只有一个门面类，而且此门面类只有一个实例，也就是说它是一个单例模式。但整个系统可以有多个门面类。
<p>11、FLYWEIGHT—每天跟MM发短信，手指都累死了，最近买了个新手机，可以把一些常用的句子存在手机里，要用的时候，直接拿出来，在前面加上MM的名字就可以发送了，再不用一个字一个字敲了。共享的句子就是Flyweight，MM的名字就是提取出来的外部特征，根据上下文情况使用。
<p>&nbsp;&nbsp;&nbsp; 享元模式：FLYWEIGHT在拳击比赛中指最轻量级。享元模式以共享的方式高效的支持大量的细粒度对象。享元模式能做到共享的关键是区分内蕴状态和外蕴状态。内蕴状态存储在享元内部，不会随环境的改变而有所不同。外蕴状态是随环境的改变而改变的。外蕴状态不能影响内蕴状态，它们是相互独立的。将可以共享的状态和不可以共享的状态从常规类中区分开来，将不可以共享的状态从类里剔除出去。客户端不可以直接创建被共享的对象，而应当使用一个工厂对象负责创建被共享的对象。享元模式大幅度的降低内存中对象的数量。
<p>12、PROXY—跟MM在网上聊天，一开头总是&#8220;hi,你好&#8221;,&#8220;你从哪儿来呀？&#8221;&#8220;你多大了？&#8221;&#8220;身高多少呀？&#8221;这些话，真烦人，写个程序做为我的Proxy吧，凡是接收到这些话都设置好了自动的回答，接收到其他的话时再通知我回答，怎么样，酷吧。
<p>&nbsp;&nbsp;&nbsp; 代理模式：代理模式给某一个对象提供一个代理对象，并由代理对象控制对源对象的引用。代理就是一个人或一个机构代表另一个人或者一个机构采取行动。某些情况下，客户不想或者不能够直接引用一个对象，代理对象可以在客户和目标对象直接起到中介的作用。客户端分辨不出代理主题对象与真实主题对象。代理模式可以并不知道真正的被代理对象，而仅仅持有一个被代理对象的接口，这时候代理对象不能够创建被代理对象，被代理对象必须有系统的其他角色代为创建并传入。
<p>行为模式
<p>13、CHAIN OF RESPONSIBLEITY—晚上去上英语课，为了好开溜坐到了最后一排，哇，前面坐了好几个漂亮的MM哎，找张纸条，写上&#8220;Hi,可以做我的女朋友吗？如果不愿意请向前传&#8221;，纸条就一个接一个的传上去了，糟糕，传到第一排的MM把纸条传给老师了，听说是个老处女呀，快跑!
<p>&nbsp;&nbsp; 责任链模式：在责任链模式中，很多对象由每一个对象对其下家的引用而接
<p>&nbsp;&nbsp;&nbsp; 起来形成一条链。请求在这个链上传递，直到链上的某一个对象决定处理此请求。客户并不知道链上的哪一个对象最终处理这个请求，系统可以在不影响客户端的情况下动态的重新组织链和分配责任。处理者有两个选择：承担责任或者把责任推给下家。一个请求可以最终不被任何接收端对象所接受。
<p>14、COMMAND—俺有一个MM家里管得特别严，没法见面，只好借助于她弟弟在我们俩之间传送信息，她对我有什么指示，就写一张纸条让她弟弟带给我。这不，她弟弟又传送过来一个COMMAND，为了感谢他，我请他吃了碗杂酱面，哪知道他说：&#8220;我同时给我姐姐三个男朋友送COMMAND，就数你最小气，才请我吃面。&#8221;，:-(
<p>&nbsp;&nbsp;&nbsp; 命令模式：命令模式把一个请求或者操作封装到一个对象中。命令模式把发出命令的责任和执行命令的责任分割开，委派给不同的对象。命令模式允许请求的一方和发送的一方独立开来，使得请求的一方不必知道接收请求的一方的接口，更不必知道请求是怎么被接收，以及操作是否执行，何时被执行以及是怎么被执行的。系统支持命令的撤消。
<p>15、INTERPRETER—俺有一个《泡MM真经》，上面有各种泡MM的攻略，比如说去吃西餐的步骤、去看电影的方法等等，跟MM约会时，只要做一个Interpreter，照着上面的脚本执行就可以了。
<p>&nbsp;&nbsp;&nbsp; 解释器模式：给定一个语言后，解释器模式可以定义出其文法的一种表示，并同时提供一个解释器。客户端可以使用这个解释器来解释这个语言中的句子。解释器模式将描述怎样在有了一个简单的文法后，使用模式设计解释这些语句。在解释器模式里面提到的语言是指任何解释器对象能够解释的任何组合。在解释器模式中需要定义一个代表文法的命令类的等级结构，也就是一系列的组合规则。每一个命令对象都有一个解释方法，代表对命令对象的解释。命令对象的等级结构中的对象的任何排列组合都是一个语言。
<p>16、ITERATOR—我爱上了Mary，不顾一切的向她求婚。
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Mary：&#8220;想要我跟你结婚，得答应我的条件&#8221;
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 我：&#8220;什么条件我都答应，你说吧&#8221;
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Mary：&#8220;我看上了那个一克拉的钻石&#8221;
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 我：&#8220;我买，我买，还有吗？&#8221;
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Mary：&#8220;我看上了湖边的那栋别墅&#8221;
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 我：&#8220;我买，我买，还有吗？&#8221;
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Mary：&#8220;你的小弟弟必须要有50cm长&#8221;
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 我脑袋嗡的一声，坐在椅子上，一咬牙：&#8220;我剪，我剪，还有吗？&#8221;
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8230;&#8230;
<p>&nbsp;&nbsp;&nbsp; 迭代子模式：迭代子模式可以顺序访问一个聚集中的元素而不必暴露聚集的内部表象。多个对象聚在一起形成的总体称之为聚集，聚集对象是能够包容一组对象的容器对象。迭代子模式将迭代逻辑封装到一个独立的子对象中，从而与聚集本身隔开。迭代子模式简化了聚集的界面。每一个聚集对象都可以有一个或一个以上的迭代子对象，每一个迭代子的迭代状态可以是彼此独立的。迭代算法可以独立于聚集角色变化。
<p>17、MEDIATOR—四个MM打麻将，相互之间谁应该给谁多少钱算不清楚了，幸亏当时我在旁边，按照各自的筹码数算钱，赚了钱的从我这里拿，赔了钱的也付给我，一切就OK啦，俺得到了四个MM的电话。
<p>&nbsp;&nbsp;&nbsp; 调停者模式：调停者模式包装了一系列对象相互作用的方式，使得这些对象不必相互明显作用。从而使他们可以松散偶合。当某些对象之间的作用发生改变时，不会立即影响其他的一些对象之间的作用。保证这些作用可以彼此独立的变化。调停者模式将多对多的相互作用转化为一对多的相互作用。调停者模式将对象的行为和协作抽象化，把对象在小尺度的行为上与其他对象的相互作用分开处理。
<p>18、MEMENTO—同时跟几个MM聊天时，一定要记清楚刚才跟MM说了些什么话，不然MM发现了会不高兴的哦，幸亏我有个备忘录，刚才与哪个MM说了什么话我都拷贝一份放到备忘录里面保存，这样可以随时察看以前的记录啦。
<p>&nbsp;&nbsp;&nbsp; 备忘录模式：备忘录对象是一个用来存储另外一个对象内部状态的快照的对象。备忘录模式的用意是在不破坏封装的条件下，将一个对象的状态捉住，并外部化，存储起来，从而可以在将来合适的时候把这个对象还原到存储起来的状态。
<p>19、OBSERVER—想知道咱们公司最新MM情报吗？加入公司的MM情报邮件组就行了，tom负责搜集情报，他发现的新情报不用一个一个通知我们，直接发布给邮件组，我们作为订阅者（观察者）就可以及时收到情报啦
<p>&nbsp;&nbsp;&nbsp; 观察者模式：观察者模式定义了一种一队多的依赖关系，让多个观察者对象同时监听某一个主题对象。这个主题对象在状态上发生变化时，会通知所有观察者对象，使他们能够自动更新自己。
<p>20、STATE—跟MM交往时，一定要注意她的状态哦，在不同的状态时她的行为会有不同，比如你约她今天晚上去看电影，对你没兴趣的MM就会说&#8220;有事情啦&#8221;，对你不讨厌但还没喜欢上的MM就会说&#8220;好啊，不过可以带上我同事么？&#8221;，已经喜欢上你的MM就会说&#8220;几点钟？看完电影再去泡吧怎么样？&#8221;，当然你看电影过程中表现良好的话，也可以把MM的状态从不讨厌不喜欢变成喜欢哦。
<p>&nbsp;&nbsp;&nbsp; 状态模式：状态模式允许一个对象在其内部状态改变的时候改变行为。这个对象看上去象是改变了它的类一样。状态模式把所研究的对象的行为包装在不同的状态对象里，每一个状态对象都属于一个抽象状态类的一个子类。状态模式的意图是让一个对象在其内部状态改变的时候，其行为也随之改变。状态模式需要对每一个系统可能取得的状态创立一个状态类的子类。当系统的状态变化时，系统便改变所选的子类。
<p>21、STRATEGY—跟不同类型的MM约会，要用不同的策略，有的请电影比较好，有的则去吃小吃效果不错，有的去海边浪漫最合适，单目的都是为了得到MM的芳心，我的追MM锦囊中有好多Strategy哦。
<p>&nbsp;&nbsp;&nbsp; 策略模式：策略模式针对一组算法，将每一个算法封装到具有共同接口的独立的类中，从而使得它们可以相互替换。策略模式使得算法可以在不影响到客户端的情况下发生变化。策略模式把行为和环境分开。环境类负责维持和查询行为类，各种算法在具体的策略类中提供。由于算法和环境独立开来，算法的增减，修改都不会影响到环境和客户端。
<p>22、TEMPLATE METHOD——看过《如何说服女生上床》这部经典文章吗？女生从认识到上床的不变的步骤分为巧遇、打破僵局、展开追求、接吻、前戏、动手、爱抚、进去八大步骤(Template method)，但每个步骤针对不同的情况，都有不一样的做法，这就要看你随机应变啦(具体实现)；
<p>&nbsp;&nbsp;&nbsp; 模板方法模式：模板方法模式准备一个抽象类，将部分逻辑以具体方法以及具体构造子的形式实现，然后声明一些抽象方法来迫使子类实现剩余的逻辑。不同的子类可以以不同的方式实现这些抽象方法，从而对剩余的逻辑有不同的实现。先制定一个顶级逻辑框架，而将逻辑的细节留给具体的子类去实现。
<p>23、VISITOR—情人节到了，要给每个MM送一束鲜花和一张卡片，可是每个MM送的花都要针对她个人的特点，每张卡片也要根据个人的特点来挑，我一个人哪搞得清楚，还是找花店老板和礼品店老板做一下Visitor，让花店老板根据MM的特点选一束花，让礼品店老板也根据每个人特点选一张卡，这样就轻松多了；
<p>&nbsp;&nbsp;&nbsp; 访问者模式：访问者模式的目的是封装一些施加于某种数据结构元素之上的操作。一旦这些操作需要修改的话，接受这个操作的数据结构可以保持不变。访问者模式适用于数据结构相对未定的系统，它把数据结构和作用于结构上的操作之间的耦合解脱开，使得操作集合可以相对自由的演化。访问者模式使得增加新的操作变的很容易，就是增加一个新的访问者类。访问者模式将有关的行为集中到一个访问者对象中，而不是分散到一个个的节点类中。当使用访问者模式时，要将尽可能多的对象浏览逻辑放在访问者类中，而不是放到它的子类中。访问者模式可以跨过几个类的等级结构访问属于不同的等级结构的成员类。&nbsp;
<h4><a href="http://www.blogjava.net/JavaExplore/archive/2006/08/24/65629.html">《java与模式》笔记(zz)</a></h4>
<p>虽然自认为自己对设计模式已经很了解了,但是从来没有系统的看过设计模式相关的书,最近在公司发现一本&lt;java与模式&gt;,正好系统的看一下,下面是这几天记的笔记.(并不是系统的讲解书中的内容)<br />
一&nbsp; 综述:<br />
1、不要使用接口定义常量<br />
2、自己少用标志接口<br />
3、不要继承具体类<br />
4、类层次的中间节点应该是接口或者抽象类，叶子是具体类<br />
5、子类应当扩展父类的责任，而不是覆写父类的责任<br />
6、面向接口编程<br />
7、不要滥用继承，组合优先于继承
<p>java中设计不当的类：calendar:作为接口，含有与具体的历法（罗马历法）相关的常量，不能扩展到中国的阴历历法（不符合开闭原则）<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; properies类：滥用继承，继承至hashtable，应当使用聚合
<p>8、笛比特法则：只与自己的直接朋友通信，不与陌生人通信（1）狭义笛比特法则：只与朋友通讯，通过自己的朋友传递间接的调用（2）结合依赖倒转原则修改：不必通过朋友传递间接的调用，通过陌生人的抽象接口调用陌生人的行为（依旧不能与具体的陌生人发生通信）<br />
9、尽量降低类中成员的访问权限，不要设计退化类（类似c中struct）。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; java中的point2D以及Dinmension2D类有这种设计缺陷（不过这种情况问题不大）<br />
10、如果多个具体的产品类没有共同的商业逻辑，就可以把它们抽象到一个接口中，如果有共同的商业逻辑，就把共同的部分抽象到抽象类中，共同的部分尽量向类继承层次的上层移动，以达到复用的目的<br />
二&nbsp;&nbsp; 工厂模式<br />
1、简单工厂模式：参与角色：工厂/抽象产品类/具体产品类
<p>&nbsp;&nbsp; 缺点：添加新产品的时候，虽然产品相关代码符合开闭原则，但对工厂类本身并不符合，需要修改其中的产生产品方法或者添加新的产生方法（工厂里实现的不同造成的修改不同）来支持新的产品类<br />
&nbsp;&nbsp; 退化方式：省略掉工厂角色，抽象产品类担任具体产品类的工厂角色：提供静态的getInstance方法，比如java类库中的DateFormat类，（本人认为这样很不符合开闭原则，父类中出现与具体子类相关的代码，不方便扩展，添加新产品的时候，修改的时候缺点与原简单工厂的工厂角色类似）
<p>2、工厂方法模式：参与角色：抽象工厂类/具体工厂类/抽象产品类/具体产品类<br />
&nbsp;&nbsp;&nbsp;&nbsp; 消除了简单工厂的缺点
<p>3、抽象工厂模式：简单工厂模式与工厂方法模式的结合
<p>4、单例模式：饿汉和懒汉两种，前者将本身对象作为静态私有属性事先生成，后者推迟到调用的时候，后者需要考虑多线程的时候，前面需要加线程安全关键字（注意），java中还是前者为优。<br />
&nbsp;&nbsp; 不要滥用单例，只有系统要求只有一个类的实例的时候才调用<br />
&nbsp;&nbsp; 有的单例可能有状态属性，这就为多例模式提供了可能<br />
&nbsp;&nbsp; 含有私有属性的类作成单例的时候尤其要注意：一是私有属性的线程安全，确实需要的时候可以加线程安全关键字，比如系统中的log类，二是确认这些属性是不是可以所有线程共享的，类似普通类的static<br />
三&nbsp;&nbsp; 各种具体模式（1）<br />
1、建造模式：参与角色4个：指导者、抽象建造对象、具体建造对象、产品<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一个复杂的产品有很多的零部件，就可以使用具体的建造对象来一一构造<br />
2、原始模式：深拷贝、浅拷贝<br />
3、适配器模式：将adaptee类适配成目标接口<br />
4、合成模式：参与角色：composite接口、树枝节点类、树叶节点类<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 分成透明式和安全式两种，各有优缺点<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (1)前者将管理子对象的方法放到接口中，这样树型结构中的所有对象都是透明的，都可以统一调用，但是叶节点并没有管理子对象的能力，因此透明但不安全<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (2)后者将管理子对象的方法下放到树枝节点类中，这样安全但不透明<br />
5、装饰模式：继承已有类的接口，提供和已有类相同的方法，并对已有类的功能提供扩展（通过组合已有对象，调用已有对象方法的时候加入新的代码）<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (1)透明的装饰模式（纯粹的装饰模式）：装饰类、被装饰类继承于同一接口，而且装饰类只实现接口的方法，不提供额外方法的实现，调用该类的时候使用接口声明调用（实例化当然还是自己的构造函数），即该类的所有方法都是透明的<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (2)半透明的装饰模式（退化的装饰模式）：装饰类、被装饰类继承于同一接口，装饰类不仅实现接口的方法，还提供额外方法的实现，这样要调用它独特的方法的时候就必须使用它本身来调用，退化到一半装饰模式、一半适配器模式。</p>
<img src ="http://www.blogjava.net/bacoo/aggbug/169175.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/bacoo/" target="_blank">bacoo</a> 2007-12-20 23:18 <a href="http://www.blogjava.net/bacoo/archive/2007/12/20/169175.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转载]Java安装后JDK/bin目录下的exe文件的用途</title><link>http://www.blogjava.net/bacoo/archive/2007/12/20/169173.html</link><dc:creator>bacoo</dc:creator><author>bacoo</author><pubDate>Thu, 20 Dec 2007 15:17:00 GMT</pubDate><guid>http://www.blogjava.net/bacoo/archive/2007/12/20/169173.html</guid><wfw:comment>http://www.blogjava.net/bacoo/comments/169173.html</wfw:comment><comments>http://www.blogjava.net/bacoo/archive/2007/12/20/169173.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/bacoo/comments/commentRss/169173.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/bacoo/services/trackbacks/169173.html</trackback:ping><description><![CDATA[<p><strong>javac：</strong>Java编译器，将Java源代码换成字节代 <br />
<strong>java：</strong>Java解释器，直接从类文件执行Java应用程序代码 <br />
<strong>appletviewer(小程序浏览器)：</strong>一种执行HTML文件上的Java小程序类的Java浏览器 <br />
<strong>javadoc：</strong>根据Java源代码及其说明语句生成的HTML文档 <br />
<strong>jdb：</strong>Java调试器，可以逐行地执行程序、设置断点和检查变量 <br />
<strong>javah：</strong>产生可以调用Java过程的C过程，或建立能被Java程序调用的C过程的头文件 <br />
<strong>Javap：</strong>Java反汇编器，显示编译类文件中的可访问功能和数据，同时显示字节代码含义 <br />
<strong>jar：</strong>多用途的存档及压缩工具，是个java应用程序，可将多个文件合并为单个JAR归档文件。 <br />
<strong>htmlConverter：</strong>命令转换工具。 <br />
<strong>native2ascii：</strong>将含有不是Unicode或Latinl字符的的文件转换为Unicode编码字符的文件。 <br />
<strong>serialver：</strong>返回serialverUID。语法：serialver [show] 命令选项show是用来显示一个简单的界面。输入完整的类名按Enter键或"显示"按钮，可显示serialverUID。 <br />
<strong>补充详细：</strong><br />
<strong>javac.exe</strong>
<p>用法：javac &lt;选项&gt; &lt;源文件&gt; <br />
可能的选项包括： <br />
-g 生成所有调试信息 <br />
-g:none 生成无调试信息 <br />
-g:{lines,vars,source} 生成只有部分调试信息 <br />
-O 优化；可能妨碍调试或者增大类文件 <br />
-nowarn 生成无警告 <br />
-verbose 输出关于编译器正在做的信息 <br />
-deprecation 输出使用了不鼓励使用的API的源程序位置 <br />
-classpath &lt;路径&gt; 指定用户类文件的位置 <br />
-sourcepath &lt;路径&gt; 指定输入源文件的位置 <br />
-bootclasspath &lt;路径&gt; 覆盖自举类文件的位置 <br />
-extdirs &lt;目录(多个)&gt; 覆盖安装的扩展类的位置 <br />
-d &lt;目录&gt; 指定输出类文件的位置 <br />
-encoding &lt;编码&gt; 指定源文件中所用的字符集编码 <br />
-target &lt;版本&gt; 生成指定虚拟机版本的类文件 <br />
-help Print a synopsis of standard options
<p><strong>appletviewer.exe</strong>
<p>用法：appletviewer &lt;options&gt; url <br />
其中，&lt;options&gt; 包括： <br />
-debug 在 Java 调试器中启动 applet 小程序查看器 <br />
-encoding &lt;encoding&gt; 指定由 HTML 文件使用的字符编码 <br />
-J&lt;runtime flag&gt; 向 Java 解释器传递参数 <br />
-J 选项不是标准选项，如有更改，不另行通知。
<p><strong>jar.exe</strong>
<p>用法：jar {ctxu}[vfm0M] [jar-文件] [manifest-文件] [-C 目录] 文件名 ... <br />
选项： <br />
-c 创建新的存档 <br />
-t 列出存档内容的列表 <br />
-x 展开存档中的命名的（或所有的〕文件 <br />
-u 更新已存在的存档 <br />
-v 生成详细输出到标准输出上 <br />
-f 指定存档文件名 <br />
-m 包含来自标明文件的标明信息 <br />
-0 只存储方式；未用ZIP压缩格式 <br />
-M 不产生所有项的清单（manifest〕文件 <br />
-i 为指定的jar文件产生索引信息 <br />
-C 改变到指定的目录，并且包含下列文件： <br />
如果一个文件名是一个目录，它将被递归处理。 <br />
清单（manifest〕文件名和存档文件名都需要被指定，按'm' 和 'f'标志指定的相同顺序。 <br />
示例1：将两个class文件存档到一个名为 'classes.jar' 的存档文件中： <br />
jar cvf classes.jar Foo.class Bar.class <br />
示例2：用一个存在的清单（manifest）文件 'mymanifest' 将 foo/ 目录下的所有 <br />
文件存档到一个名为 'classes.jar' 的存档文件中： <br />
jar cvfm classes.jar mymanifest -C foo/ .
<p><strong>javadoc.exe</strong>
<p>用法：javadoc [options] [packagenames] [sourcefiles] [classnames] [@files] <br />
-overview &lt;file&gt; 读取 HTML 格式的概述文档 <br />
-public 仅显示 public 类和成员 <br />
-protected 显示 protected/public 类和成员（缺省） <br />
-package 显示 package/protected/public 类和成员 <br />
-private 显示所有类和成员 <br />
-help 显示命令行选项 <br />
-doclet &lt;class&gt; 通过候选 doclet 生成输出 <br />
-docletpath &lt;path&gt; 指定 doclet 类文件的查找位置 <br />
-sourcepath &lt;pathlist&gt; 指定源文件的查找位置 <br />
-classpath &lt;pathlist&gt; 指定用户类文件的查找位置 <br />
-exclude &lt;pkglist&gt; Specify a list of packages to exclude <br />
-subpackages &lt;subpkglist&gt; Specify subpackages to recursively load <br />
-breakiterator Compute 1st sentence with BreakIterator <br />
-bootclasspath &lt;pathlist&gt; 覆盖自举类加载器所加载的类文件的位置 <br />
-source &lt;release&gt; Provide source compatibility with specified release <br />
-extdirs &lt;dirlist&gt; 覆盖已安装的扩展的位置 <br />
-verbose 有关 Javadoc 所做工作的输出信息 <br />
-locale &lt;name&gt; 所用的 Locale，例如 en_US 或 en_US_WIN <br />
-encoding &lt;name&gt; 源文件编码名称 <br />
-J&lt;flag&gt; 将 &lt;flag&gt; 直接传给运行时系统 <br />
由标准 doclet 提供： <br />
-d &lt;directory&gt; 输出文件的目标目录 <br />
-use 创建类和包的用法页 <br />
-version 包含 @version 段 <br />
-author 包含 @author 段 <br />
-docfilessubdirs Recursively copy doc-file subdirectories <br />
-splitindex 将索引分为每个字母对应一个文件 <br />
-windowtitle &lt;text&gt; 文档的浏览器窗口标题 <br />
-doctitle &lt;html-code&gt; 包含包索引页（首页）的标题 <br />
-header &lt;html-code&gt; 包含每一页的页眉文本 <br />
-footer &lt;html-code&gt; 包含每一页的页脚文本 <br />
-bottom &lt;html-code&gt; 包含每一页的页底文本 <br />
-link &lt;url&gt; Create links to javadoc output at &lt;url&gt; <br />
-linkoffline &lt;url&gt; &lt;url2&gt; Link to docs at &lt;url&gt; using package list at &lt;url2&gt; <br />
-excludedocfilessubdir &lt;name1&gt;:.. Exclude any doc-files subdirectories with given name. <br />
-group &lt;name&gt; &lt;p1&gt;:&lt;p2&gt;.. Group specified packages together in overview page <br />
-nocomment Supress description and tags, generate only declarations. <br />
-nodeprecated 不包含 @deprecated 信息 <br />
-noqualifier &lt;name1&gt;:&lt;name2&gt;:... Exclude the list of qualifiers from the output. <br />
-nosince Do not include @since information <br />
-nodeprecatedlist 不生成不鼓励使用的列表 <br />
-notree 不生成类层次 <br />
-noindex 不生成索引 <br />
-nohelp 不生成帮助链接 <br />
-nonavbar 不生成导航栏 <br />
-quiet Do not display status messages to screen <br />
-serialwarn Generate warning about @serial tag <br />
-tag &lt;name&gt;:&lt;locations&gt;:&lt;header&gt; Specify single argument custom tags <br />
-taglet The fully qualified name of Taglet to register <br />
-tagletpath The path to Taglets <br />
-charset &lt;charset&gt; Charset for cross-platform viewing of generated documentation. <br />
-helpfile &lt;file&gt; 包含帮助链接功能链接到目标的文件 <br />
-linksource Generate source in HTML <br />
-stylesheetfile &lt;path&gt; 改变所生成文档的样式的文件 <br />
-docencoding &lt;name&gt; 输出编码名称
<p><strong>javah.exe</strong>
<p>用法：javah [options] &lt;classes&gt; <br />
其中 [options] 包括：<br />
-help 打印该帮助信息 <br />
-classpath &lt;path&gt; 类的加载路径 <br />
-bootclasspath &lt;path&gt; 自举类的加载路径 <br />
-d &lt;dir&gt; 输出目录 <br />
-o &lt;file&gt; 输出文件（仅能使用 -d 或 -o 之一） <br />
-jni 生成 JNI 风格的头文件（缺省） <br />
-old 生成 JDK1.0 风格的头文件 <br />
-stubs 生成 stubs 文件 <br />
-version 打印版本信息 <br />
-verbose 输出有关本命令所做工作的信息 <br />
-force 始终写输出文件 <br />
指定 &lt;classes&gt; 时必须使用全名（例如 java.lang.Object）。
<p><strong>javaw.exe </strong>
<p>HtmlConverter.exe <br />
用法：HtmlConverter [-option1 value1 [-option2 value2 [...]]] [-simulate] [filespecs] <br />
其中，选项包括：<br />
-source: 获取源文件的路径。 缺省值： &lt;userdir&gt; <br />
-dest: 写入已转换文件的路径。 缺省值： &lt;userdir&gt; <br />
-backup: 写备份文件的路径。 缺省值： &lt;dirname&gt;_BAK <br />
-f: 强制覆写备份文件。 <br />
-subdirs: 应处理子目录中的文件。 <br />
-template: 模板文件的路径。 如果不确定，请使用缺省值。 <br />
-log: 写日志的路径。 如果没有提供，则不会写入任何日志。 <br />
-progress: 转换时显示进度。 缺省值： true <br />
-simulate: 在没有进行转换时显示特定于转换的信息。 <br />
-latest: 使用最新的 JRE 支持发行版 mimetype。 <br />
-gui: 显示转换程序的图形用户界面。 <br />
filespecs: 用空格分开的文件说明列表。 缺省值： "*.html *.htm" （需要引号）
<p><strong>orbd.exe</strong>
<p>用法：orbd &lt;选项&gt; <br />
其中，&lt;选项&gt; 包括： <br />
-port 启动 ORBD 的激活端口，缺省值为 1049 (可选) <br />
-defaultdb ORBD 文件的目录，缺省值为 "./orb.db" (可选) <br />
-serverid ORBD 的服务器标识符，缺省值为 1 (可选) <br />
-ORBInitialPort 初始端口（必需） <br />
-ORBInitialHost 初始主机名称（必需）
<p><strong>policytool.exe</strong>
<p>用法：policytool [选项] <br />
[-file &lt;file&gt;] 规则文件位置
<p><strong>rmic.exe</strong>
<p>用法：rmic &lt;选项&gt; &lt;类名&gt;<br />
其中 &lt;选项&gt; 包括： <br />
-keep 不删除中间生成的源文件 <br />
-keepgenerated （同 "-keep") <br />
-v1.1 为 1.1 stub 协议版本创建 stubs/skeleton <br />
-vcompat （缺省）创建与 1.1 和 <br />
1.2 stub 协议版本兼容的 stubs/skeleton <br />
-v1.2 仅为 1.2 stub 协议版本创建 stubs <br />
-iiop 为 IIOP 创建 stubs。当使用该选项时，&lt;选项&gt;还应包括： <br />
-always 总创建 stubs （即使在它们同时出现时〕 <br />
-alwaysgenerate (同 "-always") <br />
-nolocalstubs 不创建为同一进程优化的 stubs <br />
-idl 创建 IDL。当使用该选项时，&lt;选项&gt;还应包括： <br />
-noValueMethods 不生成值类型的方法 <br />
-always 总创建 IDL （即使在它们同时出现时〕 <br />
-alwaysgenerate (同 "-always") <br />
-g 一般调试信息 <br />
-depend 以递归方式重编译过期的文件 <br />
-nowarn 不警告 <br />
-nowrite 不将编译过的类写入到文件系统 <br />
-verbose 输出有关编译器所做工作的信息 <br />
-classpath &lt;path&gt; 指定输入源和类文件的查找位置 <br />
-sourcepath &lt;path&gt; 指定用户源文件的查找位置 <br />
-bootclasspath &lt;path&gt; 覆盖自举类文件的位置 <br />
-extdirs &lt;path&gt; 覆盖安装扩展类的位置 <br />
-d &lt;directory&gt; 指定所生成类文件的放置位置 <br />
-J&lt;runtime flag&gt; 将参数传给 java 解释程序
<p><strong>rmid.exe</strong>
<p>用法：rmid &lt;option&gt; <br />
其中，&lt;option&gt; 包括: <br />
-port &lt;option&gt; 指定供 rmid 使用的端口 <br />
-log &lt;directory&gt; 指定 rmid 将日志写入的目录 <br />
-stop 停止当前的 rmid 调用（对指定端口） <br />
-C&lt;runtime 标记&gt; 向每个子进程传递参数（激活组） <br />
-J&lt;runtime 标记&gt; 向 java 解释程序传递参数
<p><strong>rmiregistry.exe</strong>
<p>用法： rmiregistry &lt;选项&gt; &lt;端口&gt;<br />
其中，&lt;选项&gt; 包括： <br />
-J&lt;runtime 标记&gt; 将参数传递到 java 解释程序
<p><strong>serialver.exe</strong>
<p>用法：serialver [-classpath classpath] [-show] [classname...]
<p><strong>servertool.exe</strong>
<p>欢迎使用 Java IDL 服务器工具 <br />
请在提示处输入命令<br />
servertool &gt; help <br />
可用命令： <br />
register - 注册一个可激活的服务器 <br />
unregister - 取消服务器注册 <br />
getserverid - 返回应用程序名称的服务器标识符 <br />
list - 列举所有已注册服务器 <br />
listappnames - 列举当前定义的应用程序名称 <br />
listactive - 列举当前活动的服务器 <br />
locate - 将已注册服务器定位在特定类型的端口 <br />
locateperorb - 为已注册服务器的特定对象请求代理程序定位端口。 <br />
orblist - 对象请求代理程序 (orb) 名称及其映射列表 <br />
shutdown - 关闭一个已注册服务器 <br />
startup - 启动一个已注册服务器 <br />
help - 取得帮助 <br />
quit - 退出此工具
<p><strong>rmic</strong>
<p>功能说明： <br />
rmic 为远程对象生成 stub 和 skeleton。 <br />
语法： <br />
rmic [ options ] package-qualified-class-name(s) <br />
补充说明： <br />
rmic 编译器根据编译后的 Java 类（含有远程对象实现）名，为远程对象生成 stub 和 skeleton（远程对象是指实现 java.rmi.Remote 接口的对象）。在 rmic 命令中所给的类必须是经 javac 命令成功编译且是完全包限定的类。 <br />
命令选项 <br />
-classpath[路径] 指定 rmic 用于查询类的路径。如果设置了该选项，它将覆盖缺省值或 CLASSPATH 环境变量。目录用冒号分隔。 <br />
-d[目录] 指定类层次的根目录。此选项可用来指定 stub 和 skeleton 文件的目标目录。 <br />
-depend 使编译器考虑重新编译从其它类引用的类。 一般来说，它只重新编译从源代码引用的遗漏或过期的类。 <br />
-g 允许生成调试表格。调试表格含有行号和局部变量的有关信息，即 Java 调试工具所使用的信息。缺省情况下，只生成行号。 <br />
-J 与 -D 选项联用，它将紧跟其后的选项（ -J 与 -D 之间无空格）传给 java 解释器。 <br />
-keepgenerated 为 stub 和 skeleton 文件保留所生成的 .java 源文件，并将这些源文件写到与 .class 文件相同的目录中，如果要指定目录，则使用 -d 选项。 <br />
-nowarn 关闭警告。如果使用该选项，则编译器不输出任何警告信息。 <br />
-show 显示 rmic 编译器的 GUI（图形用户界面）。输入一个或多个包限定类名（以空格分隔），并按回车键或&#8220;显示&#8221;按钮，创建 stub 和 skeleton。 <br />
-vcompat （缺省值）创建与 JDK 1.1 和 1.2 stub 协议版本都兼容的 stub 和 skeleton。 <br />
-verbose 使编译器和链接器输出关于正在编译哪些类和正在加载哪些类文件的信息。 <br />
-v1.1 创建 JDK 1.1 stub 协议版本的 stub 和 skeleton。 <br />
-v1.2 只创建 JDK 1.2 stub 协议版本的 stub。
<p><strong>rmid</strong>
<p>功能说明： <br />
rmid 启动激活系统守护进程，以便能够在 Java 虚拟机上注册和激活对象。 <br />
语法： <br />
rmid [-port port] [-log dir] <br />
补充说明： <br />
rmid 工具启动激活系统守护进程。必须先启动激活系统守护进程，才能向激活系统注册可被激活的对象或在 Java 虚拟机上激活可被激活的对象。 <br />
命令选项 <br />
-C&lt;某些命令行选项&gt; 指定一个选项，在创建每个 rmid 的子守护进程（激活组）时，该选项以命令行参数的形式传给该子守护进程。 <br />
-log[目录] 指定目录的名称，激活系统守护进程在该目录中写入其数据库及相关信息。缺省状态下，将在执行 rmid 命令的目录中创建一个 log 目录。 <br />
-port[端口] 指定 rmid 的注册服务程序所使用的端口。激活系统守护进程将 ActivationSystem 与该注册服务程序中的名称java.rmi.activation.ActivationSystem 捆绑在一起。 <br />
-stop 停止 -port 选项所指定端口上的当前 rmid 调用。若未指定端口，则将停止在端口 1098 上运行的 rmid。
<p><strong>rmiregistry</strong>
<p>功能说明： <br />
rmiregistry 命令可在当前主机的指定端口上启动远程对象注册服务程序。 <br />
语法： <br />
rmiregistry [port] <br />
补充说明： <br />
rmiregistry 命令在当前主机的指定 port 上创建并启动远程对象注册服务程序。如果省略 port，则注册服务程序将在 1099 端口上启动。rmiregistry 命令不产生任何输出而且一般在后台运行。远程对象注册服务程序是自举命名服务。主机上的 RMI 服务器将利用它将远程对象绑定到名字上。客户机即可查询远程对象并进行远程方法调用。注册服务程序一般用于定位应用程序需调用其方法的第一个远程对象。该对象反过来对各应用程序提供相应的支持，用于查找其它对象。java.rmi.registry.LocateRegistry 类的方法可用于在某台主机或主机和端口上获取注册服务程序操作。java.rmi.Naming 类的基于 URL 的方法将对注册服务程序进行操作，并可用于查询远程对象、将简单（字符串）名称绑定到远程对象、将新名称重新绑定到远程对象（覆盖旧绑定）、取消远程对象的绑定以及列出绑定在注册服务程序上的 URL。
<p><strong>serialver </strong>
<p>功能说明： <br />
serialver 命令返回 serialVersionUID。 <br />
语法： <br />
serialver [ 命令选项 ] <br />
补充说明： <br />
serialver 以适于复制到演变类的形式返回一个或多个类的 serialVersionUID。不带参数调用时，它输出用法行。 <br />
命令选项 <br />
-show 显示一个简单的用户界面。输入完整的类名并按回车键或&#8220;显示&#8221;按钮可显示 serialVersionUID。
<p><strong>jarsigner</strong>
<p>功能说明： <br />
为 Java 归档 (JAR) 文件产生签名，并校验已签名的 JAR 文件的签名。 <br />
语法： <br />
jarsigner [ 命令选项 ] jar-file alias <br />
jarsigner -verify [ 命令选项 ] jar-file <br />
补充说明： <br />
jarsigner 工具用于两个目的： <br />
1:为 Java 归档 (JAR) 文件签名 <br />
2:校验已签名的 JAR 文件的签名和完整性 <br />
命令选项 <br />
-keystore[url] 指定密钥仓库的 URL。缺省值是用户的宿主目录中的 .keystore 文件，它由系统属性&#8220;user.home&#8221;决定。 <br />
-storetype[storetype] 指定要被实例化的密钥仓库类型。默认的密钥仓库类型是安全属性文件中 "keystore.type" 属性值所指定的那个类型，由 java.security.KeyStore 中的静态方法 getDefaultType 返回。 <br />
-storepass[password] 指定访问密钥仓库所需的口令。这仅在签名（不是校验）JAR 文件时需要。在这种情况下，如果命令行中没有提供 -storepass 选项，用户将被提示输入口令。 <br />
-keypass[password] 指定用于保护密钥仓库项（由命令行中指定的别名标出）的私钥的口令。使用 jarsigner 为 JAR 文件签名时需要该口令。如果命令行中没有提供口令，且所需的口令与密钥仓库的口令不同，则将提示用户输入它。 <br />
-sigfile[file] 指定用于生成 .SF 和 .DSA 文件的基本文件名。 <br />
-signedjar[file] 指定用于已签名的 JAR 文件的名称。 <br />
-verify 如果它出现在命令行中，则指定的 JAR 文件将被校验，而不是签名。如果校验成功，将显示&#8220;jar verified&#8221;。如果试图校验未签名的 JAR 文件，或校验被不支持的算法（例如未安装 RSA 提供者时使用的 RSA）签名的 JAR 文件，则将有如下显示： "jar is unsigned. (signatures missing or not parsable)" 。 <br />
-certs 如果它与 -verify 和 -verbose 选项一起出现在命令行中，则输出将包括 JAR 文件的每个签名人的证书信息。 <br />
-verbose 如果它出现在命令行中，则代表&#8220;verbose&#8221;模式，它使 jarsigner 在 JAR 签名或校验过程中输出额外信息。 <br />
-internalsf 过去，JAR 文件被签名时产生的 .DSA（签名块）文件包含一个同时产生的 .SF 文件（签名文件）的完整编码副本。这种做法已被更改。为了减小输出 JAR 文件的整个大小，缺省情况下 .DSA 文件不再包含 .SF 文件的副本。但是如果 -internalsf 出现在命令行中，将采用旧的做法。该选项主要在测试时有用；实际上不应使用它，因为这样将消除有用的优化。 <br />
-sectionsonly 如果它出现在命令行中，则 JAR 文件被签名时生成的 .SF 文件（签名文件）将不包括含有整个清单文件的散列的头。它仅包含 与 JAR 中每个单独的源文件相关的信息和散列。该选项主要在测试时有用；实际上不应使用它，因为这样将消除有用的优化。 <br />
-J[javaoption] 将指定的 javaoption 串直接传递到 Java 解释器。(（jarsigner 实际上是解释器的一个 &#8220;wrapper&#8221;）。该选项不应含有任何空格。它有助于调整执行环境或内存使用。要获得可用的解释器选项的清单，可在命令行键入 java -h 或 java -X。
<p><strong>keytool</strong>
<p>功能说明： <br />
管理由私钥和认证相关公钥的 X.509 证书链组成的密钥仓库（数据库）。还管理来自可信任实体的证书。 <br />
语法： <br />
keytool [ 命令 ] <br />
补充说明： <br />
keytool 是个密钥和证书管理工具。它使用户能够管理自己的公钥/私钥对及相关证书，用于（通过数字签名）自我认证（用户向别的用户/服务认证自己）或数据完整性以及认证服务。它还允许用户储存他们的通信对等者的公钥（以证书形式）。
<p><strong>native2ascii</strong>
<p>功能说明： <br />
将含有本地编码字符（既非 Latin1 又非 Unicode 字符）的文件转换为 Unicode 编码字符的文件。 <br />
语法： <br />
native2ascii [options] [inputfile [outputfile]] <br />
补充说明： <br />
Java 编译器和其它 Java 工具只能处理含有 Latin-1 和/或 Unicode 编码（udddd 记号）字符的文件。native2ascii 将含有其它字符编码的文件转换成含 Latin-1 和/或 Unicode 编码字符的文件。若省略 outputfile，则使用标准输出设备输出。此外，如果也省略 inputfile，则使用标准输入设备输入。 <br />
命令选项 <br />
-reverse 执行相反的操作：将含 Latin-1 和/或 Unicode 编码字符的文件转换成含本地编码字符的文件。 <br />
-encoding[encoding_name] 指定转换过程使用的编码名称。缺省的编码从系统属性 file.encoding 中得到。
<p><strong>appletviewer</strong>
<p>功能说明： <br />
Java applet 浏览器。appletviewer 命令可在脱离万维网浏览器环境的情况下运行 applet。 <br />
语法： <br />
appletviewer [ threads flag ] [ 命令选项 ] urls ... <br />
补充说明： <br />
appletviewer 命令连接到 url 所指向的文档或资源上，并在其自身的窗口中显示文档引用的每个 applet。注意：如果 url 所指向的文档不引用任何带有 OBJECT、EMBED 或 APPLET 标记的 applet，那么 appletviewer 就不做任何事情。 <br />
命令选项 <br />
-debug 在 Java 调试器 jdb 中启动 appletviewer，使您可以调试文档中的 applet。 <br />
-encoding[编码名称] 指定输入 HTML 文件的编码名称。 <br />
-J[javaoption] 将 javaoption 字符串作为单个参数传给运行 appletviewer 的 Java 解释器。参数不能含有空格。由多重参数组成的字符串，其中的每个参数都必须以前缀 -J 开头，该前缀以后将被除去。这在调整编译器的执行环境或内存使用时将很有用。
<p><strong>extcheck</strong>
<p>功能说明： <br />
extcheck 检测目标 jar 文件与当前安装方式扩展 jar 文件间的版本冲突。 <br />
语法： <br />
extcheck [ -verbose ] targetfile.jar <br />
补充说明： <br />
extcheck 实用程序检查指定 Jar 文件的标题和版本与 JDK TM 软件中所安装的扩展是否有冲突。在安装某个扩展前，可以用该实用程序查看是否已安装了该扩展的相同版本或更高的版本。 <br />
extcheck 实用程序将 targetfile.jar 文件清单的 specification-title 和 specification-version 头与当前安装在扩展目录下所有 Jar 文件的相对应的头进行比较（缺省扩展目录为 jre/lib/ext）。extcheck 实用程序比较版本号的方式与 java.lang.Package.isCompatibleWith 方法相同。若未检测到冲突，则返回代码为 0。如果扩展目录中任何一个 jar 文件的清单有相同的 specification-title 和相同的或更新的 specification-version 号，则返回非零错误代码。如果 targetfile.jar 的清单中没有 specification-title 或 specification-version 属性，则同样返回非零错误代码。 <br />
命令选项 <br />
-verbose 对扩展目录中的 Jar 文件进行检查时，列出文件。此外，还报告目标 jar 文件的清单属性及所有冲突的 jar 文件。
<p><strong>jar</strong>
<p>功能说明： <br />
Java归档工具 <br />
语法： <br />
jar [ 命令选项 ] [manifest] destination input-file [input-files] <br />
补充说明： <br />
jar工具是个java应用程序，可将多个文件合并为单个JAR归档文件。jar是个多用途的存档及压缩工具，它基于ZIP和ZLIB压缩格式。然而，设计jar的主要目的是便于将java applet或应用程序打包成单个归档文件。将applet或应用程序的组件(.class 文件、图像和声音)合并成单个归档文件时，可以用java代理(如浏览器)在一次HTTP事务处理过程中对它们进行下载，而不是对每个组件都要求一个新连接。这大大缩短了下载时间。jar还能压缩文件，从而进一步提高了下载速度。此外，它允许applet的作者对文件中的各个项进行签名，因而可认证其来源。jar工具的语法基本上与tar命令的语法相同。 <br />
命令选项 <br />
-c 在标准输出上创建新归档或空归档。 <br />
-t 在标准输出上列出内容表。 <br />
-x[file] 从标准输入提取所有文件，或只提取指定的文件。如果省略了file，则提取所有文件；否则只提取指定文件。 <br />
-f 第二个参数指定要处理的jar文件。在-c(创建)情形中，第二个参数指的是要创建的jar文件的名称(不是在标准输出上)。在-t(表(或-x(抽取)这两种情形中，第二个参数指定要列出或抽取的jar文件。 <br />
-v 在标准错误输出设备上生成长格式的输出结果。 <br />
-m 包括指定的现有清单文件中的清单信息。用法举例：&#8220;jar cmf myManifestFile myJarFile *.class&#8221; <br />
-0 只储存，不进行 ZIP 压缩。 <br />
-M 不创建项目的清单文件。 <br />
-u 通过添加文件或更改清单来更新现有的 JAR 文件。例如：&#8220;jar -uf foo.jar foo.class&#8221;将文件 foo.class 添加到现有的JAR文件foo.jar中，而&#8220;jar umf manifest foo.jar&#8221;则用manifest中的信息更新foo.jar的清单。 <br />
-C 在执行 jar 命令期间更改目录。例如：&#8220;jar -uf foo.jar -C classes *&#8221;将classes目录内的所有文件加到foo.jar中，但不添加类目录本身。 <br />
程序示例 <br />
1:将当前目录下所有CLASS文件打包成新的JAR文件： <br />
jar cf file.jar *.class <br />
2:显示一个JAR文件中的文件列表 <br />
jar tf file.jar <br />
3:将当前目录下的所有文件增加到一个已经存在的JAR文件中 <br />
jar cvf file.jar *
<p><strong>javadoc</strong>
<p>功能说明 <br />
Java API文档生成器从Java源文件生成API文档HTML页。 <br />
语法： <br />
javadoc [ 命令选项 ] [ 包名 ] [ 源文件名 ] [ @files ] <br />
其中[ 包名 ]为用空格分隔的一系列包的名字，包名不允许使用通配符，如（*）。[ 源文件名 ]为用空格分</p>
<img src ="http://www.blogjava.net/bacoo/aggbug/169173.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/bacoo/" target="_blank">bacoo</a> 2007-12-20 23:17 <a href="http://www.blogjava.net/bacoo/archive/2007/12/20/169173.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>