﻿<?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-Tom-随笔-随笔分类-Java</title><link>http://www.blogjava.net/43880800/category/17388.html</link><description /><language>zh-cn</language><lastBuildDate>Mon, 03 Dec 2007 21:49:55 GMT</lastBuildDate><pubDate>Mon, 03 Dec 2007 21:49:55 GMT</pubDate><ttl>60</ttl><item><title>Java反射学习</title><link>http://www.blogjava.net/43880800/archive/2007/12/04/165045.html</link><dc:creator>Tom</dc:creator><author>Tom</author><pubDate>Mon, 03 Dec 2007 16:55:00 GMT</pubDate><guid>http://www.blogjava.net/43880800/archive/2007/12/04/165045.html</guid><wfw:comment>http://www.blogjava.net/43880800/comments/165045.html</wfw:comment><comments>http://www.blogjava.net/43880800/archive/2007/12/04/165045.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/43880800/comments/commentRss/165045.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/43880800/services/trackbacks/165045.html</trackback:ping><description><![CDATA[<div class="postTitle"><a class="postTitle2" id="viewpost1_TitleUrl" href="http://www.blogjava.net/lcwlv929/articles/125646.html"><span style="color: #ff6600"><span style="color: #ffcc00"><span style="color: #008000">Java反射学习</span></span></span></a><span style="color: #ff6600"><span style="color: #ffcc00"><span style="color: #008000"> </span></span></span></div>
<span style="color: #ff6600"><span style="color: #ffcc00"><span style="color: #008000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;所谓反射，可以理解为在运行时期获取对象类型信息的操作。传统的编程方法要求程序员在编译阶段决定使用的类型，但是在反射的帮助下，编程人员可以动态获取这些信息，从而编写更加具有可移植性的代码。严格地说，反射并非编程语言的特性，因为在任何一种语言都可以实现反射机制，但是如果编程语言本身支持反射，那么反射的实现就会方便很多。 </span></span></span>
<p><span style="color: #ff6600"><span style="color: #ffcc00"><span style="color: #008000">1，获得类型类<br />
&nbsp;&nbsp;&nbsp; 我们知道在Java中一切都是对象，我们一般所使用的对象都直接或间接继承自Object类。Object类中包含一个方法名叫getClass，利用这个方法就可以获得一个实例的类型类。类型类指的是代表一个类型的类，因为一切皆是对象，类型也不例外，在Java使用类型类来表示一个类型。所有的类型类都是Class类的实例。例如，有如下一段代码：<br />
A a = new A();<br />
if(a.getClass()==A.class)<br />
&nbsp;&nbsp;&nbsp; System.out.println("equal");<br />
else System.out.println("unequal");</span></span></span></p>
<p><span style="color: #ff6600"><span style="color: #ffcc00"><span style="color: #008000">&nbsp;&nbsp;&nbsp; 可以看到，对象a是A的一个实例，A某一个类，在if语句中使用a.getClass()返回的结果正是A的类型类，在Java中表示一个特定类型的类型类可以用&#8220;类型.class&#8221;的方式获得，因为a.getClass()获得是A的类型类，也就是A.class，因此上面的代码执行的结果就是打印出&#8220;equal&#8221;。特别注意的是，类型类是一一对应的，父类的类型类和子类的类型类是不同的，因此，假设A是B的子类，那么如下的代码将得到&#8220;unequal&#8221;的输出：<br />
A a = new A();<br />
if(a.getClass()==B.class)<br />
&nbsp;&nbsp;&nbsp; System.out.println("equal");<br />
else System.out.println("unequal");</span></span></span></p>
<p><span style="color: #ff6600"><span style="color: #ffcc00"><span style="color: #008000">&nbsp;&nbsp;&nbsp; 因此，如果你知道一个实例，那么你可以通过实例的&#8220;getClass()&#8221;方法获得该对象的类型类，如果你知道一个类型，那么你可以使用&#8220;.class&#8221;的方法获得该类型的类型类。<br />
&nbsp;&nbsp;&nbsp; <br />
2，获得类型的信息<br />
&nbsp;&nbsp;&nbsp; 在获得类型类之后，你就可以调用其中的一些方法获得类型的信息了，主要的方法有：<br />
getName():String：获得该类型的全称名称。<br />
getSuperClass():Class：获得该类型的直接父类，如果该类型没有直接父类，那么返回null。<br />
getInterfaces():Class[]：获得该类型实现的所有接口。<br />
isArray():boolean：判断该类型是否是数组。<br />
isEnum():boolean：判断该类型是否是枚举类型。<br />
isInterface():boolean：判断该类型是否是接口。<br />
isPrimitive():boolean：判断该类型是否是基本类型，即是否是int，boolean，double等等。<br />
isAssignableFrom(Class cls):boolean：判断这个类型是否是类型cls的父（祖先）类或父（祖先）接口。<br />
getComponentType():Class：如果该类型是一个数组，那么返回该数组的组件类型。<br />
此外还可以进行类型转换这类的操作，主要方法有：<br />
asSubclass(Class clazz):Class：将这个类型转换至clazz，如果可以转换，那么总是返回clazz这个引用，否则抛出异常。<br />
cast(Object obj):Object：将obj强制转换为这个类型类代表的类型，不能转换的话将抛出异常。</span></span></span></p>
<p><span style="color: #ff6600"><span style="color: #ffcc00"><span style="color: #008000">&nbsp;&nbsp;&nbsp; 除了这些以外，利用类型类还可以反射该类型中的所有属性和方法。在Java中所有的属性信息都用Field表示，所有的方法信息都用Method表示，这辆各类都是java.lang.reflect包中的类。在Class中提供了4个相关的方法获得类型的属性：<br />
getField(String name):Field<br />
getFields():Field[]<br />
getDeclaredField(String name):Field<br />
getDeclaredFields():Field[]<br />
其中getField用于返回一个指定名称的属性，但是这个属性必须是公有的，这个属性可以在父类中定义。如果是私有属性或者是保护属性，那么都会抛出异常提示找不到这个属性。getFields则是返回类型中的所有公有属性，所有的私有属性和保护属性都找不到。getDeclaredField获得在这个类型的声明中定义的指定名称的属性，这个属性必须是在这个类型的声明中定义，但可以使私有和保护的。getDeclaredFields获得在这个类型的声明中定义的所有属性，包括私有和保护的属性都会被返回，但是所有父类的属性都不会被返回。举个例子，先考虑下面两个类的声明：<br />
class A extends B {<br />
&nbsp;&nbsp;&nbsp; public int a1;<br />
&nbsp;&nbsp;&nbsp; private int a2;<br />
}<br />
class B {<br />
&nbsp;public int b1;<br />
&nbsp;private int b2;<br />
}<br />
如果利用A的类型类调用getFields，那么会返回a1和b1两个属性，如果调用getField("a2")则会报错；如果调用getDeclaredFields则会返回a1和a2，如果调用getDeclaredField("b1")则会报错。</span></span></span></p>
<p><span style="color: #ff6600"><span style="color: #ffcc00"><span style="color: #008000">&nbsp;&nbsp;&nbsp; 对于方法也有类似的函数即：<br />
getMethods():Method[]<br />
getMethod(String name, Class ... parameterTypes):Method<br />
getDeclaredMethods():Method[]<br />
getDeclaredMethod(Strubg name, Class ...parameterTypes):Method<br />
不定长参数...是JDK5.0以后新加入的语法。这几个方法的用法和上面的类似，只是在获得特定方法时，除了要告知方法的名字，还需要告知方法的参数，如果没有参数，那么可以传递null，或者空数组，但是最好的方法就是什么都不写，编译器会自行解决不定长参数问题。<br />
&nbsp;&nbsp;&nbsp; 如果要获得所有的属性（方法），包括公有和私有的，那么就必须利用getDeclareFields（getDeclareMethods）方法，然后再利用getSuperClass的方法获得父类，然后递归下去。<br />
&nbsp;&nbsp;&nbsp; <br />
3，属性和方法<br />
&nbsp;&nbsp;&nbsp; 所有的属性都使用Field表示，所有的方法都使用Method表示。利用Field和Method可以获得属性和方法的信息，甚至执行是获取、修改属性值和调用方法。<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; 对于属性，主要有以下方法可以使用：<br />
getType():Class：获得该属性的类型。<br />
getName():String：获得属性名称。<br />
isAccessible():boolean：判断该属性是否是可以访问的，通常私有和保护的类型都是不可以访问的。<br />
get(Object obj):Object：获得实例obj的属性值，如果该实例的类型中不包含这个属性，那么就会报错。<br />
set(Object obj, Object value)：设置该实例的属性值<br />
setAccessible(boolean flag)：设置该属性是否可以访问，如果你调用get和set方法，那么有可能会引发访问权限的错误，这个时候你可以调用setAccessible方法使得该属性可以访问。例如下面的代码：<br />
A a = new A();<br />
Field f = A.class.getDeclaredField("a2");<br />
f.setAccessibe(true);<br />
System.out.println(f.get(a));<br />
f.set(a,12);<br />
System.out.println(f.get(a));<br />
如果移出中间的f.setAccessibe(true);那么代码会报错，反之输出0 12。<br />
&nbsp;&nbsp;&nbsp; 对于属性而言，如果该属性的类型是基本类型，那么还可以使用一些便捷的set和get操作，例如getInt，setInt什么的，你可以根据自己的需要调用相应的方法。<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; 对于方法，可以有以下的方法：<br />
getName():String：获得方法的名字。<br />
getReturnType():Class：获得方法的返回值类型。<br />
getParameterTypes():Class[]：获得方法的参数类型。<br />
isAccessible():boolean：判断该方法是否是可以访问的。<br />
setAccessible(boolean flag)：设置该方法是否可以访问。<br />
invoke(Object obj, Object... args):Object：调用实例obj的相应方法，其参数由args给定，如果没有参数那么可以什么都不写。<br />
getExceptionTypes():Class[]：获得该方法可能抛出的异常类类型。<br />
这几个方法的含义和用法都和Field的类似，这里不再赘述。</span></span></span></p>
<p><span style="color: #ff6600"><span style="color: #ffcc00"><span style="color: #008000">4，创建实例<br />
&nbsp;&nbsp;&nbsp; 利用Class对象可以创建一个类型的实例。如果一个类型拥有无参数的构造函数，那么可以简单地调用Class.newInstance()方法创建一个实例。如果该类型没有无参数的构造函数，或者你希望是用某个有参数的构造函数，那么可以首先使用getConstructors()、getConstructor(Class[] parameterTypes)和getDeclaredConstructors()、getDeclaredConstructor(Class[] parameterTypes)获得构造函数，这两个方法的返回值都使Constructor类型。特别注意的是，构造函数不能继承，因此你调用getConstructor也只能返回这个类型中定义的所有公有构造函数。<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; Constructor的使用方法和Method的类似，它也存在getParameterTypes()方法和getExceptionTypes()方法，不同的是，它使用newInstance(Object... args)来调用一个构造函数，注意newInstance不需要实例对象，因为这个时候你还没创建出来这个实例呢。</span></span></span></p>
<img src ="http://www.blogjava.net/43880800/aggbug/165045.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/43880800/" target="_blank">Tom</a> 2007-12-04 00:55 <a href="http://www.blogjava.net/43880800/archive/2007/12/04/165045.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> 栈与堆 de 区别</title><link>http://www.blogjava.net/43880800/archive/2007/08/30/141443.html</link><dc:creator>Tom</dc:creator><author>Tom</author><pubDate>Thu, 30 Aug 2007 09:11:00 GMT</pubDate><guid>http://www.blogjava.net/43880800/archive/2007/08/30/141443.html</guid><wfw:comment>http://www.blogjava.net/43880800/comments/141443.html</wfw:comment><comments>http://www.blogjava.net/43880800/archive/2007/08/30/141443.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/43880800/comments/commentRss/141443.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/43880800/services/trackbacks/141443.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 栈与堆都是Java用来在Ram中存放数据的地方。与C++不同，Java自动管理栈和堆，程序员不能直接地设置栈或堆。 <br>&nbsp; &nbsp; &nbsp;Java的堆是一个运行时数据区,类的对象从中分配空间。这些对象通过new、newarray、anewarray和multianewarray等指令建立，它们不需要程序代码来显式的释放。堆是由垃圾回收来负责的，堆的优势是可以动态地分配内存大小，生存期也不必事先告诉编译器，因为它是在运行时动态分配内存的，Java的垃圾收集器会自动收走这些不再使用的数据。但缺点是，由于要在运行时动态分配内存，存取速度较慢。 <br>&nbsp; &nbsp; &nbsp;栈的优势是，存取速度比堆要快，仅次于寄存器，栈数据可以共享。但缺点是，存在栈中的数据大小与生存期必须是确定的，缺乏灵活性。栈中主要存放一些基本类型的变量（,int, short, long, byte, float, double, boolean, char）和对象句柄。 <br>栈有一个很重要的特殊性，就是存在栈中的数据可以共享。假设我们同时定义： <br>int a = 3; <br>int b = 3； <br>&nbsp; &nbsp; &nbsp; 编译器先处理int a = 3；首先它会在栈中创建一个变量为a的引用，然后查找栈中是否有3这个值，如果没找到，就将3存放进来，然后将a指向3。接着处理int b = 3；在创建完b的引用变量后，因为在栈中已经有3这个值，便将b直接指向3。这样，就出现了a与b同时均指向3的情况。 <br>&nbsp; &nbsp; &nbsp; 这时，如果再令a=4；那么编译器会重新搜索栈中是否有4值，如果没有，则将4存放进来，并令a指向4；如果已经有了，则直接将a指向这个地址。因此a值的改变不会影响到b的值。 <br>&nbsp; &nbsp; &nbsp; 要注意这种数据的共享与两个对象的引用同时指向一个对象的这种共享是不同的，因为这种情况a的修改并不会影响到b, 它是由编译器完成的，它有利于节省空间。而一个对象引用变量修改了这个对象的内部状态，会影响到另一个对象引用变量。 <br>String是一个特殊的包装类数据。可以用： <br>String str = new String("abc"); <br>String str = "abc"; <br>&nbsp; &nbsp; &nbsp; 两种的形式来创建，第一种是用new()来新建对象的，它会在存放于堆中。每调用一次就会创建一个新的对象。而第二种是先在栈中创建一个对String类的对象引用变量str，然后查找栈中有没有存放"abc"，如果没有，则将"abc"存放进栈，并令str指向&#8221;abc&#8221;，如果已经有&#8221;abc&#8221; 则直接令str指向&#8220;abc&#8221;。 <br>比较类里面的数值是否相等时，用equals()方法；当测试两个包装类的引用是否指向同一个对象时，用==，下面用例子说明上面的理论。 <br>String str1 = "abc"; <br>String str2 = "abc"; <br>System.out.println(str1==str2); //true <br>可以看出str1和str2是指向同一个对象的。 <br>String str1 =new String ("abc"); <br>String str2 =new String ("abc"); <br>System.out.println(str1==str2); // false <br>用new的方式是生成不同的对象。每一次生成一个。 <br>&nbsp; &nbsp; &nbsp;因此用第二种方式创建多个&#8221;abc&#8221;字符串,在内存中其实只存在一个对象而已. 这种写法有利与节省内存空间. 同时它可以在一定程度上提高程序的运行速度，因为JVM会自动根据栈中数据的实际情况来决定是否有必要创建新对象。而对于String str = new String("abc")；的代码，则一概在堆中创建新对象，而不管其字符串值是否相等，是否有必要创建新对象，从而加重了程序的负担。 <br>&nbsp; &nbsp; &nbsp; 另一方面, 要注意: 我们在使用诸如String str = "abc"；的格式定义类时，总是想当然地认为，创建了String类的对象str。担心陷阱！对象可能并没有被创建！而可能只是指向一个先前已经创建的对象。只有通过new()方法才能保证每次都创建一个新的对象。 <br>由于String类的immutable性质，当String变量需要经常变换其值时，应该考虑使用StringBuffer类，以提高程序效率。 
<img src ="http://www.blogjava.net/43880800/aggbug/141443.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/43880800/" target="_blank">Tom</a> 2007-08-30 17:11 <a href="http://www.blogjava.net/43880800/archive/2007/08/30/141443.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>一个关于StringBuilder与StringBuffer性能的小试验 </title><link>http://www.blogjava.net/43880800/archive/2007/02/20/100272.html</link><dc:creator>Tom</dc:creator><author>Tom</author><pubDate>Tue, 20 Feb 2007 13:56:00 GMT</pubDate><guid>http://www.blogjava.net/43880800/archive/2007/02/20/100272.html</guid><wfw:comment>http://www.blogjava.net/43880800/comments/100272.html</wfw:comment><comments>http://www.blogjava.net/43880800/archive/2007/02/20/100272.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/43880800/comments/commentRss/100272.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/43880800/services/trackbacks/100272.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 一个关于StringBuilder与StringBuffer性能的小试验								StringBuilder				是从				Java 5				以后增加的一个字符串处理类。查看				API				文档，我们可以知道				StringBuilder				和				StringBuffer				提供同样的功能，只是				Strin...&nbsp;&nbsp;<a href='http://www.blogjava.net/43880800/archive/2007/02/20/100272.html'>阅读全文</a><img src ="http://www.blogjava.net/43880800/aggbug/100272.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/43880800/" target="_blank">Tom</a> 2007-02-20 21:56 <a href="http://www.blogjava.net/43880800/archive/2007/02/20/100272.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>利用静态内部类为您的代码添加辅助功能 </title><link>http://www.blogjava.net/43880800/archive/2007/01/29/96530.html</link><dc:creator>Tom</dc:creator><author>Tom</author><pubDate>Mon, 29 Jan 2007 08:21:00 GMT</pubDate><guid>http://www.blogjava.net/43880800/archive/2007/01/29/96530.html</guid><wfw:comment>http://www.blogjava.net/43880800/comments/96530.html</wfw:comment><comments>http://www.blogjava.net/43880800/archive/2007/01/29/96530.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/43880800/comments/commentRss/96530.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/43880800/services/trackbacks/96530.html</trackback:ping><description><![CDATA[
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-pagination: widow-orphan" align="left">
				<b>
						<span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'helvetica,helv,arial,sans-serif'; mso-hansi-font-family: 'helvetica,helv,arial,sans-serif'; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">利用静态内部类为您的代码添加辅助功能</span>
				</b>
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: helvetica,helv,arial,sans-serif; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">
						<br />
				</span>
				<span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'helvetica,helv,arial,sans-serif'; mso-hansi-font-family: 'helvetica,helv,arial,sans-serif'; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">作者</span>
				<span style="FONT-SIZE: 10pt; FONT-FAMILY: helvetica,helv,arial,sans-serif; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">
						<span lang="EN-US">javaworld.com"&gt;<span style="mso-bidi-font-size: 12.0pt">John D. Mitchell</span><p></p></span>
				</span>
		</p>
		<p>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-pagination: widow-orphan" align="left">
				<b>
						<span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'helvetica,helv,arial,sans-serif'; mso-hansi-font-family: 'helvetica,helv,arial,sans-serif'; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt; mso-bidi-font-size: 12.0pt">摘要</span>
				</b>
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: helvetica,helv,arial,sans-serif; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">
						<br />
				</span>
				<span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'helvetica,helv,arial,sans-serif'; mso-hansi-font-family: 'helvetica,helv,arial,sans-serif'; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">这个技巧提供了一个实例，它可以利用静态内部类为您的类添加独立的、可选的辅助功能，例如测试和示例代码等。（</span>
				<i>
						<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: helvetica,helv,arial,sans-serif; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt; mso-bidi-font-size: 12.0pt"> 500 </span>
				</i>
				<i>
						<span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'helvetica,helv,arial,sans-serif'; mso-hansi-font-family: 'helvetica,helv,arial,sans-serif'; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt; mso-bidi-font-size: 12.0pt">字</span>
				</i>
				<span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'helvetica,helv,arial,sans-serif'; mso-hansi-font-family: 'helvetica,helv,arial,sans-serif'; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">）</span>
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: helvetica,helv,arial,sans-serif; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">
						<p>
						</p>
				</span>
		</p>
		<p>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-pagination: widow-orphan" align="left">
				<span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'helvetica,helv,arial,sans-serif'; mso-hansi-font-family: 'helvetica,helv,arial,sans-serif'; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">学会了这个技巧，您便可以把</span>
				<i>
						<span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'helvetica,helv,arial,sans-serif'; mso-hansi-font-family: 'helvetica,helv,arial,sans-serif'; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt; mso-bidi-font-size: 12.0pt">静态内部类</span>
				</i>
				<span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'helvetica,helv,arial,sans-serif'; mso-hansi-font-family: 'helvetica,helv,arial,sans-serif'; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">的使用加入到您的</span>
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: helvetica,helv,arial,sans-serif; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt"> Java </span>
				<span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'helvetica,helv,arial,sans-serif'; mso-hansi-font-family: 'helvetica,helv,arial,sans-serif'; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">使用技巧集锦当中。静态内部类是在另一个类的定义中进行定义，并且标记为静态的类。我将向您展示一个实例，它利用静态内部类向另一个类中添加测试代码。</span>
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: helvetica,helv,arial,sans-serif; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">
						<p>
						</p>
				</span>
		</p>
		<p>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-pagination: widow-orphan" align="left">
				<span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'helvetica,helv,arial,sans-serif'; mso-hansi-font-family: 'helvetica,helv,arial,sans-serif'; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">静态内部类在概念和实现上都十分简单，基本上来说就是在您的主类中定义一个静态类：</span>
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: helvetica,helv,arial,sans-serif; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">
						<p>
						</p>
				</span>
		</p>
		<p>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-pagination: widow-orphan" align="left">
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: helvetica,helv,arial,sans-serif; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">public class TestDebug 
<p></p></span>
		</p>
		<p>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-pagination: widow-orphan" align="left">
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: helvetica,helv,arial,sans-serif; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">{ 
<p></p></span>
		</p>
		<p>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-pagination: widow-orphan" align="left">
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: helvetica,helv,arial,sans-serif; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">
						<span style="mso-tab-count: 1">         </span>private double num; 
<p></p></span>
		</p>
		<p>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-pagination: widow-orphan" align="left">
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: helvetica,helv,arial,sans-serif; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">
						<span style="mso-tab-count: 1">         </span>public TestDebug(double in) 
<p></p></span>
		</p>
		<p>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-pagination: widow-orphan" align="left">
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: helvetica,helv,arial,sans-serif; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">
						<span style="mso-tab-count: 1">         </span>{ 
<p></p></span>
		</p>
		<p>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-pagination: widow-orphan" align="left">
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: helvetica,helv,arial,sans-serif; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">
						<span style="mso-tab-count: 2">                   </span>num = in; 
<p></p></span>
		</p>
		<p>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-pagination: widow-orphan" align="left">
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: helvetica,helv,arial,sans-serif; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">
						<span style="mso-tab-count: 1">         </span>} 
<p></p></span>
		</p>
		<p>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-pagination: widow-orphan" align="left">
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: helvetica,helv,arial,sans-serif; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">
						<span style="mso-tab-count: 1">         </span>public void output() 
<p></p></span>
		</p>
		<p>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-pagination: widow-orphan" align="left">
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: helvetica,helv,arial,sans-serif; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">
						<span style="mso-tab-count: 1">         </span>{ 
<p></p></span>
		</p>
		<p>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-pagination: widow-orphan" align="left">
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: helvetica,helv,arial,sans-serif; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">
						<span style="mso-tab-count: 2">                   </span>System.out.println(num); 
<p></p></span>
		</p>
		<p>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-pagination: widow-orphan" align="left">
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: helvetica,helv,arial,sans-serif; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">
						<span style="mso-tab-count: 2">                   </span>
						<p>
						</p>
				</span>
		</p>
		<p>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-pagination: widow-orphan" align="left">
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: helvetica,helv,arial,sans-serif; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">
						<span style="mso-tab-count: 1">         </span>} 
<p></p></span>
		</p>
		<p>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-pagination: widow-orphan" align="left">
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: helvetica,helv,arial,sans-serif; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">
						<span style="mso-tab-count: 1">         </span>public static class Test 
<p></p></span>
		</p>
		<p>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-pagination: widow-orphan" align="left">
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: helvetica,helv,arial,sans-serif; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">
						<span style="mso-tab-count: 1">         </span>{ 
<p></p></span>
		</p>
		<p>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-pagination: widow-orphan" align="left">
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: helvetica,helv,arial,sans-serif; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">
						<span style="mso-tab-count: 2">                   </span>public static void main(String[] args) 
<p></p></span>
		</p>
		<p>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-pagination: widow-orphan" align="left">
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: helvetica,helv,arial,sans-serif; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">
						<span style="mso-tab-count: 2">                   </span>{ 
<p></p></span>
		</p>
		<p>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-pagination: widow-orphan" align="left">
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: helvetica,helv,arial,sans-serif; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">
						<span style="mso-tab-count: 3">                            </span>TestDebug td<span style="mso-spacerun: yes">  </span>= new TestDebug(3.9); 
<p></p></span>
		</p>
		<p>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-pagination: widow-orphan" align="left">
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: helvetica,helv,arial,sans-serif; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">
						<span style="mso-tab-count: 3">                            </span>td.output(); 
<p></p></span>
		</p>
		<p>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-pagination: widow-orphan" align="left">
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: helvetica,helv,arial,sans-serif; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">
						<p> </p>
				</span>
		</p>
		<p>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-pagination: widow-orphan" align="left">
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: helvetica,helv,arial,sans-serif; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">
						<span style="mso-tab-count: 2">                   </span>} 
<p></p></span>
		</p>
		<p>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-pagination: widow-orphan" align="left">
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: helvetica,helv,arial,sans-serif; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">
						<span style="mso-tab-count: 1">         </span>} 
<p></p></span>
		</p>
		<p>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-pagination: widow-orphan" align="left">
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: helvetica,helv,arial,sans-serif; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">} 
<p></p></span>
		</p>
		<p>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-pagination: widow-orphan" align="left">
				<span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'helvetica,helv,arial,sans-serif'; mso-hansi-font-family: 'helvetica,helv,arial,sans-serif'; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">说到向您主要的类中添加辅助代码，其中最重要的一点就是静态内部类被编译到一个单独的</span>
				<span style="FONT-SIZE: 10pt; FONT-FAMILY: helvetica,helv,arial,sans-serif; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">
						<i>
								<span lang="EN-US">.class</span>
						</i>
						<span lang="EN-US">
						</span>
				</span>
				<span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'helvetica,helv,arial,sans-serif'; mso-hansi-font-family: 'helvetica,helv,arial,sans-serif'; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">文件中，这个文件独立于它的外部类。例如，如果外部类叫做</span>
				<span style="FONT-SIZE: 10pt; FONT-FAMILY: helvetica,helv,arial,sans-serif; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">
				</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt; mso-bidi-font-size: 12.0pt">Foo</span>
				<span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'helvetica,helv,arial,sans-serif'; mso-hansi-font-family: 'helvetica,helv,arial,sans-serif'; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">，而它的一个内部类叫</span>
				<span style="FONT-SIZE: 10pt; FONT-FAMILY: helvetica,helv,arial,sans-serif; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">
				</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt; mso-bidi-font-size: 12.0pt">Test</span>
				<span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'helvetica,helv,arial,sans-serif'; mso-hansi-font-family: 'helvetica,helv,arial,sans-serif'; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">，那么这个内部类将被编译成</span>
				<span style="FONT-SIZE: 10pt; FONT-FAMILY: helvetica,helv,arial,sans-serif; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">
				</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt; mso-bidi-font-size: 12.0pt">Foo$Test.class</span>
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: helvetica,helv,arial,sans-serif; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">
				</span>
				<span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'helvetica,helv,arial,sans-serif'; mso-hansi-font-family: 'helvetica,helv,arial,sans-serif'; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">文件。</span>
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: helvetica,helv,arial,sans-serif; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">.class </span>
				<span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'helvetica,helv,arial,sans-serif'; mso-hansi-font-family: 'helvetica,helv,arial,sans-serif'; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">文件的分离意味着您可以将辅助的嵌套代码与主要的外部类牢固地捆绑在一起。它们在同一个源文件中，内部类的确是在外部类的</span>
				<i>
						<span style="FONT-SIZE: 10pt; FONT-FAMILY: helvetica,helv,arial,sans-serif; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">
						</span>
				</i>
				<i>
						<span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'helvetica,helv,arial,sans-serif'; mso-hansi-font-family: 'helvetica,helv,arial,sans-serif'; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">内部</span>
				</i>
				<span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'helvetica,helv,arial,sans-serif'; mso-hansi-font-family: 'helvetica,helv,arial,sans-serif'; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">。您无需再付出任何发布或运行时的开销。真棒！例如，如果辅助代码只是用于调试，那么您只需发布</span>
				<span style="FONT-SIZE: 10pt; FONT-FAMILY: helvetica,helv,arial,sans-serif; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">
				</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt; mso-bidi-font-size: 12.0pt">Foo.class</span>
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: helvetica,helv,arial,sans-serif; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">
				</span>
				<span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'helvetica,helv,arial,sans-serif'; mso-hansi-font-family: 'helvetica,helv,arial,sans-serif'; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">文件而将</span>
				<span style="FONT-SIZE: 10pt; FONT-FAMILY: helvetica,helv,arial,sans-serif; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">
				</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt; mso-bidi-font-size: 12.0pt">Foo$Test.class</span>
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: helvetica,helv,arial,sans-serif; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">
				</span>
				<span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'helvetica,helv,arial,sans-serif'; mso-hansi-font-family: 'helvetica,helv,arial,sans-serif'; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">文件留下即可。</span>
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: helvetica,helv,arial,sans-serif; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">
						<p>
						</p>
				</span>
		</p>
		<p>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-pagination: widow-orphan" align="left">
				<span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'helvetica,helv,arial,sans-serif'; mso-hansi-font-family: 'helvetica,helv,arial,sans-serif'; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">我将这个技巧主要用于编写外部类的演示代码、错误调试代码，以及进行单元测试实现类行为的自动验证。（当然，做为一个勤奋的开发人员，我准备将测试代码转化成单元测试。）</span>
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: helvetica,helv,arial,sans-serif; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">
						<p>
						</p>
				</span>
		</p>
		<p>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-pagination: widow-orphan" align="left">
				<span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'helvetica,helv,arial,sans-serif'; mso-hansi-font-family: 'helvetica,helv,arial,sans-serif'; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">注意，要执行</span>
				<span style="FONT-SIZE: 10pt; FONT-FAMILY: helvetica,helv,arial,sans-serif; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">
						<span lang="EN-US">TestDebug</span>
				</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt; mso-bidi-font-size: 12.0pt">.class</span>
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: helvetica,helv,arial,sans-serif; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">
				</span>
				<span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'helvetica,helv,arial,sans-serif'; mso-hansi-font-family: 'helvetica,helv,arial,sans-serif'; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">类的</span>
				<span style="FONT-SIZE: 10pt; FONT-FAMILY: helvetica,helv,arial,sans-serif; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">
				</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt; mso-bidi-font-size: 12.0pt">main()</span>
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: helvetica,helv,arial,sans-serif; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">
				</span>
				<span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'helvetica,helv,arial,sans-serif'; mso-hansi-font-family: 'helvetica,helv,arial,sans-serif'; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">方法，请使用下面的命令：</span>
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: helvetica,helv,arial,sans-serif; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">
						<p>
						</p>
				</span>
		</p>
		<p>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-pagination: widow-orphan" align="left">
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt; mso-bidi-font-size: 12.0pt">% java TestDebug$Test</span>
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: helvetica,helv,arial,sans-serif; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">
						<p>
						</p>
				</span>
		</p>
		<p>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-pagination: widow-orphan" align="left">
				<span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'helvetica,helv,arial,sans-serif'; mso-hansi-font-family: 'helvetica,helv,arial,sans-serif'; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">如果您正在使用的命令解释程序（</span>
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: helvetica,helv,arial,sans-serif; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">shell</span>
				<span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'helvetica,helv,arial,sans-serif'; mso-hansi-font-family: 'helvetica,helv,arial,sans-serif'; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">）把</span>
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: helvetica,helv,arial,sans-serif; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">“$”</span>
				<span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'helvetica,helv,arial,sans-serif'; mso-hansi-font-family: 'helvetica,helv,arial,sans-serif'; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">做为一个保留字，那么您应该使用下面的命令：</span>
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: helvetica,helv,arial,sans-serif; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">
						<p>
						</p>
				</span>
		</p>
		<p>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-pagination: widow-orphan" align="left">
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt; mso-bidi-font-size: 12.0pt">% java TestDebug\$Test</span>
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: helvetica,helv,arial,sans-serif; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">
						<p>
						</p>
				</span>
		</p>
		<p>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-pagination: widow-orphan" align="left">
				<span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'helvetica,helv,arial,sans-serif'; mso-hansi-font-family: 'helvetica,helv,arial,sans-serif'; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">还有一点十分有趣：静态内部类根据定义可以访问外部类的保护域和私有域。这件事可以说既有利也有弊。因为您可能在不经意间就破坏了外部类的保护域和私有域，从而违反了它的封装性，所以请小心对待！这一功能最恰当的应用就是编写类的</span>
				<i>
						<span style="FONT-SIZE: 10pt; FONT-FAMILY: helvetica,helv,arial,sans-serif; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">
						</span>
				</i>
				<i>
						<span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'helvetica,helv,arial,sans-serif'; mso-hansi-font-family: 'helvetica,helv,arial,sans-serif'; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">白盒</span>
				</i>
				<span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'helvetica,helv,arial,sans-serif'; mso-hansi-font-family: 'helvetica,helv,arial,sans-serif'; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">测试程序－－因为这样可以引入一些利用通常的<i>黑盒</i>测试很难引入的问题（黑盒测试不能访问对象的内部状态）。</span>
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: helvetica,helv,arial,sans-serif; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">
						<p>
						</p>
				</span>
		</p>
		<p>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-pagination: widow-orphan" align="left">
				<b>
						<span style="FONT-SIZE: 13.5pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'helvetica,helv,arial,sans-serif'; mso-hansi-font-family: 'helvetica,helv,arial,sans-serif'; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt; mso-bidi-font-size: 12.0pt">结论</span>
				</b>
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: helvetica,helv,arial,sans-serif; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">
						<br />
				</span>
				<span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: helvetica,helv,arial,sans-serif; mso-hansi-font-family: helvetica,helv,arial,sans-serif; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">通过使用静态内部类，您可以给您的系统添加辅助功能，以便完成诸如测试之类的工作，而对正式发布的产品不会带来任何不利影响。</span>
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: helvetica,helv,arial,sans-serif; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">
						<p>
						</p>
				</span>
		</p>
		<p>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">
						<p>
								<font face="Times New Roman" size="3">
								</font> </p>
				</span>
		</p>
<img src ="http://www.blogjava.net/43880800/aggbug/96530.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/43880800/" target="_blank">Tom</a> 2007-01-29 16:21 <a href="http://www.blogjava.net/43880800/archive/2007/01/29/96530.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>PO BO VO DTO POJO DAO概念及其作用（附转换图） </title><link>http://www.blogjava.net/43880800/archive/2007/01/23/95478.html</link><dc:creator>Tom</dc:creator><author>Tom</author><pubDate>Tue, 23 Jan 2007 02:51:00 GMT</pubDate><guid>http://www.blogjava.net/43880800/archive/2007/01/23/95478.html</guid><wfw:comment>http://www.blogjava.net/43880800/comments/95478.html</wfw:comment><comments>http://www.blogjava.net/43880800/archive/2007/01/23/95478.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/43880800/comments/commentRss/95478.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/43880800/services/trackbacks/95478.html</trackback:ping><description><![CDATA[
		<div class="posthead">
				<h2>
						<a class="singleposttitle" id="viewpost1_TitleUrl" href="/vip01/archive/2007/01/08/92430.html">PO BO VO DTO POJO DAO概念及其作用（附转换图）</a>
				</h2>Posted on 2007-01-08 17:52 <a href="/vip01/">交口称赞</a> 阅读(946) <a href="/vip01/archive/2007/01/08/92430.html#Post">评论(5)</a>  <a href="/vip01/admin/EditPosts.aspx?postid=92430">编辑</a> <a href="/vip01/AddToFavorite.aspx?id=92430">收藏</a><a href="/vip01/services/trackbacks/92430.aspx">引用</a><a href="javascript:d=document;t=d.selection?(d.selection.type!='None'?d.selection.createRange().text:''):(d.getSelection?d.getSelection():'');void(saveit=window.open('http://wz.csdn.net/storeit.aspx?t='+escape(d.title)+'&amp;u='+escape(d.location.href)+'&amp;c='+escape(t),'saveit','scrollbars=no,width=590,height=300,left=75,top=20,status=no,resizable=yes'));saveit.focus();">网摘</a> 所属分类: <a href="/vip01/category/16743.html">Java</a><img height="1" src="/vip01/aggbug/92430.html?webview=1" width="1" /><!--
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
<rdf:Description
rdf:about="http://www.blogjava.net/vip01/archive/2007/01/08/92430.html"
dc:identifier="http://www.blogjava.net/vip01/archive/2007/01/08/92430.html"
dc:title="PO BO VO DTO POJO DAO概念及其作用（附转换图）"
trackback:ping="http://www.blogjava.net/vip01/services/trackbacks/92430.aspx" />
</rdf:RDF>
--></div>
		<div class="postbody">
				<p>   J2EE开发中大量的专业缩略语很是让人迷惑，尤其是跟一些高手讨论问题的时候，三分钟就被人家满口的专业术语喷晕了，PO VO BO DTO POJO DAO，一大堆的就来了（听过老罗对这种现象的批判的朋友会会心一笑）。</p>
				<p>    首先声明偶也不是什么高手，以下总结都是自己的体会。不对之处请您多指教。</p>
				<p>PO：<br />persistant object持久对象<br /><br />最形象的理解就是一个PO就是数据库中的一条记录。<br />好处是可以把一条记录作为一个对象处理，可以方便的转为其它对象。<br /></p>
				<p>
				</p>
				<hr />
				<p>
						<br />BO：<br /><font size="4">business object</font><font size="4">业务对象<br /><br />主要作用是把业务逻辑封装为一个对象。这个对象可以包括一个或多个其它的对象。<br />比如一个简历，有教育经历、工作经历、社会关系等等。<br />我们可以把教育经历对应一个PO，工作经历对应一个PO，社会关系对应一个PO。<br />建立一个对应简历的BO对象处理简历，每个BO包含这些PO。<br />这样处理业务逻辑时，我们就可以针对BO去处理。<br /></font></p>
				<p>
				</p>
				<hr />
				<p>
						<br />VO ：<br />value object值对象<br /><font size="3">ViewObject表现层对象<br /><br /></font>主要对应界面显示的数据对象。对于一个WEB页面，或者SWT、SWING的一个界面，用一个VO对象对应整个界面的值。<br /></p>
				<p>
				</p>
				<hr />
				<p>
						<br />DTO ：<br />Data Transfer Object数据传输对象<br />主要用于远程调用等需要大量传输对象的地方。<br />比如我们一张表有100个字段，那么对应的PO就有100个属性。<br />但是我们界面上只要显示10个字段，<br />客户端用WEB service来获取数据，没有必要把整个PO对象传递到客户端，<br />这时我们就可以用只有这10个属性的DTO来传递结果到客户端，这样也不会暴露服务端表结构.到达客户端以后，如果用这个对象来对应界面显示，那此时它的身份就转为VO<br /></p>
				<p>
				</p>
				<hr />
				<p>
						<br />POJO ：<br /><font color="#333333" size="3">plain ordinary java object 简单java对象<br /></font>个人感觉POJO是最常见最多变的对象，是一个中间对象，也是我们最常打交道的对象。<br /><br />一个POJO持久化以后就是PO<br />直接用它传递、传递过程中就是DTO<br />直接用来对应表示层就是VO<br /><br /></p>
				<p>
				</p>
				<hr />
				<p>DAO：<br />data access object数据访问对象<br />这个大家最熟悉，和上面几个O区别最大，基本没有互相转化的可能性和必要.<br />主要用来封装对数据库的访问。通过它可以把POJO持久化为PO，用PO组装出来VO、DTO<br /><br /><br />      总结下我认为一个对象究竟是什么O要看具体环境，在不同的层、不同的应用场合，对象的身份也不一样，而且对象身份的转化也是很自然的。就像你对老婆来说就是老公，对父母来说就是子女。设计这些概念的初衷不是为了唬人而是为了更好的理解和处理各种逻辑，让大家能更好的去用<font color="#ff0000">面向对象</font>的方式处理问题.<br /><br />      大家千万不要陷入过度设计，大可不必为了设计而设计一定要在代码中区分各个对象。一句话技术是为应用服务的。<br /><br />欢迎指正。<br /><br /></p>
				<hr />
				<br />画了个图，感觉没有完全表达出自己的意思。。。。。谁帮忙完善下，最好能体现各个O在MVC中的位置<br /><img height="480" alt="snap20070108.jpg" src="http://www.blogjava.net/images/blogjava_net/vip01/snap20070108.jpg" width="557" border="0" /></div>
<img src ="http://www.blogjava.net/43880800/aggbug/95478.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/43880800/" target="_blank">Tom</a> 2007-01-23 10:51 <a href="http://www.blogjava.net/43880800/archive/2007/01/23/95478.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>适配器模式</title><link>http://www.blogjava.net/43880800/archive/2007/01/23/95476.html</link><dc:creator>Tom</dc:creator><author>Tom</author><pubDate>Tue, 23 Jan 2007 02:44:00 GMT</pubDate><guid>http://www.blogjava.net/43880800/archive/2007/01/23/95476.html</guid><wfw:comment>http://www.blogjava.net/43880800/comments/95476.html</wfw:comment><comments>http://www.blogjava.net/43880800/archive/2007/01/23/95476.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/43880800/comments/commentRss/95476.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/43880800/services/trackbacks/95476.html</trackback:ping><description><![CDATA[
		<font color="#009900">适配器模式：<br />如果你有两个编译好的(无源代码)类，类A有某些功能，但是需要一个xml读取模块才能工作，<br />这个模块要实现这个接口:<br />public interface XmlReader{<br />       public InputStream xmlReader();<br />}<br />你的另一个类B恰好有这个功能，但是B实现的是这个接口:<br />public interface ReaderXml{<br />       public InputStream readerXml();<br />}<br />这个时候我们的做法是写个适配器<br />public class Adapter implements XmlReader extends B{<br />       public InputStream xmlReader(){<br />              return readerXml();<br />      }<br />}<br />这个就是适配器模式了。<br />适配器模式还有另外一种实现方式<br />public class Adapter implements XmlReader<br />       ReaderXml b = new B();<br />       public InputStream xmlReader(){<br />               return b.readerXml();<br />       }<br />}</font>
<img src ="http://www.blogjava.net/43880800/aggbug/95476.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/43880800/" target="_blank">Tom</a> 2007-01-23 10:44 <a href="http://www.blogjava.net/43880800/archive/2007/01/23/95476.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>更详细的 Bridge Adapter Facade模式之间的比较</title><link>http://www.blogjava.net/43880800/archive/2007/01/23/95474.html</link><dc:creator>Tom</dc:creator><author>Tom</author><pubDate>Tue, 23 Jan 2007 02:34:00 GMT</pubDate><guid>http://www.blogjava.net/43880800/archive/2007/01/23/95474.html</guid><wfw:comment>http://www.blogjava.net/43880800/comments/95474.html</wfw:comment><comments>http://www.blogjava.net/43880800/archive/2007/01/23/95474.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/43880800/comments/commentRss/95474.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/43880800/services/trackbacks/95474.html</trackback:ping><description><![CDATA[
		<h2>
				<a id="viewpost1_TitleUrl" href="/dreamstone/archive/2007/01/08/92482.html">
						<font style="BACKGROUND-COLOR: #ffffff" color="#800080">更详细的 Bridge Adapter Facade模式之间的比较</font>
				</a>
				<font color="#cc3333">
				</font>
		</h2>
		<a href="/dreamstone/archive/2007/01/07/92268.html">
				<font color="#a52a2a">在这篇文章中</font>
		</a>
		<font color="#a52a2a">，我写了Bridge和adapter模式的区别.但是 maninred说<br />Bridge和adapter是没有关系的，而和Facade比较象，但在我的经验中更多的时候<br />是会混淆Bridge和adapter而不是Facade，这里详细的列出三个模式的比较 .<br />一,定义:<br />1.Facade模式是为一个复杂系统提供一个简单的接口。<br />比如你要去博物馆参观，很多东西，你一个个到处去问每个东西的管理员很麻烦，所以你找一个导游，让他给你一个个介绍，你只要找到导游就好了。导游就是门面。<br />2，适配器模式，引用一下GOF95中的话:<br />适配器模式是把一个类的接口变换成客户端所期待的另一种接口，从而使原本因接口不匹配而无法工作的两个类能够工作到一起。<br />举个例子，例如变压器<br />3，Bridge模式:<br />GOF95中的桥梁模式的描述：桥梁模式的用意是"将抽象化与实现化脱耦，使的二者可以独立变化。<br />例如AWT的实现<br />二,目的:<br />1,Facade模式使用在给一个复杂的系统提供统一的门面(接口),目的是简化客户端的操作,但并没有改变接口.<br />2,Adapter模式使用在两个部分有不同的接口的情况,目的是改变接口,使两个部分协同工作<br />3,桥梁模式是为了分离抽象和实现<br />二,使用场合<br />1,Facade模式出现较多的情况是这样的情况,你有一个复杂的系统,对应了各种情况,<br />客户看了说功能不错,但是使用太麻烦.你说没问题,我给你提供一个统一的门面.<br />所以Facade使用的场合多是对系统的"优化".<br />2,Adapter模式出现的情况是这样,你有一个类提供接口A,但是你的客户需要一个实现接口B的类,<br />这个时候你可以写一个Adapter让把A接口变成B接口,所以Adapter使用的场合是<br />指鹿为马.就是你受夹板气的时候,一边告诉你我只能提供给你A(鹿),一边告诉你说<br />我只要B(马),他长了四条腿,你没办法了,把鹿牵过去说,这是马,你看他有四条腿.<br />(当然实现指鹿为马也有两种方法,一个方法是你只露出鹿的四条腿,说你看这是马,这种方式就是<br />封装方式的Adapter实现,另一种方式是你把鹿牵过去,但是首先介绍给他说这是马,因为他长了四条腿<br />这种是继承的方式.)<br />3,Bridge模式在一般的开发中出现的情况并不多,AWT是一个,SWT也算部分是,<br />如果你的客户要求你开发一个系统,这个系统在Windows下运行界面的样子是Windows的样子.<br />在Linux下运行是Linux下的样子.在Macintosh下运行要是Mac Os的样子.<br />怎么办? 定义一系列的控件Button,Text,radio,checkBox等等.供上层开发者<br />使用,他们使用这些控件的方法,利用这些控件构造一个系统的GUI,然后你为这些控件<br />写好Linux的实现,让它在Linux上调用Linux本地的对应控件,<br />在Windows上调用Windows本地的对应控件,在Macintosh上调用Macintosh本地的对应控件<br />ok,你的任务完成了.<br />三,需求程度<br />1,Facade的需求程度是"中等",因为你不提供Facade程序照样能工作,只是不够好.<br />2,Adapter的需求程度是"必须",因为你不这么做就不能工作,除非你自己从头实现一个.<br />3,Bridge的需求程度是"一般",适合精益求精的人,因为你可以写三个程序给客户.<br />四,出现时期<br />1,Facade出现在项目中期,再优化<br />2,Adapter出现在项目后期,大部分都有了,差的仅仅是接口不同<br />3,Bridge出现在项目前期,你想让你的系统更灵活,更cool<br />五,在写文章的时候想到的<br />1,Facade很多时候是1:m的关系<br />2,Adapter很多是候是1:1的关系<br />3,Bridge很多时候是m:n的关系<br />呵呵.<br />六,最后<br />另外:回应一下maninred<br />1,我并没有把模式看的很独立,其实很多模式是配合使用的,而且在一定情况下可以<br />用一个替换另一个.同一个需求,有可能当你思考的角度不同时,使用的模式就不同了.<br />2,设计模式并不是"用OO的封装来封装所有的东西",模式其实可以应用于所有的设计上<br />和OO没有直接的关系,只是因为计算机的设计模式大部分是GOF收集总结的,<br />他们讲解设计模式是用的C++,而在Java中得到了大量应用,所以我们谈到设计模式<br />的时候多提到OO.其实模式更早应用于建筑学,Alexander的《建筑的永恒之道》讲的<br />就是设计模式。所以说设计模式应该是设计过程中积累下来的一些成型的东西。<br />更深入一点，《Java与模式》的作者认为模式起源于中国的道教思想，讲的是哲学。呵呵。<br />3，对于模式的使用，个人感觉，模式很大程度上是为了对应这类需求的所有情况，也就<br />是最复杂情况，最灵活情况，当我们实际的开发中并没有遇到这么多这样的情况。<br />所以在需要的时候使用，根据需求简化使用，而不是照搬。<br />4,虽然模式是相关的，但是只有知道了每个模式的区别点，才能更好的根据需求选择使用哪个模式。</font>
<img src ="http://www.blogjava.net/43880800/aggbug/95474.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/43880800/" target="_blank">Tom</a> 2007-01-23 10:34 <a href="http://www.blogjava.net/43880800/archive/2007/01/23/95474.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java抽象类和接口的区别</title><link>http://www.blogjava.net/43880800/archive/2007/01/23/95467.html</link><dc:creator>Tom</dc:creator><author>Tom</author><pubDate>Tue, 23 Jan 2007 02:00:00 GMT</pubDate><guid>http://www.blogjava.net/43880800/archive/2007/01/23/95467.html</guid><wfw:comment>http://www.blogjava.net/43880800/comments/95467.html</wfw:comment><comments>http://www.blogjava.net/43880800/archive/2007/01/23/95467.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/43880800/comments/commentRss/95467.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/43880800/services/trackbacks/95467.html</trackback:ping><description><![CDATA[
		<span style="FONT-WEIGHT: 400">
				<span class="unnamed4">
						<font style="BACKGROUND-COLOR: #f5f5dc">
								<font color="#0000ff">
										<font style="FONT-SIZE: 9pt">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的功能，那么上述的定义方式就要反过来了。</font>
								</font>
						</font>
				</span>
		</span>
<img src ="http://www.blogjava.net/43880800/aggbug/95467.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/43880800/" target="_blank">Tom</a> 2007-01-23 10:00 <a href="http://www.blogjava.net/43880800/archive/2007/01/23/95467.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JDOM使用详解及实例</title><link>http://www.blogjava.net/43880800/archive/2006/12/12/87308.html</link><dc:creator>Tom</dc:creator><author>Tom</author><pubDate>Tue, 12 Dec 2006 09:21:00 GMT</pubDate><guid>http://www.blogjava.net/43880800/archive/2006/12/12/87308.html</guid><wfw:comment>http://www.blogjava.net/43880800/comments/87308.html</wfw:comment><comments>http://www.blogjava.net/43880800/archive/2006/12/12/87308.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/43880800/comments/commentRss/87308.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/43880800/services/trackbacks/87308.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: JDOM使用详解及实例																																																																						一、																		JDOM 																简介																										...&nbsp;&nbsp;<a href='http://www.blogjava.net/43880800/archive/2006/12/12/87308.html'>阅读全文</a><img src ="http://www.blogjava.net/43880800/aggbug/87308.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/43880800/" target="_blank">Tom</a> 2006-12-12 17:21 <a href="http://www.blogjava.net/43880800/archive/2006/12/12/87308.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Aaron Johnson对Class.forName()的解释</title><link>http://www.blogjava.net/43880800/archive/2006/11/19/Tom.html</link><dc:creator>Tom</dc:creator><author>Tom</author><pubDate>Sun, 19 Nov 2006 12:44:00 GMT</pubDate><guid>http://www.blogjava.net/43880800/archive/2006/11/19/Tom.html</guid><wfw:comment>http://www.blogjava.net/43880800/comments/82096.html</wfw:comment><comments>http://www.blogjava.net/43880800/archive/2006/11/19/Tom.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/43880800/comments/commentRss/82096.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/43880800/services/trackbacks/82096.html</trackback:ping><description><![CDATA[
		<font color="#008000">
				<br />
		</font>
		<div class="postbody">
				<p>
						<font color="#008000">    A reader asked a question via a comment a couple months ago that I didn't really have an answer for (and had always kind of wondered the same thing). In <a href="http://cephas.net/blog/2004/05/10/coldfusion_mx_and_javasql.html">the original post</a> (which showed how to use JDBC with ColdFusion), I used the following snippet of code:<br /><code><br />Class.forName("jdbc.DriverXYZ");<br />Connection con = DriverManager.getConnection(url,<br />  "myLogin", "myPassword");<br /></code><br />and the reader wanted to know what the <code>Class.forName(..)</code> method did. The most common answer you'll hear is that it loads the database driver, which, while technically true, is shallow. Where does it get loaded? How does it happen? And why?</font>
				</p>
				<p>
						<font color="#008000">To answer the question I started with the <a href="http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Class.html#forName%28java.lang.String,%20boolean,%20java.lang.ClassLoader%29">JavaDoc for the Class.forName() method</a>. According to the documentation, the method: </font>
				</p>
				<blockquote>
						<font color="#008000">... attempts to locate, load, and link the class or interface</font>
				</blockquote>
				<font color="#008000">I wasn't perfectly clear on what "locate, load, and link" meant, so I did a little digging through the <a href="http://java.sun.com/docs/books/jls/">Java Language Specification</a>. According to <a href="http://java.sun.com/docs/books/jls/second_edition/html/execution.doc.html#44411">chapter 12 of the JLS</a>: </font>
				<blockquote>
						<font color="#008000">Loading refers to the process of finding the binary form of a class or interface type with a particular name, perhaps by computing it on the fly, but more typically by retrieving a binary representation previously computed from source code by a compiler, and constructing, from that binary form, a Class object to represent the class or interface.</font>
				</blockquote>
				<font color="#008000">Next, again according to the JLS, it must be transformed from it's binary representation to something the Java virtual machine can use, this process is called linking. Finally, the class is initialized, which is the process that executes the static initializer and the initializers for static fields declared in the class. </font>
				<p>
						<font color="#008000">So then back to the original problem, when Class.forName() is called with an argument like this:<br /><code><br />Class.forName("org.gjt.mm.mysql.Driver");<br /></code><br />the classloader attempts to load and link the <code>Driver</code> class in the "org.gjt.mm.mysql" package and if successful, the static initializer is run. The MySQL <code>Driver</code> (download the <a href="http://dev.mysql.com/downloads/connector/j/3.1.html">source code</a>) static initializer looks like this:<br /><code><br />static {<br />  try {<br />    java.sql.DriverManager.registerDriver(new Driver());<br />  } catch (SQLException E) {<br />    throw new RuntimeException("Can't register driver!");<br />  }<br />}<br /></code><br />So it calls a static method in the <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/sql/DriverManager.html">java.sql.DriverManager</a> class which apparently registers a copy of itself when it loads.</font>
				</p>
				<p>
						<font color="#008000">So now I understand the where and the how, what about why? To understand the why you have to look at the next line in the initial code example:<br /><code><br />Connection con = DriverManager.getConnection(url,<br />  "myLogin", "myPassword");<br /></code><br />The <code>DriverManager</code> class (view DriverManager source <a href="http://developer.classpath.org/doc/java/sql/DriverManager-source.html">here</a>) returns a database connection given a JDBC URL string, a username and a password. In order to create that connection, the DriverManager class has to know which database driver you want to use. It does that by iterating over the array (internally a Vector) of drivers that have registered with it (ie: the <code>registerDriver(Driver driver)</code> method illustrated above) and calls the <code>acceptsURL(url))</code> method on each driver in the array, effectively asking the driver to tell it whether or not it can handle the JDBC URL. </font>
				</p>
				<p>
						<font color="#008000">So there you have it. Class.forName explained.</font>
				</p>
		</div>
<img src ="http://www.blogjava.net/43880800/aggbug/82096.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/43880800/" target="_blank">Tom</a> 2006-11-19 20:44 <a href="http://www.blogjava.net/43880800/archive/2006/11/19/Tom.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>