﻿<?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-水煮三国-随笔分类-J2SE</title><link>http://www.blogjava.net/os586/category/8044.html</link><description>态度决定一切，思想决定出路</description><language>zh-cn</language><lastBuildDate>Tue, 27 Feb 2007 10:54:59 GMT</lastBuildDate><pubDate>Tue, 27 Feb 2007 10:54:59 GMT</pubDate><ttl>60</ttl><item><title>Java 堆与栈的使用</title><link>http://www.blogjava.net/os586/archive/2006/10/27/77676.html</link><dc:creator>水煮三国</dc:creator><author>水煮三国</author><pubDate>Fri, 27 Oct 2006 08:07:00 GMT</pubDate><guid>http://www.blogjava.net/os586/archive/2006/10/27/77676.html</guid><wfw:comment>http://www.blogjava.net/os586/comments/77676.html</wfw:comment><comments>http://www.blogjava.net/os586/archive/2006/10/27/77676.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/os586/comments/commentRss/77676.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/os586/services/trackbacks/77676.html</trackback:ping><description><![CDATA[
		<p>Java栈与堆------------转自javaeye.com</p>
		<p>----对这两个概念的不明好久，终于找到一篇好文，拿来共享（http://www.duduwolf.com/cmd.asp?act=tb&amp;id=3 ）</p>
		<p>1. 栈(stack)与堆(heap)都是Java用来在Ram中存放数据的地方。与C++不同，Java自动管理栈和堆，程序员不能直接地设置栈或堆。 </p>
		<p>2. 栈的优势是，存取速度比堆要快，仅次于直接位于CPU中的寄存器。但缺点是，存在栈中的数据大小与生存期必须是确定的，缺乏灵活性。另外，栈数据可以共享，详见第3点。堆的优势是可以动态地分配内存大小，生存期也不必事先告诉编译器，Java的垃圾收集器会自动收走这些不再使用的数据。但缺点是，由于要在运行时动态分配内存，存取速度较慢。</p>
		<p>3. Java中的数据类型有两种。</p>
		<p>一种是基本类型(primitive types), 共有8种，即int, short, long, byte, float, double, boolean, char(注意，并没有string的基本类型)。这种类型的定义是通过诸如int a = 3; long b = 255L;的形式来定义的，称为自动变量。值得注意的是，自动变量存的是字面值，不是类的实例，即不是类的引用，这里并没有类的存在。如int a = 3; 这里的a是一个指向int类型的引用，指向3这个字面值。这些字面值的数据，由于大小可知，生存期可知(这些字面值固定定义在某个程序块里面，程序块退出后，字段值就消失了)，出于追求速度的原因，就存在于栈中。</p>
		<p>另外，栈有一个很重要的特殊性，就是存在栈中的数据可以共享。假设我们同时定义：</p>
		<p>
		</p>
		<div class="code_title">代码</div>
		<div class="code_div">
				<pre>
						<span class="ident">int</span>
						<span class="ident">a</span>
						<span class="punct">=</span>
						<span class="number">3</span>
						<span class="punct">;</span>
						<br />
						<span class="ident">int</span>
						<span class="ident">b</span>
						<span class="punct">=</span>
						<span class="number">3；</span>
				</pre>
		</div>
		<br />编译器先处理int a = 3；首先它会在栈中创建一个变量为a的引用，然后查找有没有字面值为3的地址，没找到，就开辟一个存放3这个字面值的地址，然后将a指向3的地址。接着处理int b = 3；在创建完b的引用变量后，由于在栈中已经有3这个字面值，便将b直接指向3的地址。这样，就出现了a与b同时均指向3的情况。 
<p></p><p>特别注意的是，这种字面值的引用与类对象的引用不同。假定两个类对象的引用同时指向一个对象，如果一个对象引用变量修改了这个对象的内部状态，那么另一个对象引用变量也即刻反映出这个变化。相反，通过字面值的引用来修改其值，不会导致另一个指向此字面值的引用的值也跟着改变的情况。如上例，我们定义完a与b的值后，再令a=4；那么，b不会等于4，还是等于3。在编译器内部，遇到a=4；时，它就会重新搜索栈中是否有4的字面值，如果没有，重新开辟地址存放4的值；如果已经有了，则直接将a指向这个地址。因此a值的改变不会影响到b的值。</p><p>另一种是包装类数据，如Integer, String, Double等将相应的基本数据类型包装起来的类。这些类数据全部存在于堆中，Java用new()语句来显示地告诉编译器，在运行时才根据需要动态创建，因此比较灵活，但缺点是要占用更多的时间。 4. String是一个特殊的包装类数据。即可以用String str = new String("abc");的形式来创建，也可以用String str = "abc"；的形式来创建(作为对比，在JDK 5.0之前，你从未见过Integer i = 3;的表达式，因为类与字面值是不能通用的，除了String。而在JDK 5.0中，这种表达式是可以的！因为编译器在后台进行Integer i = new Integer(3)的转换)。前者是规范的类的创建过程，即在Java中，一切都是对象，而对象是类的实例，全部通过new()的形式来创建。Java中的有些类，如DateFormat类，可以通过该类的getInstance()方法来返回一个新创建的类，似乎违反了此原则。其实不然。该类运用了单例模式来返回类的实例，只不过这个实例是在该类内部通过new()来创建的，而getInstance()向外部隐藏了此细节。那为什么在String str = "abc"；中，并没有通过new()来创建实例，是不是违反了上述原则？其实没有。</p><p>5. 关于String str = "abc"的内部工作。Java内部将此语句转化为以下几个步骤：</p><p>(1)先定义一个名为str的对String类的对象引用变量：String str；</p><p>(2)在栈中查找有没有存放值为"abc"的地址，如果没有，则开辟一个存放字面值为"abc"的地址，接着创建一个新的String类的对象o，并将o的字符串值指向这个地址，而且在栈中这个地址旁边记下这个引用的对象o。如果已经有了值为"abc"的地址，则查找对象o，并返回o的地址。</p><p>(3)将str指向对象o的地址。</p><p>值得注意的是，一般String类中字符串值都是直接存值的。但像String str = "abc"；这种场合下，其字符串值却是保存了一个指向存在栈中数据的引用！</p><p>为了更好地说明这个问题，我们可以通过以下的几个代码进行验证。</p><p></p><div class="code_title">代码</div><div class="code_div"><pre><span class="constant">String</span><span class="ident">str1</span><span class="punct">=</span><span class="punct">"</span><span class="string">abc</span><span class="punct">";</span><br /><span class="constant">String</span><span class="ident">str2</span><span class="punct">=</span><span class="punct">"</span><span class="string">abc</span><span class="punct">";</span><br /><span class="constant">System</span><span class="punct">.</span><span class="ident">out</span><span class="punct">.</span><span class="ident">println</span><span class="punct">(</span><span class="ident">str1</span><span class="punct">==</span><span class="ident">str2</span><span class="punct">);</span><span class="punct">/</span><span class="regex"></span><span class="punct">/</span><span class="constant">true</span></pre></div><br />注意，我们这里并不用str1.equals(str2)；的方式，因为这将比较两个字符串的值是否相等。==号，根据JDK的说明，只有在两个引用都指向了同一个对象时才返回真值。而我们在这里要看的是，str1与str2是否都指向了同一个对象。 <br />结果说明，JVM创建了两个引用str1和str2，但只创建了一个对象，而且两个引用都指向了这个对象。 
<p></p><p>我们再来更进一步，将以上代码改成：</p><p></p><div class="code_title">代码</div><div class="code_div"><pre><span class="constant">String</span><span class="ident">str1</span><span class="punct">=</span><span class="punct">"</span><span class="string">abc</span><span class="punct">";</span><br /><span class="constant">String</span><span class="ident">str2</span><span class="punct">=</span><span class="punct">"</span><span class="string">abc</span><span class="punct">";</span><br /><span class="ident">str1</span><span class="punct">=</span><span class="punct">"</span><span class="string">bcd</span><span class="punct">";</span><br /><span class="constant">System</span><span class="punct">.</span><span class="ident">out</span><span class="punct">.</span><span class="ident">println</span><span class="punct">(</span><span class="ident">str1</span><span class="punct">+</span><span class="punct">"</span><span class="string">,</span><span class="punct">"</span><span class="punct">+</span><span class="ident">str2</span><span class="punct">);</span><span class="punct">/</span><span class="regex"></span><span class="punct">/</span><span class="ident">bcd</span><span class="punct">,</span><span class="ident">abc</span><br /><span class="constant">System</span><span class="punct">.</span><span class="ident">out</span><span class="punct">.</span><span class="ident">println</span><span class="punct">(</span><span class="ident">str1</span><span class="punct">==</span><span class="ident">str2</span><span class="punct">);</span><span class="punct">/</span><span class="regex"></span><span class="punct">/</span><span class="constant">false</span></pre></div><p></p><p>这就是说，赋值的变化导致了类对象引用的变化，str1指向了另外一个新对象！而str2仍旧指向原来的对象。上例中，当我们将str1的值改为"bcd"时，JVM发现在栈中没有存放该值的地址，便开辟了这个地址，并创建了一个新的对象，其字符串的值指向这个地址。</p><p>事实上，String类被设计成为不可改变(immutable)的类。如果你要改变其值，可以，但JVM在运行时根据新值悄悄创建了一个新对象，然后将这个对象的地址返回给原来类的引用。这个创建过程虽说是完全自动进行的，但它毕竟占用了更多的时间。在对时间要求比较敏感的环境中，会带有一定的不良影响。</p><p>再修改原来代码：</p><p></p><div class="code_title">代码</div><div class="code_div"><pre><span class="constant">String</span><span class="ident">str1</span><span class="punct">=</span><span class="punct">"</span><span class="string">abc</span><span class="punct">";</span><br /><span class="constant">String</span><span class="ident">str2</span><span class="punct">=</span><span class="punct">"</span><span class="string">abc</span><span class="punct">";</span><p></p><p><span class="ident">str1</span><span class="punct">=</span><span class="punct">"</span><span class="string">bcd</span><span class="punct">";</span></p><p><span class="constant">String</span><span class="ident">str3</span><span class="punct">=</span><span class="ident">str1</span><span class="punct">;</span><br /><span class="constant">System</span><span class="punct">.</span><span class="ident">out</span><span class="punct">.</span><span class="ident">println</span><span class="punct">(</span><span class="ident">str3</span><span class="punct">);</span><span class="punct">/</span><span class="regex"></span><span class="punct">/</span><span class="ident">bcd</span></p><p><span class="constant">String</span><span class="ident">str4</span><span class="punct">=</span><span class="punct">"</span><span class="string">bcd</span><span class="punct">";</span><br /><span class="constant">System</span><span class="punct">.</span><span class="ident">out</span><span class="punct">.</span><span class="ident">println</span><span class="punct">(</span><span class="ident">str1</span><span class="punct">==</span><span class="ident">str4</span><span class="punct">);</span><span class="punct">/</span><span class="regex"></span><span class="punct">/</span><span class="constant">true</span></p></pre></div><br />str3这个对象的引用直接指向str1所指向的对象(注意，str3并没有创建新对象)。当str1改完其值后，再创建一个String的引用str4，并指向因str1修改值而创建的新的对象。可以发现，这回str4也没有创建新的对象，从而再次实现栈中数据的共享。 
<p></p><p>我们再接着看以下的代码。</p><p></p><div class="code_title">代码</div><div class="code_div"><pre><span class="constant">String</span><span class="ident">str1</span><span class="punct">=</span><span class="keyword">new</span><span class="constant">String</span><span class="punct">("</span><span class="string">abc</span><span class="punct">");</span><br /><span class="constant">String</span><span class="ident">str2</span><span class="punct">=</span><span class="punct">"</span><span class="string">abc</span><span class="punct">";</span><br /><span class="constant">System</span><span class="punct">.</span><span class="ident">out</span><span class="punct">.</span><span class="ident">println</span><span class="punct">(</span><span class="ident">str1</span><span class="punct">==</span><span class="ident">str2</span><span class="punct">);</span><span class="punct">/</span><span class="regex"></span><span class="punct">/</span><span class="constant">false</span></pre></div><p></p><p>创建了两个引用。创建了两个对象。两个引用分别指向不同的两个对象。</p><p>String str1 = "abc"; <br />String str2 = new String("abc"); <br />System.out.println(str1==str2); //false </p><p>创建了两个引用。创建了两个对象。两个引用分别指向不同的两个对象。</p><p>以上两段代码说明，只要是用new()来新建对象的，都会在堆中创建，而且其字符串是单独存值的，即使与栈中的数据相同，也不会与栈中的数据共享。</p><p>6. 数据类型包装类的值不可修改。不仅仅是String类的值不可修改，所有的数据类型包装类都不能更改其内部的值。 7. 结论与建议：</p><p>(1)我们在使用诸如String str = "abc"；的格式定义类时，总是想当然地认为，我们创建了String类的对象str。担心陷阱！对象可能并没有被创建！唯一可以肯定的是，指向String类的引用被创建了。至于这个引用到底是否指向了一个新的对象，必须根据上下文来考虑，除非你通过new()方法来显要地创建一个新的对象。因此，更为准确的说法是，我们创建了一个指向String类的对象的引用变量str，这个对象引用变量指向了某个值为"abc"的String类。清醒地认识到这一点对排除程序中难以发现的bug是很有帮助的。</p><p>(2)使用String str = "abc"；的方式，可以在一定程度上提高程序的运行速度，因为JVM会自动根据栈中数据的实际情况来决定是否有必要创建新对象。而对于String str = new String("abc")；的代码，则一概在堆中创建新对象，而不管其字符串值是否相等，是否有必要创建新对象，从而加重了程序的负担。这个思想应该是享元模式的思想，但JDK的内部在这里实现是否应用了这个模式，不得而知。</p><p>(3)当比较包装类里面的数值是否相等时，用equals()方法；当测试两个包装类的引用是否指向同一个对象时，用==。</p><p>(4)由于String类的immutable性质，当String变量需要经常变换其值时，应该考虑使用StringBuffer类，以提高程序效率。</p><img src ="http://www.blogjava.net/os586/aggbug/77676.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/os586/" target="_blank">水煮三国</a> 2006-10-27 16:07 <a href="http://www.blogjava.net/os586/archive/2006/10/27/77676.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>NoClassDefDoundErr与ClassNotFoundException区别 </title><link>http://www.blogjava.net/os586/archive/2006/10/27/77564.html</link><dc:creator>水煮三国</dc:creator><author>水煮三国</author><pubDate>Fri, 27 Oct 2006 02:53:00 GMT</pubDate><guid>http://www.blogjava.net/os586/archive/2006/10/27/77564.html</guid><wfw:comment>http://www.blogjava.net/os586/comments/77564.html</wfw:comment><comments>http://www.blogjava.net/os586/archive/2006/10/27/77564.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/os586/comments/commentRss/77564.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/os586/services/trackbacks/77564.html</trackback:ping><description><![CDATA[
		<p>NoClassDefDoundErr与ClassNotFoundException区别</p>
		<p>作者:langm</p>
		<p>版权声明：本文可以自由转载，转载时请务必以超链接形式标明文章原始出处和作者信息及本声明 <br />作者:langm <br />原文:http://www.matrix.org.cn/resource/article/44/44056_NoClassDefDoundErr.html <br />关键字:NoClassDefDoundErr ClassNotFoundException</p>
		<p>在读这篇文章之前，你最好了解一下Java的Exception机制。</p>
		<p>也许你在开发的过程中经常地见到ClassNotFoundException和NoClassDefFoundErr这两个异常，每每看到之后，都会一概而论的是类没有找到，但有些时候见到他们的时候又有些疑惑（至少我是这样），为什么Java要用两个异常来表示类定义没有找到那？他们之间有什么区别那？</p>
		<p>正巧今天我又碰到了这个问题，顺便的仔细研究了一下这两个异常的区别。 <br />首先： <br />ClassNotFoundException直接继承与Exception，它是一个checked的异常。 <br />NoClassDefFoundErr 继承自Error-&gt;LinkageError ，它是一个unchecked的异常。</p>
		<p>下面让我们看一下两个异常在API文档中的说明</p>
		<p>ClassNotFoundException： <br />当应用尝试用字符串名称通过下面的方法装载一个类时这个类的定义却没有找到时会抛出的异常。 <br />Class.forName <br />ClassLoader.findSystemClass <br />ClassLoader.loadClass <br /><br />NoClassDefFoundErr： <br />当JVM或者ClassLoader实例尝试装载一个类的定义（这通常是一个方法调用或者new表达式创建一个实例过程的一部分）而这个类定义并没有找时所抛出的错误。 <br />当编译的时候可以找到这个类的定义，但是以后这个类不再存在。</p>
		<p>这比较显而易见了吧，读好文档是很重要的事情。这里我就说一下我对这两个类的区别的理解。</p>
		<p>ClassNotFoundException异常只出现在你的应用程序主动的装载类的过程中，这个异常很多时候出现在我们的应用框架在初始化或者运行中动态装载已配置的类的过程中。这种情况下我们应该首先检查我们的配置或者参数是否错误，是否企图装载一个并不存在的类，如果配置没有错误，我们就应该查看Classpath是否配置错误而导致ClassLoader无法找到这个类，也应该检查要装载的类是否在一个jar包中而我们在引入这个jar包的过程中是否有遗漏或错误（这里jar包的版本也是一个需要格外注意的问题，很多时候混乱的jar包版本会造成太多的麻烦）。 <br /><br />NoClassDefFoundErr异常一般出现在我们编译环境和运行环境不一致的情况下，就是说我们有可能在编译过后更改了Classpath或者jar包所以导致在运行的过程中JVM或者ClassLoader无法找到这个类的定义（我曾经在编译后作了一次jar包的清理，然后应用就送给了我一个这样的礼物）。</p>
		<p>我们经常用SDK开发应用，开发的过程中要引入很多jar包，有些SDK也会设定自己的Classpath。编译过程结束后在运行的过程中就要将已开发的应用和所有引入的jar包拷贝到应用服务器的相应目录下才可以运行，而应用服务器使用的Classpath也很有可能与SDK的不同，在这个过程中就有很大的几率造成双方环境不一致。所以很多开发者就会遇到在SDK中可以编译，运行也没有问题，但是同样的程序放到应用服务器上就出现NoClassDefFoundErr这个异常这种情况，这是让初学者很挠头的一个问题。</p>
		<p>以上就是我对这两个异常的一点个人理解，希望对各位开发者有所帮助，可以让各位开发者在以后的开发过程中能够更快的找到问题所在。祝开发顺利</p>
<img src ="http://www.blogjava.net/os586/aggbug/77564.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/os586/" target="_blank">水煮三国</a> 2006-10-27 10:53 <a href="http://www.blogjava.net/os586/archive/2006/10/27/77564.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>澄清Java语言接口与继承的本质</title><link>http://www.blogjava.net/os586/archive/2006/10/26/77316.html</link><dc:creator>水煮三国</dc:creator><author>水煮三国</author><pubDate>Thu, 26 Oct 2006 00:55:00 GMT</pubDate><guid>http://www.blogjava.net/os586/archive/2006/10/26/77316.html</guid><wfw:comment>http://www.blogjava.net/os586/comments/77316.html</wfw:comment><comments>http://www.blogjava.net/os586/archive/2006/10/26/77316.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.blogjava.net/os586/comments/commentRss/77316.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/os586/services/trackbacks/77316.html</trackback:ping><description><![CDATA[
		<table style="FLOAT: left; MARGIN: 0px 10px 10px" cellspacing="0" cellpadding="0" align="left" border="0">
				<tbody>
						<tr>
								<td>
										<script type="text/javascript">
												<!--
						csdn_AD_Position_GroupID = "{e025b96b-2fda-4e82-84ef-3e0772838ed3}";
						csdn_AD_Page_Url = document.location;
						csdn_AD_CurrPage_CharSet = "gb2312";
						//-->
										</script>
										<script src="http://ggmm.csdn.net/AD/Show_JavaScript_AD.js" type="text/javascript">
										</script>
										<script language="JavaScript1.1" src="http://ggmm.csdn.net/AD/ShowJavaScriptAD.aspx?show=true&amp;position={e025b96b-2fda-4e82-84ef-3e0772838ed3}&amp;CharSet=gb2312">
										</script>
										<br />
										<script src="http://news.csdn.net/ad/news_textlink.js" type="text/javascript">
										</script>
								</td>
						</tr>
				</tbody>
		</table>大多数人认为，接口的意义在于顶替多重继承。众所周知Java没有c++那样多重继承的机制，但是却能够实作多个接口。其实这样做是很牵强的，接口和继承是完全不同的东西，接口没有能力代替多重继承，也没有这个义务。接口的作用，一言以蔽之，就是标志类的类别（type of class）。把不同类型的类归于不同的接口，可以更好的管理他们。OO的精髓，我以为，是对对象的抽象，最能体现这一点的就是接口。为什么我们讨论设计模式都只针对具备了抽象能力的语言（比如c++、java、c#等），就是因为设计模式所研究的，实际上就是如何合理的去抽象。（cowboy的名言是“抽象就是抽去像的部分”，看似调侃，实乃至理）。<br /><br />　　设计模式中最基础的是工厂模式（Factory），在我最近的一个很简单的应用中，我想尽量的让我的程序能够在多个数据库间移植，当然，这涉及很多问题，单是如何兼容不同DBMS的SQL就让人头痛。我们不妨先把问题简单化，只考虑如何连接不同的数据库。<br /><br />　　假设我有很多个类，分别是Mysql.java、SQLServer.java、Oracle.java、DB2.java，他们分别连接不同的数据库，统一返回一个Connection对象，并且都有一个close方法，用于关闭连接。只需要针对你的DBMS，选择不同的类，就可以用了，但是我的用户他会使用什么数据库？我不知道，我希望的是尽量少的修改代码，就能满足他的需要。我可以抽象如下接口：<br /><br />package org.bromon.test;<br />public interface DB<br />{<br />　　java.sql.Connection openDB(String url,String user,String password);<br />　　void close();<br />} <br /><br />　　这个接口只定义两个方法，没有任何有实际意义的代码，具体的代码由实作这个接口的类来给出，比如Mysql.java：<br /><br />Package org.bromon.test;<br />import java.sql.*;<br />public class Mysql implements DB<br />{<br />　　private String url=”jdbc:mysql:localhost:3306/test”;<br />　　private String user=”root”;<br />　　private String password=””;<br />　　private Connection conn;<br />　　public Connection openDB(url,user,password)<br />　　{<br />　　　　//连接数据库的代码<br />　　}<br /><br />　　public void close()<br />　　{<br />　　　　//关闭数据库<br />　　}<br />} <br /><br />　　类似的当然还有Oracle.java等等，接口DB给这些类归了个类，在应用程序中我们这样定义对象：<br /><br />　　org.bromon.test.DB myDB;<br /><br />　　使用myDB来操作数据库，就可以不用管实际上我所使用的是哪个类，这就是所谓的“开-闭”原则。但是问题在于接口是不能实例化的，myDB=new DB()，这样的代码是绝对错误的，我们只能myDB=new Mysql()或者myDB=new Oracle()。麻烦了，我还是需要指定具体实例化的是哪个类，用了接口跟没用一样。所以我们需要一个工厂：<br /><br />package org.bromon.test;<br />public class DBFactory<br />{<br />　　public static DB Connection getConn()<br />　　{<br />　　　　Return(new Mysql());<br />　　}<br />} <br /><br />　　所以实例化的代码变成：myDB=DBFactory.getConn()；<br /><br />　　这就是23种模式中最基础的普通工厂(Factory)，工厂类负责具体实例化哪个类，而其他的程序逻辑都是针对DB这个接口进行操作，这就是“针对接口编程”。责任都被推卸给工厂类了，当然你也可以继续定义工厂接口，继续把责任上抛，这就演变成抽象工厂(Abstract Factory)。<br /><br />　　整个过程中接口不负责任何具体操作，其他的程序要连接数据库的话，只需要构造一个DB对象就OK，而不管工厂类如何变化。这就是接口的意义----抽象。<br /><br />　　继承的概念不用多说，很好理解。为什么要继承呢？因为你想重用代码？这绝对不是理由，继承的意义也在于抽象，而不是代码重用。如果对象A有一个run()方法，对象B也想有这个方法，所以有人就Class B extends A。这是不经大脑的做法。如果在B中实例化一个A，调用A的Run()方法，是不是可以达到同样的目的？如下：<br /><br />Class B<br />{<br />　　A a=new A();<br />　　a.run();<br />} <br /><br />　　这就是利用类的聚合来重用代码，是委派模式的雏形，是GoF一贯倡导的做法。<br /><br />　　那么继承的意义何在？其实这是历史原因造成的，最开始的OO语言只有继承，没有接口，所以只能以继承来实现抽象，请一定注意，继承的本意在于抽象，而非代码重用（虽然继承也有这个作用），这是很多Java烂书最严重的错误之一，它们所造成的阴影，我至今还没有完全摆脱，坏书害人啊，尤其是入门类的，流毒太大。什么时候应该使用继承？只在抽象类中使用，其他情况下尽量不使用。抽象类也是不能实例化的，它仅仅提供一个模版而已，这就很能说明问题。<br /><br />　　软件开发的万恶之源，一是重复代码而不是重用代码，二是烂用继承，尤以c++程序员为甚。Java中取缔多重继承，目的就是制止烂用继承，实是非常明智的做法，不过很多人都不理解。Java能够更好的体现设计，这是让我入迷的原因之一。<img src ="http://www.blogjava.net/os586/aggbug/77316.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/os586/" target="_blank">水煮三国</a> 2006-10-26 08:55 <a href="http://www.blogjava.net/os586/archive/2006/10/26/77316.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关键字new和newInstance方法区别</title><link>http://www.blogjava.net/os586/archive/2006/09/22/71237.html</link><dc:creator>水煮三国</dc:creator><author>水煮三国</author><pubDate>Fri, 22 Sep 2006 01:08:00 GMT</pubDate><guid>http://www.blogjava.net/os586/archive/2006/09/22/71237.html</guid><wfw:comment>http://www.blogjava.net/os586/comments/71237.html</wfw:comment><comments>http://www.blogjava.net/os586/archive/2006/09/22/71237.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/os586/comments/commentRss/71237.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/os586/services/trackbacks/71237.html</trackback:ping><description><![CDATA[在初始化一个类，生成一个实例的时候，newInstance()方法和new关键字除了一个是方法，一个是关键字外，最主要有什么区别？它们的区别在于创建对象的方式不一样，前者是使用类加载机制，后者是创建一个新类。那么为什么会有两种创建对象方式？这主要考虑到软件的可伸缩、可扩展和可重用等软件设计思想。 <br /><br />    Java中工厂模式经常使用newInstance()方法来创建对象，因此从为什么要使用工厂模式上可以找到具体答案。 例如：<br />    class c = Class.forName(“Example”);<br />    factory = (ExampleInterface)c.newInstance(); <br /><br />    其中ExampleInterface是Example的接口，可以写成如下形式： <br />    String className = "Example";<br />    class c = Class.forName(className);<br />    factory = (ExampleInterface)c.newInstance();<br /><br />    进一步可以写成如下形式：<br />    String className = readfromXMlConfig;//从xml 配置文件中获得字符串<br />    class c = Class.forName(className);<br />    factory = (ExampleInterface)c.newInstance();<br /><br />    上面代码已经不存在Example的类名称，它的优点是，无论Example类怎么变化，上述代码不变，甚至可以更换Example的兄弟类Example2 , Example3 , Example4……，只要他们继承ExampleInterface就可以。<br /><br />    从JVM的角度看，我们使用关键字new创建一个类的时候，这个类可以没有被加载。但是使用newInstance()方法的时候，就必须保证：1、这个类已经加载；2、这个类已经连接了。而完成上面两个步骤的正是Class的静态方法forName()所完成的，这个静态方法调用了启动类加载器，即加载java API的那个加载器。<br /><br />    现在可以看出，newInstance()实际上是把new这个方式分解为两步，即首先调用Class加载方法加载某个类，然后实例化。 这样分步的好处是显而易见的。我们可以在调用class的静态加载方法forName时获得更好的灵活性，提供给了一种降耦的手段。<br /><br />    最后用最简单的描述来区分new关键字和newInstance()方法的区别：<br />    newInstance: 弱类型。低效率。只能调用无参构造。 <br />    new: 强类型。相对高效。能调用任何public构造。<br /><img src ="http://www.blogjava.net/os586/aggbug/71237.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/os586/" target="_blank">水煮三国</a> 2006-09-22 09:08 <a href="http://www.blogjava.net/os586/archive/2006/09/22/71237.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Iterator和ListIterator的不同使用方法</title><link>http://www.blogjava.net/os586/archive/2006/09/22/71235.html</link><dc:creator>水煮三国</dc:creator><author>水煮三国</author><pubDate>Fri, 22 Sep 2006 01:02:00 GMT</pubDate><guid>http://www.blogjava.net/os586/archive/2006/09/22/71235.html</guid><wfw:comment>http://www.blogjava.net/os586/comments/71235.html</wfw:comment><comments>http://www.blogjava.net/os586/archive/2006/09/22/71235.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/os586/comments/commentRss/71235.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/os586/services/trackbacks/71235.html</trackback:ping><description><![CDATA[我们在使用List,Set的时候,为了实现对其数据的遍历,我们经常使用到了Iterator(跌代器)。<br />使用跌代器，你不需要干涉其遍历的过程，只需要每次取出一个你想要的数据进行处理就可以了。但是在使用的时候也是有不同的。<br />List和Set都有iterator()来取得其迭代器。对List来说，你也可以通过listIterator()取得其迭代器，两种迭代器在有些时候是不能通用的，Iterator和ListIterator主要区别在以下方面：<br />1.    ListIterator有add()方法，可以向List中添加对象，而Iterator不能<br />2.    ListIterator和Iterator都有hasNext()和next()方法，可以实现顺序向后遍历，但是ListIterator有hasPrevious()和previous()方法，可以实现逆向（顺序向前）遍历。Iterator就不可以。<br />3.    ListIterator可以定位当前的索引位置，nextIndex()和previousIndex()可以实现。Iterator没有此功能。<br />4.    都可实现删除对象，但是ListIterator可以实现对象的修改，set()方法可以实现。Iierator仅能遍历，不能修改。<br /><br />因为ListIterator的这些功能，可以实现对LinkedList等List数据结构的操作。<br />其实,数组对象也可以用迭代器来实现。<br />org.apache.commons.collections.iterators.ArrayIterator就可以实现此功能，我此前曾经提过起用法。具体可以参考[link=<a href="http://www.javaresearch.org/article/showarticle.jsp?column=1&amp;thread=41142">http://www.javaresearch.org/article/showarticle.jsp?column=1&amp;thread=41142</a><br />]<br />一般情况下，我们使用Iterator就可以了，如果你需要进行记录的前后反复检索的话，你就可以使用ListIterator来扩展你的功能，（有点象JDBC中的滚动结果集）。<img src ="http://www.blogjava.net/os586/aggbug/71235.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/os586/" target="_blank">水煮三国</a> 2006-09-22 09:02 <a href="http://www.blogjava.net/os586/archive/2006/09/22/71235.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>SWT:GridLayout 的使用需要注意的事项</title><link>http://www.blogjava.net/os586/archive/2006/09/12/69111.html</link><dc:creator>水煮三国</dc:creator><author>水煮三国</author><pubDate>Tue, 12 Sep 2006 02:50:00 GMT</pubDate><guid>http://www.blogjava.net/os586/archive/2006/09/12/69111.html</guid><wfw:comment>http://www.blogjava.net/os586/comments/69111.html</wfw:comment><comments>http://www.blogjava.net/os586/archive/2006/09/12/69111.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/os586/comments/commentRss/69111.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/os586/services/trackbacks/69111.html</trackback:ping><description><![CDATA[
		<p>SWT当中的GridLayout是一个非常灵活的控件,但是在使用起来需要在控制上下一番功夫.<br /><br />大家都知道,JAVA在写编写窗口程序的时候,物件的添加,放置 操作起来要比.net费劲的多,但是如果用好了相关org.eclipse.layout.*包当中的相关类,也会写出十分漂亮的界面程序.<br /><br />下面大家先看一个程序:<br /><br />源码如下:<br /><br />package com.layout;</p>
		<p>import org.eclipse.swt.widgets.*;<br />import org.eclipse.swt.layout.*;<br />import org.eclipse.swt.SWT;</p>
		<p>public class CopyOfGridLayoutExc {<br /> <br /> public static void main(String[] args) {</p>
		<p>  Display display = new Display();</p>
		<p>     Shell shell = new Shell(display);</p>
		<p>     shell.setText("Find (GridLayout)");</p>
		<p>     Label label = new Label(shell, SWT.NONE);</p>
		<p>     label.setText("Find what:");</p>
		<p>     Text text = new Text(shell, SWT.BORDER);</p>
		<p>     Button findButton = new Button(shell, SWT.PUSH);</p>
		<p>     findButton.setText("Find Next");</p>
		<p>     Group group = new Group(shell, SWT.NONE);</p>
		<p>     group.setLayout(new RowLayout());</p>
		<p>     Button upButton = new Button(group, SWT.RADIO);</p>
		<p>     upButton.setText("Up");</p>
		<p>     Button downButton = new Button(group, SWT.RADIO);</p>
		<p>     downButton.setText("Down");</p>
		<p>     downButton.setSelection(true);</p>
		<p>     group.setText("Direction");</p>
		<p>     Button cancelButton = new Button(shell, SWT.PUSH);</p>
		<p>     cancelButton.setText("Cancel");</p>
		<p> </p>
		<p>     /* Use a GridLayout to position the controls */</p>
		<p>     Monitor monitor = shell.getMonitor();</p>
		<p>     int width = monitor.getClientArea().width / 10;</p>
		<p>     GridLayout layout = new GridLayout(4, false);</p>
		<p>     layout.marginWidth = layout.marginHeight = 14;//layout leave's the window's space</p>
		<p>     shell.setLayout(layout);</p>
		<p>     GridData labelData =</p>
		<p>         new GridData(SWT.FILL, SWT.CENTER, false, false);</p>
		<p>     label.setLayoutData(labelData);</p>
		<p>     GridData textData =</p>
		<p>         new GridData(SWT.FILL,SWT.CENTER,true,false,2,1);</p>
		<p>     textData.widthHint = width;</p>
		<p>     text.setLayoutData(textData);</p>
		<p>     GridData findData =</p>
		<p>         new GridData(SWT.FILL, SWT.CENTER, false, false);</p>
		<p>     findButton.setLayoutData(findData);</p>
		<p>     GridData groupData =</p>
		<p>         new GridData(SWT.RIGHT,SWT.TOP,false,false,3,1);</p>
		<p>     group.setLayoutData(groupData);</p>
		<p>     GridData cancelData =</p>
		<p>         new GridData(SWT.FILL, SWT.TOP, false, false);</p>
		<p>     cancelButton.setLayoutData(cancelData);</p>
		<p> </p>
		<p>     shell.pack();</p>
		<p>     shell.open();</p>
		<p>     while (!shell.isDisposed()) {</p>
		<p>         if (!display.readAndDispatch()) display.sleep();</p>
		<p>     }</p>
		<p>     display.dispose();</p>
		<p> }</p>
		<p>}<br /><br /><br /><br />这其中我们在使用的时候应该要注意以下几点:<br /><br />1.要选择自己适合 的Layout类型.GridLayout适合于多种情况,它大部分情况是使用在较为复杂的界面编程当中,因为复杂的界面会有相当多的控件.<br /><br /><br /><br />2.GridData的使用将是一个控制界面显示的主要类.通过使用GridData我们可以很好的控制界面.<br /><br />   其中GridData的构造函数比较多,但是相关的使用我们都应该熟悉,特别是上面源程序当中使用的那个构造函数,在使用起来更容易控制GridLayout的布局.通过horizantalSpan,VerticalSpan来控制控件所占用的单元格,这样就会控制其它控制是否在一列当中显示还是在几列当中显示.前提是通过GridLayout.numColumns来设置列数.<br /><br />3.如果不设置GridData那么相关的控件都会按照相关的建立顺序加入到GridLayout当中.GridData不能控制控件的显示顺序,而相关顺序是对象的建立顺序来控制的.这一点不要与GridData混淆了.<br /><br />希望写这篇文章对大家学习SWT有用.<br /><br /><br /></p>
<img src ="http://www.blogjava.net/os586/aggbug/69111.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/os586/" target="_blank">水煮三国</a> 2006-09-12 10:50 <a href="http://www.blogjava.net/os586/archive/2006/09/12/69111.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>转 JAVA一篇排序算法文章</title><link>http://www.blogjava.net/os586/archive/2006/09/01/67032.html</link><dc:creator>水煮三国</dc:creator><author>水煮三国</author><pubDate>Fri, 01 Sep 2006 02:31:00 GMT</pubDate><guid>http://www.blogjava.net/os586/archive/2006/09/01/67032.html</guid><wfw:comment>http://www.blogjava.net/os586/comments/67032.html</wfw:comment><comments>http://www.blogjava.net/os586/archive/2006/09/01/67032.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/os586/comments/commentRss/67032.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/os586/services/trackbacks/67032.html</trackback:ping><description><![CDATA[
		<p>1  Java排序算法  <br />  package com.cucu.test;</p>
		<p>/**<br /> * @author <a href="http://www.linewell.com/">http://www.linewell.com</a> &lt;a href=mailto:cg@linewell.com&gt;cg@linewell.com&lt;/a&gt;<br /> * @version 1.0<br /> */<br />public class Sort {</p>
		<p>  public void swap(int a[], int i, int j) {<br />    int tmp = a[i];<br />    a[i] = a[j];<br />    a[j] = tmp;<br />  }</p>
		<p>  public int partition(int a[], int low, int high) {<br />    int pivot, p_pos, i;<br />    p_pos = low;<br />    pivot = a[p_pos];<br />    for (i = low + 1; i &lt;= high; i++) {<br />      if (a[i] &gt; pivot) {<br />        p_pos++;<br />        swap(a, p_pos, i);<br />      }<br />    }<br />    swap(a, low, p_pos);<br />    return p_pos;<br />  }</p>
		<p>  public void quicksort(int a[], int low, int high) {<br />    int pivot;<br />    if (low &lt; high) {<br />      pivot = partition(a, low, high);<br />      quicksort(a, low, pivot - 1);<br />      quicksort(a, pivot + 1, high);<br />    }</p>
		<p>  }</p>
		<p>  public static void main(String args[]) {<br />    int vec[] = new int[] { 37, 47, 23, -5, 19, 56 };<br />    int temp;<br />    //选择排序法(Selection Sort)<br />    long begin = System.currentTimeMillis();<br />    for (int k = 0; k &lt; 1000000; k++) {<br />      for (int i = 0; i &lt; vec.length; i++) {<br />        for (int j = i; j &lt; vec.length; j++) {<br />          if (vec[j] &gt; vec[i]) {<br />            temp = vec[i];<br />            vec[i] = vec[j];<br />            vec[j] = temp;<br />          }<br />        }</p>
		<p>      }<br />    }<br />    long end = System.currentTimeMillis();<br />    System.out.println("选择法用时为：" + (end - begin));<br />    //打印排序好的结果<br />    for (int i = 0; i &lt; vec.length; i++) {<br />      System.out.println(vec[i]);<br />    }<br />    //  冒泡排序法(Bubble Sort)<br />    begin = System.currentTimeMillis();<br />    for (int k = 0; k &lt; 1000000; k++) {<br />      for (int i = 0; i &lt; vec.length; i++) {<br />        for (int j = i; j &lt; vec.length - 1; j++) {<br />          if (vec[j + 1] &gt; vec[j]) {<br />            temp = vec[j + 1];<br />            vec[j + 1] = vec[j];<br />            vec[j] = temp;<br />          }<br />        }</p>
		<p>      }<br />    }<br />    end = System.currentTimeMillis();<br />    System.out.println("冒泡法用时为：" + (end - begin));<br />    //打印排序好的结果<br />    for (int i = 0; i &lt; vec.length; i++) {<br />      System.out.println(vec[i]);<br />    }</p>
		<p>    //插入排序法(Insertion Sort)<br />    begin = System.currentTimeMillis();<br />    for (int k = 0; k &lt; 1000000; k++) {<br />      for (int i = 1; i &lt; vec.length; i++) {<br />        int j = i;<br />        while (vec[j - 1] &lt; vec[i]) {<br />          vec[j] = vec[j - 1];<br />          j--;<br />          if (j &lt;= 0) {<br />            break;<br />          }<br />        }<br />        vec[j] = vec[i];<br />      }<br />    }<br />    end = System.currentTimeMillis();<br />    System.out.println("插入法用时为：" + (end - begin));<br />    //打印排序好的结果<br />    for (int i = 0; i &lt; vec.length; i++) {<br />      System.out.println(vec[i]);<br />    }</p>
		<p>    //快速排序法(Quick Sort)</p>
		<p>    Sort s = new Sort();<br />    begin = System.currentTimeMillis();<br />    for (int k = 0; k &lt; 1000000; k++) {<br />      s.quicksort(vec, 0, 5);<br />    }<br />    end = System.currentTimeMillis();<br />    System.out.println("快速法用时为：" + (end - begin));<br />    //打印排序好的结果<br />    for (int i = 0; i &lt; vec.length; i++) {<br />      System.out.println(vec[i]);<br />    }<br />  }</p>
		<p>}<br />以下是运行结果：<br />选择法用时为：234<br />56<br />47<br />37<br />23<br />19<br />-5<br />冒泡法用时为：172<br />56<br />47<br />37<br />23<br />19<br />-5<br />插入法用时为：78<br />56<br />47<br />37<br />23<br />19<br />-5<br />快速法用时为：297<br />56<br />47<br />37<br />23<br />19<br />-5  </p>
<img src ="http://www.blogjava.net/os586/aggbug/67032.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/os586/" target="_blank">水煮三国</a> 2006-09-01 10:31 <a href="http://www.blogjava.net/os586/archive/2006/09/01/67032.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Thinking：Java中static、this、super、final用法</title><link>http://www.blogjava.net/os586/archive/2006/08/23/65213.html</link><dc:creator>水煮三国</dc:creator><author>水煮三国</author><pubDate>Wed, 23 Aug 2006 02:15:00 GMT</pubDate><guid>http://www.blogjava.net/os586/archive/2006/08/23/65213.html</guid><wfw:comment>http://www.blogjava.net/os586/comments/65213.html</wfw:comment><comments>http://www.blogjava.net/os586/archive/2006/08/23/65213.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/os586/comments/commentRss/65213.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/os586/services/trackbacks/65213.html</trackback:ping><description><![CDATA[Thinking：Java中static、this、super、final用法 <br />本篇旨在帮助准备学习Java以及刚接触Java的朋友认识、掌握和使用static、this、super、final这几个关键字的使用。Java博大精深，我也是一位正在学习和使用Java的爱好者，文中难免有不妥之处，欢迎指正。<br />一、static<br />请先看下面这段程序：<br />public class Hello{<br />     public static void main(String[] args){//(1)<br />          System.out.println("Hello,world!");//(2)<br />        }<br />  }<br />看过这段程序，对于大多数学过Java 的从来说，都不陌生。即使没有学过Java，而学过其它的高级语言，例如C，那你也应该能看懂这段代码的意思。它只是简单的输出“Hello,world”，一点别的用处都没有，然而，它却展示了static关键字的主要用法。 <br />在1处，我们定义了一个静态的方法名为main，这就意味着告诉Java编译器，我这个方法不需要创建一个此类的对象即可使用。你还得你是怎么运行这个程序吗？一般，我们都是在命令行下，打入如下的命令(加下划线为手动输入)：<br />javac Hello.java<br />java Hello<br />Hello,world!<br />这就是你运行的过程，第一行用来编译Hello.java这个文件，执行完后，如果你查看当前，会发现多了一个Hello.class文件，那就是第一行产生的Java二进制字节码。第二行就是执行一个Java程序的最普遍做法。执行结果如你所料。在2中，你可能会想，为什么要这样才能输出。好，我们来分解一下这条语句。（如果没有安装Java文档，请到Sun的官方网站浏览J2SE API）首先，System是位于java.lang包中的一个核心类，如果你查看它的定义，你会发现有这样一行：public static final PrintStream out;接着在进一步，点击PrintStream这个超链接，在METHOD页面，你会看到大量定义的方法，查找println，会有这样一行：<br />public void println(String x)。好了，现在你应该明白为什么我们要那样调用了，out是System的一个静态变量，所以可以直接使用，而out所属的类有一个println方法。<br />静态方法<br />通常，在一个类中定义一个方法为static，那就是说，无需本类的对象即可调用此方法。如下所示：<br />class Simple{<br />   static void go(){<br />        System.out.println("Go...");<br />    }<br />}<br />public class Cal{<br />  public static void main(String[] args){<br />     Simple.go();<br />  }<br />}<br />调用一个静态方法就是“类名.方法名”,静态方法的使用很简单如上所示。一般来说，静态方法常常为应用程序中的其它类提供一些实用工具所用，在Java的类库中大量的静态方法正是出于此目的而定义的。<br />静态变量<br />静态变量与静态方法类似。所有此类实例共享此静态变量，也就是说在类装载时，只分配一块存储空间，所有此类的对象都可以操控此块存储空间，当然对于final则另当别论了。看下面这段代码：<br />class Value{<br /> static int c=0;<br /> static void inc(){<br /> c++;<br />  }<br />}<br />class Count{<br />  public static void prt(String s){<br />    System.out.println(s);<br />  }<br />  public static void main(String[] args){<br />    Value v1,v2;<br />    v1=new Value();<br />    v2=new Value();<br />    prt("v1.c="+v1.c+"  v2.c="+v2.c);<br />    v1.inc();<br />    prt("v1.c="+v1.c+"  v2.c="+v2.c);  <br />  }<br />}<br />结果如下：<br />v1.c=0  v2.c=0<br />v1.c=1  v2.c=1<br />由此可以证明它们共享一块存储区。static变量有点类似于C中的全局变量的概念。值得探讨的是静态变量的初始化问题。我们修改上面的程序：<br />class Value{<br />  static int c=0;<br />  Value(){<br />    c=15;<br />  }<br />  Value(int i){<br />    c=i;<br />  }<br />  static void inc(){<br />    c++;<br />  }<br />}<br />class Count{<br />  public static void prt(String s){<br />    System.out.println(s);<br />  }<br />    Value v=new Value(10);<br />    static Value v1,v2;<br />    static{<br />      prt("v1.c="+v1.c+"  v2.c="+v2.c);<br />      v1=new Value(27);<br />      prt("v1.c="+v1.c+"  v2.c="+v2.c);<br />      v2=new Value(15);<br />      prt("v1.c="+v1.c+"  v2.c="+v2.c);<br />    }<br />  public static void main(String[] args){<br />    Count ct=new Count();<br />    prt("ct.c="+ct.v.c);<br />    prt("v1.c="+v1.c+"  v2.c="+v2.c);<br />    v1.inc();<br />    prt("v1.c="+v1.c+"  v2.c="+v2.c);<br />    prt("ct.c="+ct.v.c);<br />  }<br />}<br />运行结果如下：<br />v1.c=0  v2.c=0<br />v1.c=27  v2.c=27<br />v1.c=15  v2.c=15<br />ct.c=10<br />v1.c=10  v2.c=10<br />v1.c=11  v2.c=11<br />ct.c=11<br />这个程序展示了静态初始化的各种特性。如果你初次接触Java，结果可能令你吃惊。可能会对static后加大括号感到困惑。首先要告诉你的是，static定义的变量会优先于任何其它非static变量，不论其出现的顺序如何。正如在程序中所表现的，虽然v出现在v1和v2的前面，但是结果却是v1和v2的初始化在v的前面。在static{后面跟着一段代码，这是用来进行显式的静态变量初始化，这段代码只会初始化一次，且在类被第一次装载时。如果你能读懂并理解这段代码，会帮助你对static关键字的认识。在涉及到继承的时候，会先初始化父类的static变量，然后是子类的，依次类推。非静态变量不是本文的主题，在此不做详细讨论，请参考Think in Java中的讲解。<br />静态类<br />通常一个普通类不允许声明为静态的，只有一个内部类才可以。这时这个声明为静态的内部类可以直接作为一个普通类来使用，而不需实例一个外部类。如下代码所示：<br />public class StaticCls{<br />  public static void main(String[] args){<br />    OuterCls.InnerCls oi=new OuterCls.InnerCls();<br />  }<br />}<br />class OuterCls{<br />  public static class InnerCls{<br />    InnerCls(){<br />      System.out.println("InnerCls");<br />    }<br />   }<br />}<br />输出结果会如你所料：<br />InnerCls<br />和普通类一样。内部类的其它用法请参阅Think in Java中的相关章节，此处不作详解。<br />二、this &amp; super<br />    在上一篇拙作中，我们讨论了static的种种用法，通过用static来定义方法或成员，为我们编程提供了某种便利，从某种程度上可以说它类似于C语言中的全局函数和全局变量。但是，并不是说有了这种便利，你便可以随处使用，如果那样的话，你便需要认真考虑一下自己是否在用面向对象的思想编程，自己的程序是否是面向对象的。好了，现在开始讨论this&amp;super这两个关键字的意义和用法。<br />在Java中，this通常指当前对象，super则指父类的。当你想要引用当前对象的某种东西，比如当前对象的某个方法，或当前对象的某个成员，你便可以利用this来实现这个目的，当然，this的另一个用途是调用当前对象的另一个构造函数，这些马上就要讨论。如果你想引用父类的某种东西，则非super莫属。由于this与super有如此相似的一些特性和与生俱来的某种关系，所以我们在这一块儿来讨论，希望能帮助你区分和掌握它们两个。<br />在一般方法中<br />最普遍的情况就是，在你的方法中的某个形参名与当前对象的某个成员有相同的名字，这时为了不至于混淆，你便需要明确使用this关键字来指明你要使用某个成员，使用方法是“this.成员名”，而不带this的那个便是形参。另外，还可以用“this.方法名”来引用当前对象的某个方法，但这时this就不是必须的了，你可以直接用方法名来访问那个方法，编译器会知道你要调用的是那一个。下面的代码演示了上面的用法：<br />public class DemoThis{<br />  private String name;<br />  private int age;<br />  DemoThis(String name,int age){<br />    setName(name); //你可以加上this来调用方法，像这样：this.setName(name);但这并不是必须的<br />    setAge(age);<br />    this.print();<br />  }   <br />  public void setName(String name){<br />    this.name=name;//此处必须指明你要引用成员变量<br />  }<br />  public void setAge(int age){<br />    this.age=age;<br />  }<br />  public void print(){<br />    System.out.println("Name="+name+" Age="+age);//在此行中并不需要用this，因为没有会导致混淆的东西<br />  }<br />  public static void main(String[] args){<br />    DemoThis dt=new DemoThis("Kevin","22");<br />  }<br />}<br />这段代码很简单，不用解释你也应该能看明白。在构造函数中你看到用this.print(),你完全可以用print()来代替它，两者效果一样。下面我们修改这个程序，来演示super的用法。<br />class Person{<br />  public int c;<br />  private String name;<br />  private int age;<br />  protected void setName(String name){<br />    this.name=name;<br />  }<br />  protected void setAge(int age){<br />    this.age=age;<br />  }<br />  protected void print(){<br />    System.out.println("Name="+name+" Age="+age);<br />  }<br />}<br />public class DemoSuper extends Person{<br />  public void print(){<br />    System.out.println("DemoSuper:");<br />    super.print();<br />  }<br />  public static void main(String[] args){<br />    DemoSuper ds=new DemoSuper();<br />    ds.setName("kevin");<br />    ds.setAge(22);<br />    ds.print();<br />  }<br />}<br />在DemoSuper中，重新定义的print方法覆写了父类的print方法，它首先做一些自己的事情，然后调用父类的那个被覆写了的方法。输出结果说明了这一点：<br />DemoSuper:<br />Name=kevin Age=22<br />这样的使用方法是比较常用的。另外如果父类的成员可以被子类访问，那你可以像使用this一样使用它，用“super.父类中的成员名”的方式，但常常你并不是这样来访问父类中的成员名的。<br />在构造函数中<br />构造函数是一种特殊的方法，在对象初始化的时候自动调用。在构造函数中，this和super也有上面说的种种使用方式，并且它还有特殊的地方，请看下面的例子：<br />class Person{<br />  public static void prt(String s){<br />    System.out.println(s);<br />  }<br />  Person(){<br />    prt("A Person.");<br />  }<br />  Person(String name){<br />    prt("A person name is:"+name);<br />  }<br />}<br />public class Chinese extends Person{<br />  Chinese(){<br />    super();  //调用父类构造函数（1）<br />    prt("A chinese.");//(4)<br />  }<br />  Chinese(String name){<br />    super(name);//调用父类具有相同形参的构造函数（2）<br />    prt("his name is:"+name);<br />  }<br />  Chinese(String name,int age){<br />    this(name);//调用当前具有相同形参的构造函数（3）<br />    prt("his age is:"+age);<br />  }<br />  public static void main(String[] args){<br />    Chinese cn=new Chinese();<br />    cn=new Chinese("kevin");<br />    cn=new Chinese("kevin",22);<br />  }<br />}<br />在这段程序中，this和super不再是像以前那样用“.”连接一个方法或成员，而是直接在其后跟上适当的参数，因此它的意义也就有了变化。super后加参数的是用来调用父类中具有相同形式的构造函数，如1和2处。this后加参数则调用的是当前具有相同参数的构造函数，如3处。当然，在Chinese的各个重载构造函数中，this和super在一般方法中的各种用法也仍可使用，比如4处，你可以将它替换为“this.prt”(因为它继承了父类中的那个方法）或者是“super.prt”（因为它是父类中的方法且可被子类访问），它照样可以正确运行。但这样似乎就有点画蛇添足的味道了。<br />最后，写了这么多，如果你能对“this通常指代当前对象，super通常指代父类”这句话牢记在心，那么本篇便达到了目的，其它的你自会在以后的编程实践当中慢慢体会、掌握。另外关于本篇中提到的继承，请参阅相关Java教程。<br />三、final<br />final在Java中并不常用，然而它却为我们提供了诸如在C语言中定义常量的功能，不仅如此，final还可以让你控制你的成员、方法或者是一个类是否可被覆写或继承等功能，这些特点使final在Java中拥有了一个不可或缺的地位，也是学习Java时必须要知道和掌握的关键字之一。<br />final成员<br />当你在类中定义变量时，在其前面加上final关键字，那便是说，这个变量一旦被初始化便不可改变，这里不可改变的意思对基本类型来说是其值不可变，而对于对象变量来说其引用不可再变。其初始化可以在两个地方，一是其定义处，也就是说在final变量定义时直接给其赋值，二是在构造函数中。这两个地方只能选其一，要么在定义时给值，要么在构造函数中给值，不能同时既在定义时给了值，又在构造函数中给另外的值。下面这段代码演示了这一点：<br />import java.util.List;<br />import java.util.ArrayList;<br />import java.util.LinkedList;<br />public class Bat{<br />    final PI=3.14;          //在定义时便给址值<br />    final int i;            //因为要在构造函数中进行初始化，所以此处便不可再给值<br />    final List list;        //此变量也与上面的一样<br />    Bat(){<br />        i=100;<br />        list=new LinkedList();<br />    }<br />    Bat(int ii,List l){<br />        i=ii;<br />        list=l;<br />    }<br />    public static void main(String[] args){<br />        Bat b=new Bat();<br />        b.list.add(new Bat());<br />        //b.i=25;<br />        //b.list=new ArrayList();<br />        System.out.println("I="+b.i+" List Type:"+b.list.getClass());<br />        b=new Bat(23,new ArrayList());<br />        b.list.add(new Bat());<br />        System.out.println("I="+b.i+" List Type:"+b.list.getClass());<br />    }<br />}<br />此程序很简单的演示了final的常规用法。在这里使用在构造函数中进行初始化的方法，这使你有了一点灵活性。如Bat的两个重载构造函数所示，第一个缺省构造函数会为你提供默认的值，重载的那个构造函数会根据你所提供的值或类型为final变量初始化。然而有时你并不需要这种灵活性，你只需要在定义时便给定其值并永不变化，这时就不要再用这种方法。在main方法中有两行语句注释掉了，如果你去掉注释，程序便无法通过编译，这便是说，不论是i的值或是list的类型，一旦初始化，确实无法再更改。然而b可以通过重新初始化来指定i的值或list的类型，输出结果中显示了这一点：<br />I=100 List Type:class java.util.LinkedList<br />I=23 List Type:class java.util.ArrayList<br />还有一种用法是定义方法中的参数为final，对于基本类型的变量，这样做并没有什么实际意义，因为基本类型的变量在调用方法时是传值的，也就是说你可以在方法中更改这个参数变量而不会影响到调用语句，然而对于对象变量，却显得很实用，因为对象变量在传递时是传递其引用，这样你在方法中对对象变量的修改也会影响到调用语句中的对象变量，当你在方法中不需要改变作为参数的对象变量时，明确使用final进行声明，会防止你无意的修改而影响到调用方法。<br />另外方法中的内部类在用到方法中的参变量时，此参变也必须声明为final才可使用，如下代码所示：<br />public class INClass{<br />   void innerClass(final String str){<br />        class IClass{<br />            IClass(){<br />                System.out.println(str);<br />            }<br />        }<br />        IClass ic=new IClass();<br />    }<br />  public static void main(String[] args){<br />      INClass inc=new INClass();<br />      inc.innerClass("Hello");<br />  }<br />}<br />final方法<br />将方法声明为final，那就说明你已经知道这个方法提供的功能已经满足你要求，不需要进行扩展，并且也不允许任何从此类继承的类来覆写这个方法，但是继承仍然可以继承这个方法，也就是说可以直接使用。另外有一种被称为inline的机制，它会使你在调用final方法时，直接将方法主体插入到调用处，而不是进行例行的方法调用，例如保存断点，压栈等，这样可能会使你的程序效率有所提高，然而当你的方法主体非常庞大时，或你在多处调用此方法，那么你的调用主体代码便会迅速膨胀，可能反而会影响效率，所以你要慎用final进行方法定义。<br />final类<br />当你将final用于类身上时，你就需要仔细考虑，因为一个final类是无法被任何人继承的，那也就意味着此类在一个继承树中是一个叶子类，并且此类的设计已被认为很完美而不需要进行修改或扩展。对于final类中的成员，你可以定义其为final，也可以不是final。而对于方法，由于所属类为final的关系，自然也就成了final型的。你也可以明确的给final类中的方法加上一个final，但这显然没有意义。<br />下面的程序演示了final方法和final类的用法：<br />final class final{<br />      final String str="final Data";<br />      public String str1="non final data";<br />      final public void print(){<br />           System.out.println("final method.");<br />      }<br />      public void what(){<br />             System.out.println(str+"\n"+str1);<br />     }<br />}<br />public class FinalDemo{//extends final无法继承<br />        public static void main(String[] args){<br />              final f=new final();<br />               f.what();<br />               f.print();<br />    }<br />}<br />从程序中可以看出，final类与普通类的使用几乎没有差别，只是它失去了被继承的特性。final方法与非final方法的区别也很难从程序行看出，只是记住慎用。<br />final在设计模式中的应用<br />在设计模式中有一种模式叫做不变模式，在Java中通过final关键字可以很容易的实现这个模式，在讲解final成员时用到的程序Bat.java就是一个不变模式的例子。如果你对此感兴趣，可以参考阎宏博士编写的《Java与模式》一书中的讲解。<br />到此为止，this,static,supert和final的使用已经说完了，如果你对这四个关键字已经能够大致说出它们的区别与用法，那便说明你基本已经掌握。然而，世界上的任何东西都不是完美无缺的，Java提供这四个关键字，给程序员的编程带来了很大的便利，但并不是说要让你到处使用，一旦达到滥用的程序，便适得其反，所以在使用时请一定要认真考虑。<img src ="http://www.blogjava.net/os586/aggbug/65213.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/os586/" target="_blank">水煮三国</a> 2006-08-23 10:15 <a href="http://www.blogjava.net/os586/archive/2006/08/23/65213.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>设计模式：Builder建造者模式</title><link>http://www.blogjava.net/os586/archive/2006/08/15/63627.html</link><dc:creator>水煮三国</dc:creator><author>水煮三国</author><pubDate>Tue, 15 Aug 2006 02:41:00 GMT</pubDate><guid>http://www.blogjava.net/os586/archive/2006/08/15/63627.html</guid><wfw:comment>http://www.blogjava.net/os586/comments/63627.html</wfw:comment><comments>http://www.blogjava.net/os586/archive/2006/08/15/63627.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/os586/comments/commentRss/63627.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/os586/services/trackbacks/63627.html</trackback:ping><description><![CDATA[其实我对建造者模式的理解，倒是有些聚合合并的原则在里面．这只是我个人的理解．<br /><br />但是对于建造者模式来说：对于客户端来说，相关的产品内部的元件的建立都是被隐藏的．我们通过相关的角色去完成产品对象及其元件的建立．<br /><br />引用&lt;Java模式&gt;的一句话是这样说的：一个导演者对象和具体建造者对象一个一个地建造出所有的零件，从而建造出完整的产品对象．建造者模式将产品的结构和产品的零件建造过程对客户端隐藏起来，把对建造过程进行指挥的责任和具体建造者零件的责任侵害开来．达到责任划分和封装的目的．<br /><br /><br /><br />我觉得建造者模式当中：相关角色的定义是最为重要的．它们各司其职，而又互不干涉．<br /><br />抽象建造者角色：它是一个抽象接口，给出了建立相关元件的方法及一个返回对象的方法．这个接口必须由具体建造者角色来实现．<br /><br />具体建造者角色：它有两个作用：第一是实现抽象建造者角色声明的方法<br /><br />第二就是提供产品对象的实例．<br /><br /><br />导演者角色：它是一个中间转换类．它实现了构建相关元件的方法，调用具体建造者类．<br /><br />产品角色：具体的产品类的实现．<br /><br /><br /><br /><br /><br /><br /><img src ="http://www.blogjava.net/os586/aggbug/63627.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/os586/" target="_blank">水煮三国</a> 2006-08-15 10:41 <a href="http://www.blogjava.net/os586/archive/2006/08/15/63627.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>相关JAVA站点，欢迎加入</title><link>http://www.blogjava.net/os586/archive/2006/08/02/61348.html</link><dc:creator>水煮三国</dc:creator><author>水煮三国</author><pubDate>Wed, 02 Aug 2006 08:09:00 GMT</pubDate><guid>http://www.blogjava.net/os586/archive/2006/08/02/61348.html</guid><wfw:comment>http://www.blogjava.net/os586/comments/61348.html</wfw:comment><comments>http://www.blogjava.net/os586/archive/2006/08/02/61348.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/os586/comments/commentRss/61348.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/os586/services/trackbacks/61348.html</trackback:ping><description><![CDATA[
		<p>
				<font face="Times New Roman" color="#000000" size="3">
						<strong>
								<span class="tpc_title">J2EE相关站点(欢迎填加)</span>
								<br />
						</strong>
						<span class="tpc_content">
								<a href="http://www.theserverside.com/" target="_blank">
										<font style="FONT-SIZE: 12px; FONT-FAMILY: Courier new" color="#485a68">http://www.theserverside.com</font>
								</a>
								<br />
								<font style="FONT-SIZE: 12px; FONT-FAMILY: Courier new">权威的的J2EE站点，有最新的消息发布和很多技术文章以及很好的论坛，进行J2EE相关技术的全方位的讨论，也有电子书可以下载。<br /><br /></font>
								<a href="http://www.javaworld.com/" target="_blank">
										<font style="FONT-SIZE: 12px; FONT-FAMILY: Courier new" color="#485a68">http://www.javaworld.com</font>
								</a>
								<br />
								<font style="FONT-SIZE: 12px; FONT-FAMILY: Courier new">很著名的国外的java技术站点。有一段时间由于一些原因停止了更新，不过不久前有开始了更新的工作。<br /><br /></font>
								<a href="http://www-900.ibm.com/developerWorks/cn/java/index.shtml" target="_blank">
										<font style="FONT-SIZE: 12px; FONT-FAMILY: Courier new" color="#485a68">http://www-900.ibm.com/developerWorks/cn/java/index.shtml</font>
								</a>
								<br />
								<font style="FONT-SIZE: 12px; FONT-FAMILY: Courier new">IBM公司的developerWorks Java技术专区，有很多关于J2EE的技术文章，并且文章的质量很高。<br /><br /></font>
								<a href="http://www.jdon.com/" target="_blank">
										<font style="FONT-SIZE: 12px; FONT-FAMILY: Courier new" color="#485a68">http://www.jdon.com</font>
								</a>
								<br />
								<font style="FONT-SIZE: 12px">国内不错的J2EE技术站点，有很多技术文章和源代码。以前推出过汉化的JIVE版本，现在有了自己的J2EE框架产品。<br /><br /></font>
								<a href="http://www.huihoo.com/" target="_blank">
										<font color="#485a68" size="2">http://www.huihoo.com</font>
								</a>
								<br />
								<font style="FONT-SIZE: 12px">专注于中间件技术的站点和论坛，国内开源软件做的相当不错的组织，推出了自己的J2EE服务器产品JFox以及相关的OpenSource 产品。<br /><br /></font>
								<a href="http://gceclub.sun.com.cn/" target="_blank">
										<font style="FONT-SIZE: 12px" color="#485a68">http://gceclub.sun.com.cn</font>
								</a>
								<br />
								<font size="2">SUN的中文技术社区，有SUN 的技术人员的支持维护，很多不错的文章，在线讲堂栏目办的很有特色。推出了新版的技术论坛，但是人气一直不是很旺。<br /><br /></font>
								<a href="http://www.cnjsp.org/" target="_blank">
										<font style="FONT-SIZE: 12px" color="#485a68">http://www.cnjsp.org</font>
								</a>
								<br />
								<font style="FONT-SIZE: 12px">以前做过JSP的论坛，现在定位于Java技术服务，提供一些J2EE的技术文章，还不错。<br /><br /></font>
								<a href="http://www.chinajavaworld.net/" target="_blank">
										<font style="FONT-SIZE: 12px" color="#485a68">http://www.chinajavaworld.net</font>
								</a>
								<br />
								<font style="FONT-SIZE: 12px">应该是国内最著名和热门的java技术站点了，有很j2ee的信息和技术文章和很好的论坛。<br /><br /></font>
								<a href="http://www.csdn.net/" target="_blank">
										<font style="FONT-SIZE: 12px" color="#485a68">http://www.csdn.net</font>
								</a>
								<br />
								<font style="FONT-SIZE: 12px">程序员都知道的网站:)也把它列进来。有最新的java业界动态和技术文章可以查找。<br /></font>
						</span>这两个网站都是台湾省的所以都是繁体中文，不过并不影响大家的阅读速度。<br /><br /><a href="http://www.javaworld.com.tw/" target="_blank">http://www.javaworld.com.tw</a><br /><br /><a href="http://www.caterpillar.onlyfun.net/phpBB2/index.php" target="_blank">http://www.caterpillar.onlyfun.net/phpBB2/index.php</a><br /><!----><br /><p style="FONT-SIZE: 12px">Java学习网站   <br />  http://www-900.ibm.com/developerWorks/cn/java/index.shtml  IBM的JAVA专题——永远的蓝色巨人 <br />  http://www.huihoo.com   灰狐动力——Enterprise Open Source <br />  http://www.jdon.com   J道——JAVA和J2EE解决之道 <br />  http://www.chinaunix.net   ChinaUnix——我们在努力打造一个Unix时代！ <br />  http://www.theserverside.com   TheServerSide.COM——Your Enterprise Java Community <br />  http://www.onjava.com   O'REILLY ON java.com <br />  http://www.matrix.org.cn   Matrix与Java共舞 <br />  http://www.java-source.net   JavaSource <br />  http://www.javaresearch.org   Java研究组织——汇聚技术精英,增进技术交流 <br />  http://www.cn-java.com   中文Java技术网——为Java爱好者服务 <br />  http://www.javalobby.org   JavaLobby <br />  http://www.javajia.com   Java家 <br />  http://www.cnjavaclub.com   中国JAVA俱乐部 <br />  http://www.jspcn.net   JSP中文网 <br />  http://www.cnjsp.org   中国JSP技术网站 <br />  http://www.xuejava.com   学Java——学习Java的精髓 <br />  http://tech.ccidnet.com   赛迪网技术天地 <br />  http://www.uml.org.cn   UML软件工程组织 <br />  http://dev2dev.bea.com.cn/index.jsp   BEAdev2dev在线 <br />  http://www.kissjava.com   爪哇流氓 <br />  http://java.about.com   来自About.com的Java新闻和技术文章 <br />  http://www.jcp.org/en/home/index   Java Community Process <br />  http://www.java-cn.com   Java中文站——每一天我们都在进步 <br />  http://www.chedong.com/   车东 <br />  http://www.javayou.com/   Java自由人 <br />  http://www.j2medev.com/   J2ME开发网 <br /></p></font>
		</p>
		<p>
		</p>
		<p>
		</p>
		<font color="#000000" style="font-size:12px;font-family:courier new">
				<p>
						<font style="FONT-SIZE: 12px; FONT-FAMILY: Courier new" color="#000000">http://www.javadown.com.cn<br /></font>
						<font face="Times New Roman" color="#000000" style="font-size:12px;font-family:courier new">http://www.java.net/<br /></font>
						<br />Java技术论坛  <br />  http://bbs.chinajavaworld.com      ChinaJavaWorld技术论坛 <br />  http://www.javaworld.com.tw/jute/index.html   JavaWorld技术论坛 <br />  http://forum.javaeye.com   Java视线论坛 <br />  http://www.jdon.com/jive/index.jsp   J道论坛 <br />  http://gceclub.sun.com.cn/NASApp/sme/jive/index.jsp   Sun技术社区论坛 <br />  http://www.cjsdn.com   中国Java开发网 <br />  http://spring.jactiongroup.net   SpringFramework中文论坛 <br />  http://www.cartexpert.com/forum/forum.jsp?column=24   Jive研究论坛 <br />  http://www.javafan.net/jive/index.jsp   JavaFan论坛 </p>
				<p>
						<br />Java优秀Blog   <br /><a href="http://javazhai.mblogger.cn/">javazhai.mblogger.cn</a> <br /><a href="http://blog.donews.com/redtroy/">http://blog.donews.com/redtroy/</a><br />  http://blog.csdn.net/casularm   Casularm Blog <br />  http://hedong.3322.org   竹笋炒肉 <br />  http://blog.csdn.net/baijsp   Java and OpenSource Software <br />  http://leosky.java.mblogger.cn   leo的Blog <br />  http://java2guru.java.mblogger.cn   J2EE Blog <br />  http://blog.csdn.net/chenyun2000   Open Java Project <br />  http://gigix.blogdriver.com/gigix/index.html   透明思考 <br />  http://blog.tomxp.com/Home.html   东波的Blog <br />  http://blog.csdn.net/liaoxingya276   liaoxingya的Blog <br />  http://blog.csdn.net/arielxp   !Java <br />  http://www.nncn.com/blog/weblog.php   HuiFei's Blog <br />  http://www.donews.net/yahoo163/   BlogJava </p>
				<p>
						<br />Java热门QQ群  <br />  6927954   Java爱好者   5747018   Java开源框架研究 <br />  2184090   Java最后通道   5464040   Java技术交流 <br />  6090680   Java讨论组   6868040   Java讨论区 <br />  2848217   Java技术交流   5287881   Java社团 <br />  3057466   Java世界   3657130   Java夜未眠 <br />  4874250   Java开发者   6522650   Java联盟 <br />  4972763   Java爱好者   6880123   Java技术交流 <br />  2473372   Java学习班   6347116   Java学院 <br />  3049837   Java人生路   1407900   Java爱好者 <br />  2371661   Java最爱   7096701   Java思想与技术 <br />  4421567   Java菜鸟交流室   3493424   Java学习班 <br />  1822386   Java学习小组   3905714   Java乐园 <br />  4085683   Java疯狂编程   5718771   Java社区 <br />  4578000   Jsp技术群   4384534   Jsp学习组 <br />  4617990   Jsp学习班   1845656   Jsp爱好者 <br />  2493314   Jsp交流中心   3241217   Jsp专题学习 <br />  6788666   Jsp爱好者   3417234   Jsp交流 <br />  7378475   开发联盟Jsp学习   2347397   Java和Jsp技术讨论 <br />  1020937   Jsp   1693379   Jsp <br />  200016    J2ME   4453572   J2ME <br />  6074752   J2ME   4835602   J2ME <br />  1772284   J2ME   155348    开发联盟 WAP J2ME </p>
		</font>
		<p>
				<font color="#000000" style="font-size:12px;font-family:courier new">源代码下载!<br />基于j2ee平台的大型电子商务网站源代码下载 :</font>
		</p>
		<p>
				<font style="FONT-SIZE: 12px; FONT-FAMILY: Courier new" color="#000000">本源代码可以帮助大家了解大型物品买卖和交换网站如淘宝，易宝乐等网站的开发和创建。<br />下载地址: http://www.ebaole.com/sourcedown.html<br />并且开辟了一个社区专门为大家提供源代码的交流和讨论!<br /><!--    HEADER    --> </font>
		</p>
		<h1>Online Resources for Java Programmers </h1>
		<p>
		</p>
		<p>The Web offers many resources to help you use the Java platform. This section lists some that we use ourselves, or that we've heard good things about. </p>
		<p>
		</p>
		<blockquote>
				<hr />
				<strong>Caveat:</strong> A Web site that's good one year might stagnate the next, and it can be difficult to tell unless you know the site well. Please <a href="http://javazhai.cnblogs.com/forms/sendusmail.html" target="_top">tell us</a> if any of these Web sites is obsolete, or if you have a URL for an excellent resource not mentioned here. 
<hr /></blockquote>
		<p>We list three kinds of resources: </p>
		<dt>
				<a href="http://javazhai.cnblogs.com/admin/#general">General Programming Resources</a>
		</dt>
		<dd>Web sites that provide information useful to most developers. 
</dd>
		<dt>
				<a href="http://javazhai.cnblogs.com/admin/#subset">Specialized Programming Resources</a>
		</dt>
		<dd>Sources of more specialized programming information. Examples include assorted tutorials, The Swing Connection, and a Web site for Macintosh programmers. 
</dd>
		<dt>
				<a href="http://javazhai.cnblogs.com/admin/#other">Other Resources</a>
		</dt>
		<dd>Other stuff, such as the latest industry news. 
<dl></dl>Don't forget that our <a href="http://javazhai.cnblogs.com/index.html">Tutorial</a> has many examples, and that you can <a href="http://java.sun.com/search/index.jsp?tab=jsc&amp;docs=tutorial" target="_blank"><font color="#009bbb">search all the java.sun.com tutorials</font></a><a href="http://java.sun.com/search/index.jsp?tab=jsc&amp;docs=tutorial" target="_blank"><img height="11" alt=" (outside of the tutorial)" src="http://javazhai.cnblogs.com/images/otherIcon.gif" width="11" align="middle" border="0" /></a>. Another source of resources is the <a href="http://servlet.java.sun.com/help/" target="_blank"><font color="#009bbb">Help section</font></a><a href="http://servlet.java.sun.com/help/" target="_blank"><img height="11" alt=" (outside of the tutorial)" src="http://javazhai.cnblogs.com/images/otherIcon.gif" width="11" align="middle" border="0" /></a> of java.sun.com. 
<p><a name="general"><h2>General Programming Resources</h2></a></p><p></p><p></p><p></p><p></p><blockquote><strong>The Java Developer Connection<sup><font size="-2">SM</font></sup><br /><a href="http://developer.java.sun.com/" target="_blank"><font color="#009bbb">http://developer.java.sun.com</font></a><a href="http://developer.java.sun.com/" target="_blank"><img height="11" alt=" (outside of the tutorial)" src="http://javazhai.cnblogs.com/images/otherIcon.gif" width="11" align="middle" border="0" /></a></strong><blockquote><p>Essential. Here are some of the things you can do at the JDC: </p><ul><li>research bugs 
</li><li>vote for which bugs should be fixed first 
</li><li>view tutorials and book samples 
</li><li>download early access software 
</li><li>chat with developers and API architects </li></ul></blockquote><strong>Code Conventions <br /><a href="http://java.sun.com/docs/codeconv/" target="_blank"><font color="#009bbb">http://java.sun.com/docs/codeconv/</font></a><a href="http://java.sun.com/docs/codeconv/" target="_blank"><img height="11" alt=" (outside of the tutorial)" src="http://javazhai.cnblogs.com/images/otherIcon.gif" width="11" align="middle" border="0" /></a></strong><blockquote>Conventions that developers within Sun try to follow when writing programs in the Java programming language. </blockquote><strong>About.com Focus on Java <br /><a href="http://java.about.com/" target="_blank"><font color="#009bbb">http://java.about.com</font></a><a href="http://java.about.com/" target="_blank"><img height="11" alt=" (outside of the tutorial)" src="http://javazhai.cnblogs.com/images/otherIcon.gif" width="11" align="middle" border="0" /></a></strong><blockquote>Has articles and links to many resources. </blockquote><strong>JavaWorld Magazine <br /><a href="http://www.javaworld.net/" target="_blank"><font color="#009bbb">http://www.javaworld.net</font></a><a href="http://www.javaworld.net/" target="_blank"><img height="11" alt=" (outside of the tutorial)" src="http://javazhai.cnblogs.com/images/otherIcon.gif" width="11" align="middle" border="0" /></a></strong><blockquote>Has articles about current programming topics. </blockquote><strong>Java Boutique <br /><a href="http://javaboutique.internet.com/" target="_blank"><font color="#009bbb">http://javaboutique.internet.com</font></a><a href="http://javaboutique.internet.com/" target="_blank"><img height="11" alt=" (outside of the tutorial)" src="http://javazhai.cnblogs.com/images/otherIcon.gif" width="11" align="middle" border="0" /></a></strong><blockquote>Has applets (some including source code), tutorials, book reviews, and more. </blockquote><strong>Java Developer's Journal <br /><a href="http://www.sys-con.com/java/" target="_blank"><font color="#009bbb">http://www.sys-con.com/java/</font></a><a href="http://www.sys-con.com/java/" target="_blank"><img height="11" alt=" (outside of the tutorial)" src="http://javazhai.cnblogs.com/images/otherIcon.gif" width="11" align="middle" border="0" /></a></strong><blockquote>An online subset of a print magazine. Includes source code and selected articles. </blockquote></blockquote><a name="subset"><h2>Specialized Programming Resources</h2></a><blockquote><strong>The J2EE<font size="-2"><sup>TM</sup></font> Tutorial <br /><a href="http://java.sun.com/j2ee/tutorial/index.html" target="_blank"><font color="#009bbb">http://java.sun.com/j2ee/tutorial/index.html</font></a><a href="http://java.sun.com/j2ee/tutorial/index.html" target="_blank"><img height="11" alt=" (outside of the tutorial)" src="http://javazhai.cnblogs.com/images/otherIcon.gif" width="11" align="middle" border="0" /></a><br /></strong><blockquote>A beginner's guide to developing enterprise applications on the Java 2 Platform, Enterprise Edition SDK. </blockquote><p><strong>Java 3D<font size="-2"><sup>TM</sup></font> API Tutorial <br /><a href="http://java.sun.com/products/java-media/3D/collateral/" target="_blank"><font color="#009bbb">http://java.sun.com/products/java-media/3D/collateral/</font></a><a href="http://java.sun.com/products/java-media/3D/collateral/" target="_blank"><img height="11" alt=" (outside of the tutorial)" src="http://javazhai.cnblogs.com/images/otherIcon.gif" width="11" align="middle" border="0" /></a><br /></strong></p><blockquote>Has descriptions and examples of the most commonly used features in the Java 3D API. </blockquote><p><strong>XML Technologies <br /><a href="http://java.sun.com/xml/tutorial_intro.html" target="_blank"><font color="#009bbb">http://java.sun.com/xml/tutorial_intro.html</font></a><a href="http://java.sun.com/xml/tutorial_intro.html" target="_blank"><img height="11" alt=" (outside of the tutorial)" src="http://javazhai.cnblogs.com/images/otherIcon.gif" width="11" align="middle" border="0" /></a><br /></strong></p><blockquote>Introduces XML and tells you how to use the Java XML APIs. </blockquote><p><strong>The JNDI Tutorial <br /><a href="http://java.sun.com/products/jndi/tutorial/" target="_blank"><font color="#009bbb">http://java.sun.com/products/jndi/tutorial/</font></a><a href="http://java.sun.com/products/jndi/tutorial/" target="_blank"><img height="11" alt=" (outside of the tutorial)" src="http://javazhai.cnblogs.com/images/otherIcon.gif" width="11" align="middle" border="0" /></a><br /></strong></p><blockquote>Tells you how to use the Java<font size="-2"><sup>TM</sup></font> Naming and Directory Interface (JNDI) for associating names and attributes with objects. </blockquote><p><strong>JDC Tutorials <br /><a href="http://developer.java.sun.com/developer/onlineTraining/" target="_blank"><font color="#009bbb">http://developer.java.sun.com/developer/onlineTraining/</font></a><a href="http://developer.java.sun.com/developer/onlineTraining/" target="_blank"><img height="11" alt=" (outside of the tutorial)" src="http://javazhai.cnblogs.com/images/otherIcon.gif" width="11" align="middle" border="0" /></a><br /></strong></p><blockquote>Many tutorials, covering a wealth of topics. Subjects include JavaBeans, Enterprise JavaBeans, JDBC, and Java 2D. </blockquote><p><strong>The Swing Connection <br /><a href="http://java.sun.com/products/jfc/tsc/" target="_blank"><font color="#009bbb">http://java.sun.com/products/jfc/tsc/</font></a><a href="http://java.sun.com/products/jfc/tsc/" target="_blank"><img height="11" alt=" (outside of the tutorial)" src="http://javazhai.cnblogs.com/images/otherIcon.gif" width="11" align="middle" border="0" /></a><br /></strong></p><blockquote>The Swing engineering team's Web site. Has articles written both by Swing creators and by external programmers who use Swing. </blockquote><p><strong>The Swing/JFC FAQ <br /><a href="http://www.drye.com/java/faq.html" target="_blank"><font color="#009bbb">http://www.drye.com/java/faq.html</font></a><a href="http://www.drye.com/java/faq.html" target="_blank"><img height="11" alt=" (outside of the tutorial)" src="http://javazhai.cnblogs.com/images/otherIcon.gif" width="11" align="middle" border="0" /></a><br /></strong></p><blockquote>Unofficial answers to frequently asked questions about Swing. </blockquote><p><strong>Apple's Developer Site <br /><a href="http://developer.apple.com/java/" target="_blank"><font color="#009bbb">http://developer.apple.com/java/</font></a><a href="http://developer.apple.com/java/" target="_blank"><img height="11" alt=" (outside of the tutorial)" src="http://javazhai.cnblogs.com/images/otherIcon.gif" width="11" align="middle" border="0" /></a></strong></p><blockquote>For programmers who use Macs. </blockquote></blockquote><a name="other"><h2>Other Resources</h2></a><blockquote><strong>How To Write Unmaintainable Code <br /><a href="http://mindprod.com/unmain.html" target="_blank"><font color="#009bbb">http://mindprod.com/unmain.html</font></a><a href="http://mindprod.com/unmain.html" target="_blank"><img height="11" alt=" (outside of the tutorial)" src="http://javazhai.cnblogs.com/images/otherIcon.gif" width="11" align="middle" border="0" /></a></strong><blockquote>Long, funny essay on how (not) to write code that no one else can read. </blockquote><strong>Slashdot <br /><a href="http://slashdot.org/search.pl?topic=108" target="_blank"><font color="#009bbb">http://slashdot.org/search.pl?topic=108</font></a><a href="http://slashdot.org/search.pl?topic=108" target="_blank"><img height="11" alt=" (outside of the tutorial)" src="http://javazhai.cnblogs.com/images/otherIcon.gif" width="11" align="middle" border="0" /></a></strong><blockquote>News and discussions about the Java platform. </blockquote></blockquote></dd>
<img src ="http://www.blogjava.net/os586/aggbug/61348.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/os586/" target="_blank">水煮三国</a> 2006-08-02 16:09 <a href="http://www.blogjava.net/os586/archive/2006/08/02/61348.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>讨论：Java 接口当中的 “常量接口”</title><link>http://www.blogjava.net/os586/archive/2006/08/02/61342.html</link><dc:creator>水煮三国</dc:creator><author>水煮三国</author><pubDate>Wed, 02 Aug 2006 07:41:00 GMT</pubDate><guid>http://www.blogjava.net/os586/archive/2006/08/02/61342.html</guid><wfw:comment>http://www.blogjava.net/os586/comments/61342.html</wfw:comment><comments>http://www.blogjava.net/os586/archive/2006/08/02/61342.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/os586/comments/commentRss/61342.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/os586/services/trackbacks/61342.html</trackback:ping><description><![CDATA[
		<p style="FONT-SIZE: 12px; FONT-FAMILY: Courier new">Java接口当中有一个类型为常量接口，我在网上看到有些人不提倡使用这种方式。具体的原因也没怎么讲，但是在这里我还是想与大家讨论一下这个接口方式的使用。<br /><br />希望有对此接口使用方式有深刻了解的网友能够多提意见：<br /><br />今天朋友发来邮件谈起这种接口方式，说她写的程序当中的最后一句有错，让 我帮着看看：下面是这段程序的源码<br /><br />interface Math<br />{<br />  double PI=3.1415926;<br />}<br />class Arithmetic implements Math<br />{<br />  double roudeArea(double radius)<br />     {<br />         return PI*radius*radius;<br />     }<br />}<br />class Student<br />{<br />   public static void main(String[] args)<br />     {<br />       Arithmetic a=new Arithmetic();<br />       System.out.println(a.roudeArea(3));<br />       System.out.println(Math.PI);<br />       System.out.println(Arithmetic.PI);<br />       System.out.println(a.PI);<br />      }<br />}<br /><br /><br /><br />我在eclipse里面看了，是一个警告原因就在于她用a.PI来取得常量值的方式的警告。<br /><br />其实原因很简单，就是一个静态字段需要在一个静态方法中使用的警告。<br /><br />看了这段代码后，我发现其实她使用常量接口的作用已经在实现了接口Maths的类中体现。就是我们可以在实现常量接口的类中直接使用常量而不必加上前面的对象，当然使用Math.PI也是对的，不过为了方便我们可以在这个类当中直接使用PI去代替它。<br /><br />同样我们也可以使用类Arithmetic当中的PI，我们可以直接引用arithmetic.PI,但是我们不能够使用a.PI<br /><br />类当中的常量定义对其它类来说是可见可用的：他的使用可以以 类名.常量名 即可<br /><br />而接口当中：对其它类来说是不可见的，除非我们需要去实现这个接口，只有实现它我们才可以直接使用 常量名 的方式<br /><br />常量接口当中定义的常量，在实现这个接口的类当中可以直接拿来使用。它里面没有相关属性和其它方法。还有一点就是：常量在使用起来更为简洁。<br /><br /></p>
<img src ="http://www.blogjava.net/os586/aggbug/61342.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/os586/" target="_blank">水煮三国</a> 2006-08-02 15:41 <a href="http://www.blogjava.net/os586/archive/2006/08/02/61342.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JAVA 当中 接口的使用总结</title><link>http://www.blogjava.net/os586/archive/2006/08/02/61340.html</link><dc:creator>水煮三国</dc:creator><author>水煮三国</author><pubDate>Wed, 02 Aug 2006 07:22:00 GMT</pubDate><guid>http://www.blogjava.net/os586/archive/2006/08/02/61340.html</guid><wfw:comment>http://www.blogjava.net/os586/comments/61340.html</wfw:comment><comments>http://www.blogjava.net/os586/archive/2006/08/02/61340.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/os586/comments/commentRss/61340.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/os586/services/trackbacks/61340.html</trackback:ping><description><![CDATA[转自Cnblogs.com<br /><br /><h1><span>法则</span><span lang="EN-US">2</span><span>：针对接口编程，而非（接口的）实现</span></h1><p><b><i><span lang="EN-US">[ Program To An Interface, Not An Implementation ]</span></i></b></p><h2><span>接口</span></h2><p><span lang="EN-US"><span>n<span>         </span></span><i><span>接口</span></i><span>是一个对象在对其它的对象进行调用时所知道的方法集合。</span></span></p><p><span lang="EN-US"><span>n<span>         </span></span><span>一个对象可以有多个接口（实际上，接口是对象所有方法的一个子集）</span></span></p><p><span lang="EN-US"><span>n<span>         </span></span><i><span>类型</span></i><span>是对象的一个特定的接口。</span></span></p><p><span lang="EN-US"><span>n<span>         </span></span><span>不同的对象可以具有相同的类型，而且一个对象可以具有多个不同的类型。</span></span></p><p><span lang="EN-US"><span>n<span>         </span></span><span>一个对象仅能通过其接口才会被其它对象所了解。</span></span></p><p><span lang="EN-US"><span>n<span>         </span></span><span>某种意义上，接口是以一种非常局限的方式，将“是一种</span><span lang="EN-US">…</span><span>”表达为“一种支持该接口的</span><span lang="EN-US">…</span><span>”。</span></span></p><p><span lang="EN-US"><span>n<span>         </span></span><span>接口是实现插件化（</span><span lang="EN-US">pluggability</span><span>）的关键</span></span></p><h2><span>实现继承和接口继承</span></h2><p><span lang="EN-US"><span>n<span>         </span></span><i><span>实现继承</span></i><span>（<i>类继承</i>）：一个对象的实现是根据另一个对象的实现来定义的。</span></span></p><p><span lang="EN-US"><span>n<span>         </span></span><i><span>接口继承</span></i><span>（<i>子类型化</i>）：描述了一个对象可在什么时候被用来替代另一个对象。</span></span></p><p><span lang="EN-US"><span>n<span>         </span></span><span lang="EN-US">C++</span><span>的继承机制既指类继承，又指接口继承。</span></span></p><p><span lang="EN-US"><span>n<span>         </span></span><span lang="EN-US">C++</span><span>通过继承纯虚类来实现接口继承。</span></span></p><p><span lang="EN-US"><span>n<span>         </span></span><span lang="EN-US">Java</span><span>对接口继承具有单独的语言构造方式－</span><span lang="EN-US">Java</span><span>接口。</span></span></p><p><span lang="EN-US"><span>n<span>         </span></span><span lang="EN-US">Java</span><span>接口构造方式更加易于表达和实现那些专注于对象接口的设计。</span></span></p><h2><span>接口的好处</span></h2><p><span lang="EN-US"><span>n<span>         </span></span><span>优点：</span></span></p><p><span lang="EN-US"><span>F<span>        </span></span><span lang="EN-US">Client</span><span>不必知道其使用对象的具体所属类。</span></span></p><p><span lang="EN-US"><span>F<span>        </span></span><span>一个对象可以很容易地被（实现了相同接口的）的另一个对象所替换。</span></span></p><p><span lang="EN-US"><span>F<span>        </span></span><span>对象间的连接不必硬绑定（</span><span lang="EN-US">hardwire</span><span>）到一个具体类的对象上，因此增加了灵活性。</span></span></p><p><span lang="EN-US"><span>F<span>        </span></span><span>松散藕合（</span><span lang="EN-US">loosens coupling</span><span>）。</span></span></p><p><span lang="EN-US"><span>F<span>        </span></span><span>增加了重用的可能性。</span></span></p><p><span lang="EN-US"><span>F<span>        </span></span><span>提高了（对象）组合的机率，因为被包含对象可以是任何实现了一个指定接口的类。</span></span></p><p><span lang="EN-US"><span>n<span>         </span></span><span>缺点：</span></span></p><p><span lang="EN-US"><span>F<span>        </span></span><span>设计的复杂性略有增加</span></span></p><p><span>（译者注：接口表示“</span><span lang="EN-US">…</span><span>像</span><span lang="EN-US">…</span><span>”（</span><span lang="EN-US">LikeA</span><span>）的关系，继承表示“</span><span lang="EN-US">…</span><span>是</span><span lang="EN-US">…</span><span>”（</span><span lang="EN-US">IsA</span><span>）的关系，组合表示“</span><span lang="EN-US">…</span><span>有</span><span lang="EN-US">…</span><span>”（</span><span lang="EN-US">HasA</span><span>）的关系。）</span></p><h2><span>接口实例</span></h2><p><span lang="EN-US"><font size="5"></font></span></p><p><span lang="EN-US"><font size="5"></font></span></p><p><span>该方法是指其它的一些类可以进行交通工具的驾驶，而不必关心其实际上是（汽车，轮船，潜艇或是其它任何实现了</span><span lang="EN-US">IManeuverabre</span><span>的对象）。</span></p><img src ="http://www.blogjava.net/os586/aggbug/61340.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/os586/" target="_blank">水煮三国</a> 2006-08-02 15:22 <a href="http://www.blogjava.net/os586/archive/2006/08/02/61340.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java 中final,finally,finalized的使用</title><link>http://www.blogjava.net/os586/archive/2006/08/01/61124.html</link><dc:creator>水煮三国</dc:creator><author>水煮三国</author><pubDate>Tue, 01 Aug 2006 01:06:00 GMT</pubDate><guid>http://www.blogjava.net/os586/archive/2006/08/01/61124.html</guid><wfw:comment>http://www.blogjava.net/os586/comments/61124.html</wfw:comment><comments>http://www.blogjava.net/os586/archive/2006/08/01/61124.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/os586/comments/commentRss/61124.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/os586/services/trackbacks/61124.html</trackback:ping><description><![CDATA[final：<br />final可以让你控制你的成员、方法或者是一个类是否可被覆写或继承等功能，这些特点使final在Java中拥有了一个不可或缺的地位，也是学习Java时必须要知道和掌握的关键字之一。<br />final成员<br />当你在类中定义变量时，在其前面加上final关键字，那便是说，这个变量一旦被初始化便不可改变，这里不可改变的意思对基本类型来说是其值不可变，而对于对象变量来说其引用不可再变。其初始化可以在两个地方，一是其定义处，二是在构造函数中，两者只能选其一。<br />下面程序很简单的演示了final的常规用法：<br />public class Test{<br />    final int t = 1; // 在定义时给值<br />    // 或者（两者只能选其一）<br />    final int t;<br />    public Test(){<br />        t = 3; // 构造时给值<br />}<br />}<br /><br />还有一种用法是定义方法中的参数为final，对于基本类型的变量，这样做并没有什么实际意义，因为基本类型的变量在调用方法时是传值的，也就是说你可以在方法中更改这个参数变量而不会影响到调用语句，然而对于对象变量，却显得很实用，因为对象变量在传递时是传递其引用，这样你在方法中对对象变量的修改也会影响到调用语句中的对象变量，当你在方法中不需要改变作为参数的对象变量时，明确使用final进行声明，会防止你无意的修改而影响到调用方法。<br />另外方法中的内部类在用到方法中的参变量时，此参变也必须声明为final才可使用，如下代码所示：<br />public class Test{<br />   void print(final String str){<br />        class InnerTest{<br />            InnerTest (){<br />                System.out.println(str);<br />            }<br />        }<br />        InnerTest it=new InnerTest ();<br />    }<br />  public static void main(String[] args){<br />      Test test=new Test();<br />      test.print("Hello word!!!");<br />  }<br />}<br />final方法<br />将方法声明为final那有两个原因，第一就是说明你已经知道这个方法提供的功能已经满足你要求，不需要进行扩展，并且也不允许任何从此类继承的类来覆写这个方法，但是继承仍然可以继承这个方法，也就是说可以直接使用。第二就是允许编译器将所有对此方法的调用转化为inline（行内）调用的机制，它会使你在调用final方法时，直接将方法主体插入到调用处，而不是进行例行的方法调用，例如保存断点，压栈等，这样可能会使你的程序效率有所提高，然而当你的方法主体非常庞大时，或你在多处调用此方法，那么你的调用主体代码便会迅速膨胀，可能反而会影响效率，所以你要慎用final进行方法定义。<br />final类<br />当你将final用于类身上时，你就需要仔细考虑，因为一个final类是无法被任何人继承的，那也就意味着此类在一个继承树中是一个叶子类，并且此类的设计已被认为很完美而不需要进行修改或扩展。对于final类中的成员，你可以定义其为final，也可以不是final。而对于方法，由于所属类为final的关系，自然也就成了final型的。你也可以明确的给final类中的方法加上一个final，但这显然没有意义。<br /><br />finally:<br />finally 关键字是对 Java 异常处理模型的最佳补充。 finally 结构使代码总会执行，而不管有无异常发生。使用 finally 可以维护对象的内部状态，并可以清理非内存资源。如果没有 finally，您的代码就会很费解。例如，下面的代码说明，在不使用 finally 的情况下您如何编写代码来释放非内存资源：<br /><br />public void writeFile(String filePath, String fileName, String args)<br />            throws IOException<br /><br />    {<br /><br />        FileWriter fw = new FileWriter(filePath + fileName);<br />        try {<br /><br />            fw.write(args);<br />        } catch (IOException e) {<br />            //1<br />            fw.close();<br />            throw e;<br />        }<br />//2<br />        fw.close();<br />    }<br />这段代码创建了一个FileWriter object，并调用 write 方法。在退出该方法之前，您必须关闭FileWriter object，以避免资源漏洞。为了完成这一任务，我们在 //2 处调用 close，它是该方法的最后一条语句。但是，如果 try 块中发生一个异常会怎么样呢？在这种情况下，//2 处的 close 调用永远不会发生。因此，您必须捕获这个异常，并在重新发出这个异常之前在 //1 处插入对 close 的另一个调用。这样就可以确保在退出该方法之前关闭FileWriter object。这样编写代码既麻烦又易于出错，但在没有 finally 的情况下这是必不可少的。有了 finally，前面的代码就可以重写为以下的形式：<br /><br />public void writeFile(String filePath, String fileName, String args)<br />            throws IOException<br /><br />    {<br /><br />        FileWriter fw = new FileWriter(filePath + fileName);<br />        try {<br /><br />            fw.write(args);<br />        } catch (IOException e) {<br />            throw e;<br />        } finally {<br /><br />            fw.close();<br />        }<br />    }<br />finally 块确保 close 方法总被执行，而不管 try 块内是否发出异常。因此，可以确保在退出该方法之前总会调用 close 方法。这样您就可以确信FileWriter object被关闭并且您没有泄漏资源。<br /><br />finalize： <br /><br />　　根据Java语言规范，JVM保证调用finalize函数之前，这个对象是不可达的，但是JVM不保证这个函数一定会被调用。另外，规范还保证finalize函数最多运行一次。<br /><br />　　通常，finalize用于一些不容易控制、并且非常重要资源的释放，例如一些I/O的操作，数据的连接。这些资源的释放对整个应用程序是非常关键的。在这种情况下，程序员应该以通过程序本身管理(包括释放)这些资源为主，以finalize函数释放资源方式为辅，形成一种双保险的管理机制，而不应该仅仅依靠finalize来释放资源。<img src ="http://www.blogjava.net/os586/aggbug/61124.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/os586/" target="_blank">水煮三国</a> 2006-08-01 09:06 <a href="http://www.blogjava.net/os586/archive/2006/08/01/61124.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JAVA 中 final全接触</title><link>http://www.blogjava.net/os586/archive/2006/08/01/61123.html</link><dc:creator>水煮三国</dc:creator><author>水煮三国</author><pubDate>Tue, 01 Aug 2006 00:58:00 GMT</pubDate><guid>http://www.blogjava.net/os586/archive/2006/08/01/61123.html</guid><wfw:comment>http://www.blogjava.net/os586/comments/61123.html</wfw:comment><comments>http://www.blogjava.net/os586/archive/2006/08/01/61123.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/os586/comments/commentRss/61123.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/os586/services/trackbacks/61123.html</trackback:ping><description><![CDATA[转自JR-研究<br /><br /><font face="Arial"><strong>1.final value:<br /></strong>如: 类Thread中的　： <br />public static final int MAX_PRIORITY = 10; <br />// MAX_PRIORITY的值不能再修改,之所以称为final value,是因为此处为primitive type<br /><br /><b>2.final reference:</b><br />如: public final String str = "This is a string";<br />// 指的是Object reference 为final,str不能再改而指向其他的对象,但其指向的对象并不一定不能改变.<br /><br />注:<br />1&gt;我们常会看见函数参数或局部变量常被声明为final,根据变量是primitive还是reference区别考虑.<br />2&gt;.在局部内部类(local inner class)和匿名内部类(anonymous inner class)中不但可以访问外类的成员(包括成员变量和成员函数),还可以访问外类的final 变量.<br /><br /><b>3.final class:</b><br />如:public final class URL extends Object implements Serializable<br />//指URL类不能被继承,cannot be subclassed.<br /><br /><b>4.final method:</b><br />如: 类Thread中的 :　<br />public final void setPriority(int newPriority)<br />//指此方法不能被子类override,final class 中的所有方法都自动为final</font><br /><img src ="http://www.blogjava.net/os586/aggbug/61123.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/os586/" target="_blank">水煮三国</a> 2006-08-01 08:58 <a href="http://www.blogjava.net/os586/archive/2006/08/01/61123.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JAVA中内部类的使用总结</title><link>http://www.blogjava.net/os586/archive/2006/08/01/61121.html</link><dc:creator>水煮三国</dc:creator><author>水煮三国</author><pubDate>Tue, 01 Aug 2006 00:53:00 GMT</pubDate><guid>http://www.blogjava.net/os586/archive/2006/08/01/61121.html</guid><wfw:comment>http://www.blogjava.net/os586/comments/61121.html</wfw:comment><comments>http://www.blogjava.net/os586/archive/2006/08/01/61121.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/os586/comments/commentRss/61121.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/os586/services/trackbacks/61121.html</trackback:ping><description><![CDATA[
		<p>内部类的使用：</p>
		<p>内部类的使用的优缺点：</p>
		<p>   优点：减少了在类文件编译后的产生的字节码文件的大小<br />   缺点：使程序结构不清晰</p>
		<p>使用内部类的注意事项：</p>
		<p>   内部类的使用一般都与所在的外部类有一定的关联，它是在一个类的内部嵌套定义的类，它可以是其它类的成员，也可以在一个语句块的内部定义，还可以在表达式内部匿名定义(匿名内部类)。</p>
		<p>内部类有如下的特性：</p>
		<p>  .一般用在定义它的类或语句块之内，在外部引用它时必须给出完整的名称，名字不能与包含它的数百名相同</p>
		<p> . 可以使用包含它的类的表态和实例成员变量，也可以使用它所在方法的局部变量</p>
		<p> .可以定义为abstract</p>
		<p> .若被声明为static,就变成了顶层类，不能再使用局部变量</p>
		<p> .若想在inner class 中声明任何static成员，则该inner class必须声明为static.</p>
		<p> .匿名类是一种特殊的内部类，它是在一个表达式的内部包含一个完整的类的定义。匿名内部类不需要任何的修饰词。</p>
		<p> .内部类可以使用任何听修饰符，但是如果声明为static类，则等同于一个标准类。</p>
		<p> .如果非表态内部类，就拥有对外部类的所有成员的完全访问权限，包括实例字段和方法。为实现这一行为，非表态内部类存着对外部类的实例的一个隐匿的引用。</p>
		<p> .所以对一个非表态内部类进行实例化需要采用不同语法的new 语句，这种开工的new 语句要求外部类的一个实例，使内部类能在那个实例的上下文中创建。</p>
		<p> .非表态内部类具有一些限制。尤其是，它们不能声明表态初始化列表和表态成员，除非是在常量字段中。此外方法内部声明的内部类不能访问方法的局部变量和参数，除非它们被初始化成final.</p>
		<p>
				<br /> .表态内部类当中可以有表态数据，表态方法或者是又一个表态内部类。而非表态内部类当中不能有静态数据。这是它们的区别。</p>
		<p> .局部内部类：Java内部类也可以是局部的，它可以定义在一个方法甚至一个代码块之内。</p>
		<p> </p>
		<p>有一点需要注意的是，匿名内部类由于没有名字，所以它没有构造函数（但是如果这个匿名内部类继承了一个只含有带参数构造函数的父类，创建它的时候必须带上这些参数，并在实现的过程中使用super关键字调用相应的内容）。如果你想要初始化它的成员变量，有下面几种方法：</p>
		<p>　　如果是在一个方法的匿名内部类，可以利用这个方法传进你想要的参数，不过记住，这些参数必须被声明为final。 </p>
		<p>　　将匿名内部类改造成有名字的局部内部类，这样它就可以拥有构造函数了。 </p>
		<p>　　在这个匿名内部类中使用初始化代码块。 </p>
		<p>　　为什么需要内部类？ </p>
		<p>　　java内部类有什么好处？为什么需要内部类？</p>
		<p>　　首先举一个简单的例子，如果你想实现一个接口，但是这个接口中的一个方法和你构想的这个类中的一个方法的名称，参数相同，你应该怎么办？这时候，你可以建一个内部类实现这个接口。由于内部类对外部类的所有内容都是可访问的，所以这样做可以完成所有你直接实现这个接口的功能。</p>
		<p>　　不过你可能要质疑，更改一下方法的不就行了吗？</p>
		<p>　　的确，以此作为设计内部类的理由，实在没有说服力。</p>
		<p>　　真正的原因是这样的，java中的内部类和接口加在一起，可以的解决常被C++程序员抱怨java中存在的一个问题——没有多继承。实际上，C++的多继承设计起来很复杂，而java通过内部类加上接口，可以很好的实现多继承的效果。<br /><br /><br /><br />下面是使用内部类的几个小例子：<br /><br /> JAVA的内部类的构造方法是不会自动调用，必须在外部类当中的某个方法当中或构造函数当中显示调用才能够正确使用。</p>
		<p>   Class Outer{<br />   <br />        public outer(){<br /> System.out.println("....");<br />       }</p>
		<p>        Class Inner{</p>
		<p> public Innter(){<br /> <br />       System.out.println("inner");<br /> } <br />        }</p>
		<p>       public static void Main(String[] args){</p>
		<p>            Outer a = new Outer();<br />       }<br />}</p>
		<p>这种使用方法不会关系到内部类的输出。因为它并没有显示调用内部类。<br />所以我们应该进行这样的修改：</p>
		<p>  在Outer构造函数中加入 Innter b = new Innter();<br />就可以直接调用它的输出或方法体了。</p>
		<p>不过我们经常使用的还是匿名内部类：</p>
		<p>   class Outer{</p>
		<p>       Outer(){</p>
		<p> (new Inner(){<br />  public void print(){<br />   System.out.println("Inner");<br />   }<br />  }<br /> ).print();<br /> System.out.println("Outer");<br />       }<br />}</p>
		<p> </p>
		<p>
				<br />下面是JAVA的一个源码使用了匿名内部类：<br />/**<br />* "Tokenizes" the entire stream as a single token.<br />*/<br />public class KeywordAnalyzer extends Analyzer {<br />public TokenStream tokenStream(String fieldName,<br />final Reader reader) {<br />return new TokenStream() {<br />private boolean done;<br />private final char[] buffer = new char[1024];<br />public Token next() throws IOException {<br />if (!done) {<br />done = true;<br />StringBuffer buffer = new StringBuffer();<br />int length = 0;<br />while (true) {<br />length = reader.read(this.buffer);<br />if (length == -1) break;<br />buffer.append(this.buffer, 0, length);<br />}<br />String text = buffer.toString();<br />return new Token(text, 0, text.length());<br />}<br />return null;<br />}<br />};<br />}<br />}<br /></p>
<img src ="http://www.blogjava.net/os586/aggbug/61121.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/os586/" target="_blank">水煮三国</a> 2006-08-01 08:53 <a href="http://www.blogjava.net/os586/archive/2006/08/01/61121.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java当中接口与抽象类的思考</title><link>http://www.blogjava.net/os586/archive/2006/07/31/61041.html</link><dc:creator>水煮三国</dc:creator><author>水煮三国</author><pubDate>Mon, 31 Jul 2006 08:35:00 GMT</pubDate><guid>http://www.blogjava.net/os586/archive/2006/07/31/61041.html</guid><wfw:comment>http://www.blogjava.net/os586/comments/61041.html</wfw:comment><comments>http://www.blogjava.net/os586/archive/2006/07/31/61041.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/os586/comments/commentRss/61041.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/os586/services/trackbacks/61041.html</trackback:ping><description><![CDATA[
		<p>在没有好好地研习面向对象设计的设计模式之前，我对Java接口和Java抽象类的认识还是很模糊，很不可理解。</p>
		<p>刚学Java语言时，就很难理解为什么要有接口这个概念，虽说是可以实现所谓的多继承，可一个只有方法名，没有方法体的东西，我实现它又有什么用呢？我从它那什么也得不到，除了一些方法名，我直接在具体类里加入这些方法不就行了吗？</p>
		<p>为什么一定要有抽象类这个概念？为什么就不能把这个父类写成一个具体的类，子类再继承它不就可以了吗？何必弄一个抽象类出来，还要弄一些没有方法体的抽象方法，弄得又象接口又象类的，让人捉摸不定。</p>
		<p>当我开始学习java设计模式，真正走进面向对象设计的大门之后，我才发现，自己对面向对象设计的理解原来是那么的片面，那么的肤浅，根本就没有真正理解面向对象思想的精髓，在某一种程度上还受着面向过程的影响，以为弄出了一个个类，就算是面向对象了，而其实还是被过程所驱使着。</p>
		<p>我还是说说我现在对面向对象思想的理解吧，不一定正确全面，但我想应该还算是比以前略有进步吧。</p>
		<p>
				<strong>面向对象思想，我觉得最关键的就是抽象。</strong>
		</p>
		<p>一个软件设计的好坏，我想很大程度上取决于它的整体架构，而这个整体架构其实就是你对整个宏观商业业务的抽象框架，当代表业务逻辑的高层抽象层结构合理时，你底层的具体实现需要考虑的就仅仅是一些算法和一些具体的业务实现了。当你需要再开发另一个相近的项目时，你以前的抽象层说不定还可以再次利用呢，面对对象的设计，复用的重点其实应该是抽象层的复用，而不是具体某一个代码块的复用，是不是一下子感觉自己对复用理解的高度又上升了一层？^_^</p>
		<p>说到了抽象，我就不能不提到曾让我头痛的Java接口和Java抽象类了，这也是本文我想说的重点。</p>
		<p>既然面向对象设计的重点在于抽象，那Java接口和Java抽象类就有它存在的必然性了。</p>
		<p>Java接口和Java抽象类代表的就是抽象类型，就是我们需要提出的抽象层的具体表现。OOP面向对象的编程，如果要提高程序的复用率，增加程序的可维护性，可扩展性，就必须是面向接口的编程，面向抽象的编程，正确地使用接口、抽象类这些太有用的抽象类型做为你结构层次上的顶层。</p>
		<p>Java接口和Java抽象类有太多相似的地方，又有太多特别的地方，究竟在什么地方，才是它们的最佳位置呢？把它们比较一下，你就可以发现了。</p>
		<p>1、Java接口和Java抽象类最大的一个区别，就在于Java抽象类可以提供某些方法的部分实现，而Java接口不可以，这大概就是Java抽象类唯一的优点吧，但这个优点非常有用。<br />如果向一个抽象类里加入一个新的具体方法时，那么它所有的子类都一下子都得到了这个新方法，而Java接口做不到这一点，如果向一个Java接口里加入一个新方法，所有实现这个接口的类就无法成功通过编译了，因为你必须让每一个类都再实现这个方法才行，这显然是Java接口的缺点。</p>
		<p>2、一个抽象类的实现只能由这个抽象类的子类给出，也就是说，这个实现处在抽象类所定义出的继承的等级结构中，而由于Java语言的单继承性，所以抽象类作为类型定义工具的效能大打折扣。<br />在这一点上，Java接口的优势就出来了，任何一个实现了一个Java接口所规定的方法的类都可以具有这个接口的类型，而一个类可以实现任意多个Java接口，从而这个类就有了多种类型。</p>
		<p>3、从第2点不难看出，Java接口是定义混合类型的理想工具，混合类表明一个类不仅仅具有某个主类型的行为，而且具有其他的次要行为。</p>
		<p>4、结合1、2点中抽象类和Java接口的各自优势，具精典的设计模式就出来了：声明类型的工作仍然由Java接口承担，但是同时给出一个Java抽象类，且实现了这个接口，而其他同属于这个抽象类型的具体类可以选择实现这个Java接口，也可以选择继承这个抽象类，也就是说在层次结构中，Java接口在最上面，然后紧跟着抽象类，哈，这下两个的最大优点都能发挥到极至了。这个模式就是“缺省适配模式”。<br />在Java语言API中用了这种模式，而且全都遵循一定的命名规范：Abstract ＋接口名。</p>
		<p>Java接口和Java抽象类的存在就是为了用于具体类的实现和继承的，如果你准备写一个具体类去继承另一个具体类的话，那你的设计就有很大问题了。Java抽象类就是为了继承而存在的，它的抽象方法就是为了强制子类必须去实现的。</p>
		<p>
				<font color="#000000">使用Java接口和抽象Java类进行变量的类型声明、参数是类型声明、方法的返还类型说明，以及数据类型的转换等。而不要用具体Java类进行变量的类型声明、参数是类型声明、方法的返还类型说明，以及数据类型的转换等。</font>
		</p>
		<p>我想，如果你编的代码里面连一个接口和抽象类都没有的话，也许我可以说你根本没有用到任何设计模式，任何一个设计模式都是和抽象分不开的，而抽象与<font color="#000000">Java接口和抽象Java类</font>又是分不开的。</p>
		<p>理解抽象，理解Java接口和抽象Java类，我想就应该是真正开始用面向对象的思想去分析问题，解决问题了吧</p>
<img src ="http://www.blogjava.net/os586/aggbug/61041.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/os586/" target="_blank">水煮三国</a> 2006-07-31 16:35 <a href="http://www.blogjava.net/os586/archive/2006/07/31/61041.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>转：使用Java中的final变量需要注意的地方</title><link>http://www.blogjava.net/os586/archive/2006/07/28/60473.html</link><dc:creator>水煮三国</dc:creator><author>水煮三国</author><pubDate>Fri, 28 Jul 2006 01:36:00 GMT</pubDate><guid>http://www.blogjava.net/os586/archive/2006/07/28/60473.html</guid><wfw:comment>http://www.blogjava.net/os586/comments/60473.html</wfw:comment><comments>http://www.blogjava.net/os586/archive/2006/07/28/60473.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/os586/comments/commentRss/60473.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/os586/services/trackbacks/60473.html</trackback:ping><description><![CDATA[
		<div class="con_sample">
				<p>对与java中的final变量，java编译器是进行了优化的。每个使用了final类型变量的地方都不会通过连接而进行访问。比如说Test类中使用了Data类中一个final的int数字fNumber=77，这时候，java编译器会将77这个常数编译到Test类的指令码或者常量池中。这样，每次Test类用到fNumber的时候，不会通过引用连接到Data类中进行读取，而是直接使用自己保存在类文件中的副本。
</p>
				<p>
				</p>
				<br />
				<font color="#000080">对与java中的final变量，java编译器是进行了优化的。每个使用了final类型变量的地方都不会通过连接而进行访问。比如说Test类中使用了Data类中一个final的int数字fNumber=77，这时候，java编译器会将77这个常数编译到Test类的指令码或者常量池中。这样，每次Test类用到fNumber的时候，不会通过引用连接到Data类中进行读取，而是直接使用自己保存在类文件中的副本。<br />用程序说话：<br />Test.java:</font>
		</div>
		<div class="con_all">
				<p>
						<font color="#000080">
								<span class="Code">
										<font color="#000080">public class Test{<br /> public static void main(String[] args){<br />  System.out.println(Data.fNumber);<br /> }<br />}</font>
								</span>
						</font>
				</p>
				<p>
						<br />
						<font color="#000080">Data.java:</font>
				</p>
				<p>
						<font color="#000080">
								<span class="Code" twffan="done">
										<font color="#000080">public class Data{<br /> public static final int fNumber=77; <br />}</font>
								</span>
						</font>
				</p>
				<p>
						<font color="#000080">执行命令和结果：</font>
				</p>
				<p>
						<font color="#000080">Microsoft Windows XP [版本 5.1.2600]<br />(C) 版权所有 1985-2001 Microsoft Corp.</font>
				</p>
				<p>
						<font color="#000080">C:\Documents and Settings\zangmeng&gt;cd ..</font>
				</p>
				<p>
						<font color="#000080">C:\Documents and Settings&gt;cd ..</font>
				</p>
				<p>
						<font color="#000080">C:\&gt;javac Test.java</font>
				</p>
				<p>
						<font color="#000080">C:\&gt;java Test<br />77</font>
				</p>
				<p>
						<font color="#000080">C:\&gt;</font>
				</p>
				<p>
						<br />
						<font color="#000080">这时候，我们更改Data.java的内容：<br />public class Data{<br /> public static final int fNumber=777; <br />}</font>
				</p>
				<p>
						<font color="#000080">然后执行如下命令：</font>
				</p>
				<p>
						<font color="#000080">C:\&gt;javac Data.java</font>
				</p>
				<p>
						<font color="#000080">C:\&gt;java Test<br />77</font>
				</p>
				<p>
						<font color="#000080">C:\&gt;</font>
				</p>
				<p>
						<font color="#000080">这里我们看到，虽然Data.java中的fNumber已经更改为777，而且已经重新编译了，但是因为编译器把fNumber的副本保存Test类中，所以在重新编译Test类的前，Test类一直把fNumber认为是77而不是777。下面我们变异Test.java，再执行，看看结果。</font>
				</p>
				<p>
						<font color="#000080">C:\&gt;javac Test.java</font>
				</p>
				<p>
						<font color="#000080">C:\&gt;java Test<br />777</font>
				</p>
				<p>
						<font color="#000080">C:\&gt;<br />这时候，我们看到，重新编译的Test类将新的777数值封装到了自己类中。</font>
				</p>
				<p>
						<font color="#000080">整个过程如下：<br />Microsoft Windows XP [版本 5.1.2600]<br />(C) 版权所有 1985-2001 Microsoft Corp.</font>
				</p>
				<p>
						<font color="#000080">C:\Documents and Settings\zangmeng&gt;cd ..</font>
				</p>
				<p>
						<font color="#000080">C:\Documents and Settings&gt;cd ..</font>
				</p>
				<p>
						<font color="#000080">C:\&gt;javac Test.java</font>
				</p>
				<p>
						<font color="#000080">C:\&gt;java Test<br />77<br />//在这里改变了Data.java的内容<br />C:\&gt;javac Data.java</font>
				</p>
				<p>
						<font color="#000080">C:\&gt;java Test<br />77</font>
				</p>
				<p>
						<font color="#000080">C:\&gt;javac Test.java</font>
				</p>
				<p>
						<font color="#000080">C:\&gt;java Test<br />777</font>
				</p>
				<p>
						<font color="#000080">C:\&gt;</font>
				</p>
		</div>
<img src ="http://www.blogjava.net/os586/aggbug/60473.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/os586/" target="_blank">水煮三国</a> 2006-07-28 09:36 <a href="http://www.blogjava.net/os586/archive/2006/07/28/60473.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>深入理解abstract class和interface</title><link>http://www.blogjava.net/os586/archive/2006/07/28/60464.html</link><dc:creator>水煮三国</dc:creator><author>水煮三国</author><pubDate>Fri, 28 Jul 2006 01:11:00 GMT</pubDate><guid>http://www.blogjava.net/os586/archive/2006/07/28/60464.html</guid><wfw:comment>http://www.blogjava.net/os586/comments/60464.html</wfw:comment><comments>http://www.blogjava.net/os586/archive/2006/07/28/60464.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/os586/comments/commentRss/60464.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/os586/services/trackbacks/60464.html</trackback:ping><description><![CDATA[
		<font style="font-size:12px">abstract class和interface是Java语言中对于抽象类定义进行支持的两种机制，正是由于这两种机制的存在，才赋予了Java强大的面向对象能力。abstract class和interface之间在对于抽象类定义的支持方面具有很大的相似性，甚至可以相互替换，因此很多开发者在进行抽象类定义时对于abstract class和interface的选择显得比较随意。其实，两者之间还是有很大的区别的，对于它们的选择甚至反映出对于问题领域本质的理解、对于设计意图的理解是否正确、合理。本文将对它们之间的区别进行一番剖析，试图给开发者提供一个在二者之间进行选择的依据。 <br /><br />理解抽象类 <br /><br />abstract class和interface在Java语言中都是用来进行抽象类（本文中的抽象类并非从abstract class翻译而来，它表示的是一个抽象体，而abstract class为Java语言中用于定义抽象类的一种方法，请读者注意区分）定义的，那么什么是抽象类，使用抽象类能为我们带来什么好处呢？ <br /><br />在面向对象的概念中，我们知道所有的对象都是通过类来描绘的，但是反过来却不是这样。并不是所有的类都是用来描绘对象的，如果一个类中没有包含足够的信息来描绘一个具体的对象，这样的类就是抽象类。抽象类往往用来表征我们在对问题领域进行分析、设计中得出的抽象概念，是对一系列看上去不同，但是本质上相同的具体概念的抽象。比如：如果我们进行一个图形编辑软件的开发，就会发现问题领域存在着圆、三角形这样一些具体概念，它们是不同的，但是它们又都属于形状这样一个概念，形状这个概念在问题领域是不存在的，它就是一个抽象概念。正是因为抽象的概念在问题领域没有对应的具体概念，所以用以表征抽象概念的抽象类是不能够实例化的。 <br /><br />在面向对象领域，抽象类主要用来进行类型隐藏。我们可以构造出一个固定的一组行为的抽象描述，但是这组行为却能够有任意个可能的具体实现方式。这个抽象描述就是抽象类，而这一组任意个可能的具体实现则表现为所有可能的派生类。模块可以操作一个抽象体。由于模块依赖于一个固定的抽象体，因此它可以是不允许修改的；同时，通过从这个抽象体派生，也可扩展此模块的行为功能。熟悉OCP的读者一定知道，为了能够实现面向对象设计的一个最核心的原则OCP(Open-Closed Principle)，抽象类是其中的关键所在。 <br /><br /><br />从语法定义层面看abstract class和interface <br /><br />在语法层面，Java语言对于abstract class和interface给出了不同的定义方式，下面以定义一个名为Demo的抽象类为例来说明这种不同。 <br /><br />使用abstract class的方式定义Demo抽象类的方式如下： <br /><br />abstract class Demo ｛ <br />abstract void method1(); <br />abstract void method2(); <br />… <br />｝ <br /><br />使用interface的方式定义Demo抽象类的方式如下： <br /><br />interface Demo { <br />void method1(); <br />void method2(); <br />… <br />} <br /><br />在abstract class方式中，Demo可以有自己的数据成员，也可以有非abstarct的成员方法，而在interface方式的实现中，Demo只能够有静态的不能被修改的数据成员（也就是必须是static final的，不过在interface中一般不定义数据成员），所有的成员方法都是abstract的。从某种意义上说，interface是一种特殊形式的abstract class。 <br /><br />从编程的角度来看，abstract class和interface都可以用来实现"design by contract"的思想。但是在具体的使用上面还是有一些区别的。 <br /><br />首先，abstract class在Java语言中表示的是一种继承关系，一个类只能使用一次继承关系。但是，一个类却可以实现多个interface。也许，这是Java语言的设计者在考虑Java对于多重继承的支持方面的一种折中考虑吧。 <br /><br />其次，在abstract class的定义中，我们可以赋予方法的默认行为。但是在interface的定义中，方法却不能拥有默认行为，为了绕过这个限制，必须使用委托，但是这会 增加一些复杂性，有时会造成很大的麻烦。 <br /><br />在抽象类中不能定义默认行为还存在另一个比较严重的问题，那就是可能会造成维护上的麻烦。因为如果后来想修改类的界面（一般通过abstract class或者interface来表示）以适应新的情况（比如，添加新的方法或者给已用的方法中添加新的参数）时，就会非常的麻烦，可能要花费很多的时间（对于派生类很多的情况，尤为如此）。但是如果界面是通过abstract class来实现的，那么可能就只需要修改定义在abstract class中的默认行为就可以了。 <br /><br />同样，如果不能在抽象类中定义默认行为，就会导致同样的方法实现出现在该抽象类的每一个派生类中，违反了"one rule，one place"原则，造成代码重复，同样不利于以后的维护。因此，在abstract class和interface间进行选择时要非常的小心。 <br /><br /><br />从设计理念层面看abstract class和interface <br /><br />上面主要从语法定义和编程的角度论述了abstract class和interface的区别，这些层面的区别是比较低层次的、非本质的。本小节将从另一个层面：abstract class和interface所反映出的设计理念，来分析一下二者的区别。作者认为，从这个层面进行分析才能理解二者概念的本质所在。 <br /><br />前面已经提到过，abstarct class在Java语言中体现了一种继承关系，要想使得继承关系合理，父类和派生类之间必须存在"is a"关系，即父类和派生类在概念本质上应该是相同的（参考文献〔3〕中有关于"is a"关系的大篇幅深入的论述，有兴趣的读者可以参考）。对于interface 来说则不然，并不要求interface的实现者和interface定义在概念本质上是一致的，仅仅是实现了interface定义的契约而已。为了使论述便于理解，下面将通过一个简单的实例进行说明。 <br /><br />考虑这样一个例子，假设在我们的问题领域中有一个关于Door的抽象概念，该Door具有执行两个动作open和close，此时我们可以通过abstract class或者interface来定义一个表示该抽象概念的类型，定义方式分别如下所示： <br /><br />使用abstract class方式定义Door： <br /><br />abstract class Door { <br />abstract void open(); <br />abstract void close()； <br />} <br /><br /><br />使用interface方式定义Door： <br /><br /><br />interface Door { <br />void open(); <br />void close(); <br />} <br /><br /><br />其他具体的Door类型可以extends使用abstract class方式定义的Door或者implements使用interface方式定义的Door。看起来好像使用abstract class和interface没有大的区别。 <br /><br />如果现在要求Door还要具有报警的功能。我们该如何设计针对该例子的类结构呢（在本例中，主要是为了展示abstract class和interface反映在设计理念上的区别，其他方面无关的问题都做了简化或者忽略）？下面将罗列出可能的解决方案，并从设计理念层面对这些不同的方案进行分析。 <br /><br />解决方案一： <br /><br />简单的在Door的定义中增加一个alarm方法，如下： <br /><br />abstract class Door { <br />abstract void open(); <br />abstract void close()； <br />abstract void alarm(); <br />} <br /><br /><br />或者 <br /><br />interface Door { <br />void open(); <br />void close(); <br />void alarm(); <br />} <br /><br /><br />那么具有报警功能的AlarmDoor的定义方式如下： <br /><br />class AlarmDoor extends Door { <br />void open() { … } <br />void close() { … } <br />void alarm() { … } <br />} <br /><br /><br />或者 <br /><br />class AlarmDoor implements Door ｛ <br />void open() { … } <br />void close() { … } <br />void alarm() { … } <br />｝ <br /><br />这种方法违反了面向对象设计中的一个核心原则ISP（Interface Segregation Priciple），在Door的定义中把Door概念本身固有的行为方法和另外一个概念"报警器"的行为方法混在了一起。这样引起的一个问题是那些仅仅依赖于Door这个概念的模块会因为"报警器"这个概念的改变（比如：修改alarm方法的参数）而改变，反之依然。 <br /><br />解决方案二： <br /><br />既然open、close和alarm属于两个不同的概念，根据ISP原则应该把它们分别定义在代表这两个概念的抽象类中。定义方式有：这两个概念都使用abstract class方式定义；两个概念都使用interface方式定义；一个概念使用abstract class方式定义，另一个概念使用interface方式定义。 <br /><br />显然，由于Java语言不支持多重继承，所以两个概念都使用abstract class方式定义是不可行的。后面两种方式都是可行的，但是对于它们的选择却反映出对于问题领域中的概念本质的理解、对于设计意图的反映是否正确、合理。我们一一来分析、说明。 <br /><br />如果两个概念都使用interface方式来定义，那么就反映出两个问题：1、我们可能没有理解清楚问题领域，AlarmDoor在概念本质上到底是Door还是报警器？2、如果我们对于问题领域的理解没有问题，比如：我们通过对于问题领域的分析发现AlarmDoor在概念本质上和Door是一致的，那么我们在实现时就没有能够正确的揭示我们的设计意图，因为在这两个概念的定义上（均使用interface方式定义）反映不出上述含义。 <br /><br />如果我们对于问题领域的理解是：AlarmDoor在概念本质上是Door，同时它有具有报警的功能。我们该如何来设计、实现来明确的反映出我们的意思呢？前面已经说过，abstract class在Java语言中表示一种继承关系，而继承关系在本质上是"is a"关系。所以对于Door这个概念，我们应该使用abstarct class方式来定义。另外，AlarmDoor又具有报警功能，说明它又能够完成报警概念中定义的行为，所以报警概念可以通过interface方式定义。如下所示： <br /><br />abstract class Door { <br />abstract void open(); <br />abstract void close()； <br />} <br />interface Alarm { <br />void alarm(); <br />} <br />class AlarmDoor extends Door implements Alarm { <br />void open() { … } <br />void close() { … } <br />void alarm() { … } <br />} <br /><br /><br />这种实现方式基本上能够明确的反映出我们对于问题领域的理解，正确的揭示我们的设计意图。其实abstract class表示的是"is a"关系，interface表示的是"like a"关系，大家在选择时可以作为一个依据，当然这是建立在对问题领域的理解上的，比如：如果我们认为AlarmDoor在概念本质上是报警器，同时又具有Door的功能，那么上述的定义方式就要反过来了。 <br /><br /><br /><br />结论 <br /><br />abstract class和interface是Java语言中的两种定义抽象类的方式，它们之间有很大的相似性。但是对于它们的选择却又往往反映出对于问题领域中的概念本质的理解、对于设计意图的反映是否正确、合理，因为它们表现了概念间的不同的关系（虽然都能够实现需求的功能）。这其实也是语言的一种的惯用法。</font>
<img src ="http://www.blogjava.net/os586/aggbug/60464.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/os586/" target="_blank">水煮三国</a> 2006-07-28 09:11 <a href="http://www.blogjava.net/os586/archive/2006/07/28/60464.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>避免NullPointerException异常的几种常用方法</title><link>http://www.blogjava.net/os586/archive/2006/03/03/33370.html</link><dc:creator>水煮三国</dc:creator><author>水煮三国</author><pubDate>Fri, 03 Mar 2006 01:53:00 GMT</pubDate><guid>http://www.blogjava.net/os586/archive/2006/03/03/33370.html</guid><wfw:comment>http://www.blogjava.net/os586/comments/33370.html</wfw:comment><comments>http://www.blogjava.net/os586/archive/2006/03/03/33370.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/os586/comments/commentRss/33370.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/os586/services/trackbacks/33370.html</trackback:ping><description><![CDATA[在写JAVA程序的时候，特别是jsp/servlet之类的东西，经常会有这样一种情况：当然你辛辛苦苦地打下了千百行字母的时候，写完最后一个大括号；当你运行这个程序进行调试时，忽然出现NullPointerException的字样，你是不是很懊丧呢。在以前我肯定会随手拿起桌上的杯子砸了。<BR>经过了一年多的打字母经历，我渐渐的总结出了一些经验，关于NullPointerException这个恶棍。<BR>NullPointerException这个异常出现在处理对象时对象不存在但又没有捕捉到进行处理的时候，但是在JAVA里面它又是被大多断片的类所抛出，所以它经常会不经意的出现在你的面前。在api里的原文说明是这样的：Thrown when an application attempts to use null in a case where an object is required. These include:<BR><BR>* Calling the instance method of a null object.<BR>* Accessing or modifying the field of a null object.<BR>* Taking the length of null as if it were an array.<BR>* Accessing or modifying the slots of null as if it were an array.<BR>* Throwing null as if it were a Throwable value. <BR><BR>Applications should throw instances of this class to indicate other illegal uses of the null object. <BR>据我自己的统计，在我的代码中，出现频率最多的类是String.class，因此我们就以String为例来看一下怎么避免在使用这个类的时候遇到NullPointerException。<BR>从JAVA的源代码来看，String这个类一共在两个地方就抛出了NullPointerException这个异常，一个是String的一个构造方法，一个是toLowerCase这个方法，所以在用到这两个方法的时候最好捕捉一下异常。<BR>还有经常遇到的是equals这个方法，equals出现NullPointerException异常是因为对象不存在造成的。如果是变量和常量的比较，比如str.equals("this is a string."),如果str == null。那么就会出现NullPointerException，怎么解决呢，就是把常量和变量的位置互换，"this is a string.".equals(str),这样就不会再见到NullPointerException了。<BR>在jsp中经常会有一些form来提交表单给服务器，但是有时候表单项并没有填，那么在jsp程序对传上来的数据进行处理时，就会有异常出现。这时就要在使用这些数据前进行一次判断，如：request.getParameter("str")，如果没有任何处理就直接使用的话就有可能出错，但是如果这样<BR><BR>String tmp = "";<BR>if(request.getParameter("str") != null)<BR>tmp = request.getParameter("str");<BR><BR>然后再对tmp进行操作就没有问题了。当然，几乎所有的NullPointerException问题差不多都可以用这个方法解决。<BR>还有在使用JDBC的时候，ResultSet这个对象使用的时候也会经常有NullPointerException异常，一般来说ResultSet出现这个问题主要是sql不对的原因。<img src ="http://www.blogjava.net/os586/aggbug/33370.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/os586/" target="_blank">水煮三国</a> 2006-03-03 09:53 <a href="http://www.blogjava.net/os586/archive/2006/03/03/33370.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>全面理解Java中的String数据类型</title><link>http://www.blogjava.net/os586/archive/2006/03/03/33359.html</link><dc:creator>水煮三国</dc:creator><author>水煮三国</author><pubDate>Fri, 03 Mar 2006 01:33:00 GMT</pubDate><guid>http://www.blogjava.net/os586/archive/2006/03/03/33359.html</guid><wfw:comment>http://www.blogjava.net/os586/comments/33359.html</wfw:comment><comments>http://www.blogjava.net/os586/archive/2006/03/03/33359.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/os586/comments/commentRss/33359.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/os586/services/trackbacks/33359.html</trackback:ping><description><![CDATA[　　1. 首先String不属于8种基本数据类型，String是一个对象。 <BR><BR>　　因为对象的默认值是null，所以String的默认值也是null；但它又是一种特殊的对象，有其它对象没有的一些特性。 <BR><BR>　　2. new String()和new String(“”)都是申明一个新的空字符串，是空串不是null； <BR><BR>　　3. String str=”kvill”； <BR>String str=new String (“kvill”);的区别： <BR><BR>　　在这里，我们不谈堆，也不谈栈，只先简单引入常量池这个简单的概念。 <BR><BR>　　常量池(constant pool)指的是在编译期被确定，并被保存在已编译的.class文件中的一些数据。它包括了关于类、方法、接口等中的常量，也包括字符串常量。 <BR><BR>　　看例1： <BR><BR>
<TABLE borderColor=#cccccc width="90%" align=center bgColor=#e3e3e3 border=1>
<TBODY>
<TR>
<TD>String s0=”kvill”; <BR>String s1=”kvill”; <BR>String s2=”kv” + “ill”; <BR>System.out.println( s0==s1 ); <BR>System.out.println( s0==s2 ); </TD></TR></TBODY></TABLE><BR>　　结果为： <BR><BR>
<TABLE borderColor=#cccccc width="90%" align=center bgColor=#e3e3e3 border=1>
<TBODY>
<TR>
<TD>true <BR>true </TD></TR></TBODY></TABLE><BR>　　首先，我们要知道Java会确保一个字符串常量只有一个拷贝。 <BR><BR>　　因为例子中的s0和s1中的”kvill”都是字符串常量，它们在编译期就被确定了，所以s0==s1为true；而”kv”和”ill”也都是字符串常量，当一个字符串由多个字符串常量连接而成时，它自己肯定也是字符串常量，所以s2也同样在编译期就被解析为一个字符串常量，所以s2也是常量池中”kvill”的一个引用。 <BR><BR>　　所以我们得出s0==s1==s2; <BR><BR>　　用new String() 创建的字符串不是常量，不能在编译期就确定，所以new String() 创建的字符串不放入常量池中，它们有自己的地址空间。 <BR><BR>　　看例2： <BR><BR>
<TABLE borderColor=#cccccc width="90%" align=center bgColor=#e3e3e3 border=1>
<TBODY>
<TR>
<TD>String s0=”kvill”; <BR>String s1=new String(”kvill”); <BR>String s2=”kv” + new String(“ill”); <BR>System.out.println( s0==s1 ); <BR>System.out.println( s0==s2 ); <BR>System.out.println( s1==s2 ); </TD></TR></TBODY></TABLE><BR>　　结果为： <BR><BR>
<TABLE borderColor=#cccccc width="90%" align=center bgColor=#e3e3e3 border=1>
<TBODY>
<TR>
<TD>false <BR>false <BR>false </TD></TR></TBODY></TABLE><BR>　　例2中s0还是常量池中”kvill”的应用，s1因为无法在编译期确定，所以是运行时创建的新对象”kvill”的引用，s2因为有后半部分new String(“ill”)所以也无法在编译期确定，所以也是一个新创建对象”kvill”的应用;明白了这些也就知道为何得出此结果了。 <BR><BR>　　4. String.intern()： <BR><BR>　　再补充介绍一点：存在于.class文件中的常量池，在运行期被JVM装载，并且可以扩充。String的intern()方法就是扩充常量池的一个方法；当一个String实例str调用intern()方法时，Java查找常量池中是否有相同Unicode的字符串常量，如果有，则返回其的引用，如果没有，则在常量池中增加一个Unicode等于str的字符串并返回它的引用；看例3就清楚了 <BR><BR>　　例3： <BR><BR>
<TABLE borderColor=#cccccc width="90%" align=center bgColor=#e3e3e3 border=1>
<TBODY>
<TR>
<TD>String s0= “kvill”; <BR>String s1=new String(”kvill”); <BR>String s2=new String(“kvill”); <BR>System.out.println( s0==s1 ); <BR>System.out.println( “**********” ); <BR>s1.intern(); <BR>s2=s2.intern(); //把常量池中“kvill”的引用赋给s2 <BR>System.out.println( s0==s1); <BR>System.out.println( s0==s1.intern() ); <BR>System.out.println( s0==s2 ); </TD></TR></TBODY></TABLE><BR>　　结果为： <BR><BR>
<TABLE borderColor=#cccccc width="90%" align=center bgColor=#e3e3e3 border=1>
<TBODY>
<TR>
<TD>false <BR>********** <BR>false //虽然执行了s1.intern(),但它的返回值没有赋给s1 <BR>true //说明s1.intern()返回的是常量池中”kvill”的引用 <BR>true </TD></TR></TBODY></TABLE><BR>　　最后我再破除一个错误的理解： <BR><BR>　　有人说，“使用String.intern()方法则可以将一个String类的保存到一个全局String表中，如果具有相同值的Unicode字符串已经在这个表中，那么该方法返回表中已有字符串的地址，如果在表中没有相同值的字符串，则将自己的地址注册到表中“如果我把他说的这个全局的String表理解为常量池的话，他的最后一句话，“如果在表中没有相同值的字符串，则将自己的地址注册到表中”是错的： <BR><BR>　　看例4： <BR><BR>
<TABLE borderColor=#cccccc width="90%" align=center bgColor=#e3e3e3 border=1>
<TBODY>
<TR>
<TD>String s1=new String("kvill"); <BR>String s2=s1.intern(); <BR>System.out.println( s1==s1.intern() ); <BR>System.out.println( s1+" "+s2 ); <BR>System.out.println( s2==s1.intern() ); </TD></TR></TBODY></TABLE><BR>　　结果： <BR><BR>
<TABLE borderColor=#cccccc width="90%" align=center bgColor=#e3e3e3 border=1>
<TBODY>
<TR>
<TD>false <BR>kvill kvill <BR>true </TD></TR></TBODY></TABLE><BR>　　在这个类中我们没有声名一个”kvill”常量，所以常量池中一开始是没有”kvill”的，当我们调用s1.intern()后就在常量池中新添加了一个”kvill”常量，原来的不在常量池中的”kvill”仍然存在，也就不是“将自己的地址注册到常量池中”了。 <BR><BR>　　s1==s1.intern()为false说明原来的“kvill”仍然存在； <BR><BR>　　s2现在为常量池中“kvill”的地址，所以有s2==s1.intern()为true。 <BR><BR>　　5. 关于equals()和==: <BR><BR>　　这个对于String简单来说就是比较两字符串的Unicode序列是否相当，如果相等返回true;而==是比较两字符串的地址是否相同，也就是是否是同一个字符串的引用。 <BR><BR>　　6. 关于String是不可变的<BR><BR>　　这一说又要说很多，大家只要知道String的实例一旦生成就不会再改变了，比如说：String str=”kv”+”ill”+” “+”ans”; <BR>就是有4个字符串常量，首先”kv”和”ill”生成了”kvill”存在内存中，然后”kvill”又和” “ 生成 ”kvill “存在内存中，最后又和生成了”kvill ans”;并把这个字符串的地址赋给了str,就是因为String的“不可变”产生了很多临时变量，这也就是为什么建议用StringBuffer的原因了，因为StringBuffer是可改变的 <img src ="http://www.blogjava.net/os586/aggbug/33359.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/os586/" target="_blank">水煮三国</a> 2006-03-03 09:33 <a href="http://www.blogjava.net/os586/archive/2006/03/03/33359.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>经典的Object转为String的几种形式[摘]</title><link>http://www.blogjava.net/os586/archive/2006/03/03/33356.html</link><dc:creator>水煮三国</dc:creator><author>水煮三国</author><pubDate>Fri, 03 Mar 2006 01:18:00 GMT</pubDate><guid>http://www.blogjava.net/os586/archive/2006/03/03/33356.html</guid><wfw:comment>http://www.blogjava.net/os586/comments/33356.html</wfw:comment><comments>http://www.blogjava.net/os586/archive/2006/03/03/33356.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/os586/comments/commentRss/33356.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/os586/services/trackbacks/33356.html</trackback:ping><description><![CDATA[在java项目的实际开发和应用中，常常需要用到将对象转为String这一基本功能。本文将对常用的转换方法进行一个总结。常用的方法有Object#toString()，（String）要转换的对象，String.valueOf(Object)等。下面对这些方法一一进行分析。<BR><BR>方法1：采用 Object#toString()方法<BR>请看下面的例子：<BR><BR>　　Object object = getObject();<BR><BR>System.out.println(object.toString());<BR><BR>在这种使用方法中，因为java.lang.Object类里已有public方法.toString()，所以对任何严格意义上的java对象都可以调用此方法。但在使用时要注意，必须保证object不是null值，否则将抛出NullPointerException异常。采用这种方法时，通常派生类会覆盖Object里的toString（）方法。<BR><BR>方法2：采用类型转换（String）object方法<BR>这是标准的类型转换，将object转成String类型的值。使用这种方法时，需要注意的是类型必须能转成String类型。因此最好用instanceof做个类型检查，以判断是否可以转换。否则容易抛出CalssCastException异常。此外，需特别小心的是因定义为Object 类型的对象在转成String时语法检查并不会报错，这将可能导致潜在的错误存在。这时要格外小心。如：<BR><BR>Object obj = new Integer(100);<BR><BR>String　strVal = (String)obj;<BR><BR>在运行时将会出错，因为将Integer类型强制转换为String类型，无法通过。但是，<BR><BR>Integer obj = new Integer(100);<BR><BR>String　strVal = (String)obj;<BR><BR>如是格式代码，将会报语法错误。<BR><BR>此外，因null值可以强制转换为任何java类类型，(String)null也是合法的。<BR><BR>方法3：采用String.valueOf(Object)<BR>String.valueOf(Object)的基础是Object#toString()。但它与Object#toString()又有所不同。在前面方法1的分析中提到，使用后者时需保证不为null。但采用第三种方法时，将不用担心object是否为null值这一问题。为了便于说明问题，我们来分析一下相关的源代码。Jdk里String# valueOf(Object)源码如下：<BR><BR>　　/**<BR><BR>　　 * Returns the string representation of the Object argument.<BR><BR>　　 *<BR><BR>　　 * @param　 obj　 an Object.<BR><BR>　　 * @return　if the argument is null, then a string equal to<BR><BR>　　 *　　　　　"null"; otherwise, the value of<BR><BR>　　 *　　　　　obj.toString() is returned.<BR><BR>　　 * @see　　 java.lang.Object#toString()<BR><BR>　　 */<BR><BR>　　public static String valueOf(Object obj) {<BR><BR>　　　 return (obj == null) ? "null" : obj.toString();<BR><BR>}<BR><BR>从上面的源码可以很清晰的看出null值不用担心的理由。但是，这也恰恰给了我们隐患。我们应当注意到，当object为null时，String.valueOf（object）的值是字符串”null”，而不是null！！！在使用过程中切记要注意。试想一下，如果我们用 if(String.valueOf（object）==null){System.out.println(“传入的值是null！”);}这样的语句将可能会发生什么问题。再想一下，向控制台输出时，在视觉上如下语句在执行的结果上有什么不同：<BR><BR>System.out.println(String.valueOf(null));<BR><BR>System.out.println(null);<BR><BR>我们看到的输出将是一模一样的东西：null，但它们意义相同吗？<img src ="http://www.blogjava.net/os586/aggbug/33356.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/os586/" target="_blank">水煮三国</a> 2006-03-03 09:18 <a href="http://www.blogjava.net/os586/archive/2006/03/03/33356.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>