﻿<?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/balajinima/category/24467.html</link><description /><language>zh-cn</language><lastBuildDate>Tue, 03 Nov 2009 08:20:18 GMT</lastBuildDate><pubDate>Tue, 03 Nov 2009 08:20:18 GMT</pubDate><ttl>60</ttl><item><title>Java对象的序列化和反序列化实践</title><link>http://www.blogjava.net/balajinima/articles/286124.html</link><dc:creator>李云泽</dc:creator><author>李云泽</author><pubDate>Thu, 09 Jul 2009 09:52:00 GMT</pubDate><guid>http://www.blogjava.net/balajinima/articles/286124.html</guid><wfw:comment>http://www.blogjava.net/balajinima/comments/286124.html</wfw:comment><comments>http://www.blogjava.net/balajinima/articles/286124.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/balajinima/comments/commentRss/286124.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/balajinima/services/trackbacks/286124.html</trackback:ping><description><![CDATA[<p>&nbsp;</p>
&nbsp;
<div id="artibody"><!-- Error -->
<div class="clear1">　　当两个进程在进行远程通信时，彼此可以发送各种类型的数据。无论是何种类型的数据，都会以二进制序列的形式在网络上传送。发送方需要把这个Java对象转换为字节序列，才能在网络上传送；接收方则需要把字节序列再恢复为Java对象。 <br />
<br />
　　把Java对象转换为字节序列的过程称为对象的序列化。<br />
<br />
　　把字节序列恢复为Java对象的过程称为对象的反序列化。<br />
<br />
　　对象的序列化主要有两种用途：<br />
<br />
　　1） 把对象的字节序列永久地保存到<a class="fllink" href="http://product.yesky.com/harddisk/" target="_bank">硬盘</a>上，通常存放在一个文件中；<br />
<br />
　　2） 在网络上传送对象的字节序列。<br />
<br />
　　<strong>一． JDK类库中的序列化API</strong><br />
<br />
　　java.io.ObjectOutputStream代表对象输出流，它的writeObject(Object obj)方法可对参数指定的obj对象进行序列化，把得到的字节序列写到一个目标输出流中。<br />
<br />
　　java.io.ObjectInputStream代表对象输入流，它的readObject()方法从一个源输入流中读取字节序列，再把它们反序列化为一个对象，并将其返回。、<br />
<br />
　　只有实现了Serializable和Externalizable接口的类的对象才能被序列化。Externalizable接口继承自Serializable接口，实现Externalizable接口的类完全由自身来控制序列化的行为，而仅实现Serializable接口的类可以采用默认的序列化方式 。<br />
<br />
　　对象序列化包括如下步骤：<br />
<br />
　　1） 创建一个对象输出流，它可以包装一个其他类型的目标输出流，如文件输出流；<br />
<br />
　　2） 通过对象输出流的writeObject()方法写对象。<br />
<br />
　　对象反序列化的步骤如下：<br />
<br />
　　1） 创建一个对象输入流，它可以包装一个其他类型的源输入流，如文件输入流；<br />
<br />
　　2） 通过对象输入流的readObject()方法读取对象。<br />
<br />
　　下面让我们来看一个对应的例子，类的内容如下：<br />
<br />
<table width="90%" bgcolor="#d8d7d3" align="center">
    <tbody>
        <tr>
            <td>import java.io.*;<br />
            import java.util.Date;<br />
            <br />
            /**<br />
            * 对象的序列化和反序列化测试类. <br />
            * @author &lt;a href="mailto:xiexingxing1121@126.com"&gt;AmigoXie&lt;/a&gt;<br />
            * @version 1.0 <br />
            * Creation date: 2007-9-15 - 下午21:45:48<br />
            */<br />
            <br />
            public class ObjectSaver {<br />
            　/**<br />
            　* @param args<br />
            　* @author &lt;a href="mailto:xiexingxing1121@126.com"&gt;AmigoXie&lt;/a&gt;<br />
            　* Creation date: 2007-9-15 - 下午21:45:37<br />
            　*/<br />
            <br />
            public static void main(String[] args) throws Exception {<br />
            　ObjectOutputStream out = new ObjectOutputStream<br />
            (new FileOutputStream("D:""objectFile.obj"));<br />
            <br />
            　//序列化对象<br />
            <br />
            　Customer customer = new Customer("阿蜜果", 24);<br />
            　out.writeObject("你好!");<br />
            　out.writeObject(new Date());<br />
            　out.writeObject(customer);<br />
            　out.writeInt(123); //写入基本类型数据<br />
            　out.close();<br />
            　//反序列化对象<br />
            <br />
            　ObjectInputStream in = new ObjectInputStream<br />
            (new FileInputStream("D:""objectFile.obj"));<br />
            <br />
            　System.out.println("obj1=" + (String) in.readObject());<br />
            　System.out.println("obj2=" + (Date) in.readObject());<br />
            　Customer obj3 = (Customer) in.readObject();<br />
            　System.out.println("obj3=" + obj3);<br />
            　int obj4 = in.readInt();<br />
            　System.out.println("obj4=" + obj4);<br />
            　in.close();<br />
            }<br />
            }<br />
            <br />
            class Customer implements Serializable {<br />
            private String name;<br />
            private int age;<br />
            public Customer(String name, int age) {<br />
            this.name = name;<br />
            this.age = age;<br />
            }<br />
            <br />
            public String toString() {<br />
            return "name=" + name + ", age=" + age;<br />
            }<br />
            }</td>
        </tr>
    </tbody>
</table>
<br />
　　输出结果如下：<br />
<br />
<table width="90%" bgcolor="#d8d7d3" align="center">
    <tbody>
        <tr>
            <td>obj1=你好!<br />
            <br />
            obj2=Sat Sep 15 22:02:21 CST 2007<br />
            <br />
            obj3=name=阿蜜果, age=24<br />
            <br />
            obj4=123</td>
        </tr>
    </tbody>
</table>
<br />
　　因此例比较简单，在此不再详述。<br />
<br />
　　<strong>二．实现Serializable接口</strong><br />
<br />
　　ObjectOutputStream只能对Serializable接口的类的对象进行序列化。默认情况下，ObjectOutputStream按照默认方式序列化，这种序列化方式仅仅对对象的非transient的实例变量进行序列化，而不会序列化对象的transient的实例变量，也不会序列化静态变量。<br />
<br />
　　当ObjectOutputStream按照默认方式反序列化时，具有如下特点：<br />
<br />
　　1） 如果在<a class="fllink" href="http://product.yesky.com/memory/" target="_bank">内存</a>中对象所属的类还没有被加载，那么会先加载并初始化这个类。如果在classpath中不存在相应的类文件，那么会抛出ClassNotFoundException；<br />
<br />
　　2） 在反序列化时不会调用类的任何构造方法。<br />
<br />
　　如果用户希望控制类的序列化方式，可以在可序列化类中提供以下形式的writeObject()和readObject()方法。<br />
<br />
<table width="90%" bgcolor="#d8d7d3" align="center">
    <tbody>
        <tr>
            <td>private void writeObject(java.io.ObjectOutputStream out) throws IOException<br />
            <br />
            private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException;</td>
        </tr>
    </tbody>
</table>
<br />
　　当ObjectOutputStream对一个Customer对象进行序列化时，如果该对象具有writeObject()方法，那么就会执行这一方法，否则就按默认方式序列化。在该对象的writeObjectt()方法中，可以先调用ObjectOutputStream的defaultWriteObject()方法，使得对象输出流先执行默认的序列化操作。同理可得出反序列化的情况，不过这次是defaultReadObject()方法。<br />
<br />
　　有些对象中包含一些敏感信息，这些信息不宜对外公开。如果按照默认方式对它们序列化，那么它们的序列化数据在网络上传输时，可能会被不法份子窃取。对于这类信息，可以对它们进行加密后再序列化，在反序列化时则需要解密，再恢复为原来的信息。<br />
<br />
　　默认的序列化方式会序列化整个对象图，这需要递归遍历对象图。如果对象图很复杂，递归遍历操作需要消耗很多的空间和时间，它的内部数据结构为双向列表。<br />
<br />
　　在应用时，如果对某些成员变量都改为transient类型，将节省空间和时间，提高序列化的性能。<br />
<br />
　　<strong>三． 实现Externalizable接口</strong><br />
<br />
　　Externalizable接口继承自Serializable接口，如果一个类实现了Externalizable接口，那么将完全由这个类控制自身的序列化行为。Externalizable接口声明了两个方法：<br />
<br />
<table width="90%" bgcolor="#d8d7d3" align="center">
    <tbody>
        <tr>
            <td>public void writeExternal(ObjectOutput out) throws IOException<br />
            <br />
            public void readExternal(ObjectInput in) throws IOException , ClassNotFoundException</td>
        </tr>
    </tbody>
</table>
<br />
　　前者负责序列化操作，后者负责反序列化操作。<br />
<br />
　　在对实现了Externalizable接口的类的对象进行反序列化时，会先调用类的不带参数的构造方法，这是有别于默认反序列方式的。如果把类的不带参数的构造方法删除，或者把该构造方法的访问权限设置为private、默认或protected级别，会抛出java.io.InvalidException: no valid constructor异常。<br />
<br />
　　<strong>四． 可序列化类的不同版本的序列化兼容性</strong><br />
<br />
　　凡是实现Serializable接口的类都有一个表示序列化版本标识符的静态变量：<br />
<br />
<table width="90%" bgcolor="#d8d7d3" align="center">
    <tbody>
        <tr>
            <td>private static final long serialVersionUID;</td>
        </tr>
    </tbody>
</table>
<br />
　　以上serialVersionUID的取值是Java运行时环境根据类的内部细节自动生成的。如果对类的源代码作了修改，再重新编译，新生成的类文件的serialVersionUID的取值有可能也会发生变化。<br />
<br />
　　类的serialVersionUID的默认值完全依赖于Java编译器的实现，对于同一个类，用不同的Java编译器编译，有可能会导致不同的serialVersionUID，也有可能相同。为了提高哦啊serialVersionUID的独立性和确定性，强烈建议在一个可序列化类中显示的定义serialVersionUID，为它赋予明确的值。显式地定义serialVersionUID有两种用途：<br />
<br />
　　1） 在某些场合，希望类的不同版本对序列化兼容，因此需要确保类的不同版本具有相同的serialVersionUID；<br />
<br />
　　2） 在某些场合，不希望类的不同版本对序列化兼容，因此需要确保类的不同版本具有不同的serialVersionUID。<br />
</div>
</div>
<img src ="http://www.blogjava.net/balajinima/aggbug/286124.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/balajinima/" target="_blank">李云泽</a> 2009-07-09 17:52 <a href="http://www.blogjava.net/balajinima/articles/286124.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> List排序（转载）</title><link>http://www.blogjava.net/balajinima/articles/264418.html</link><dc:creator>李云泽</dc:creator><author>李云泽</author><pubDate>Wed, 08 Apr 2009 03:33:00 GMT</pubDate><guid>http://www.blogjava.net/balajinima/articles/264418.html</guid><wfw:comment>http://www.blogjava.net/balajinima/comments/264418.html</wfw:comment><comments>http://www.blogjava.net/balajinima/articles/264418.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/balajinima/comments/commentRss/264418.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/balajinima/services/trackbacks/264418.html</trackback:ping><description><![CDATA[
		<p> </p>
		<p>import java.lang.reflect.InvocationTargetException;<br />import java.lang.reflect.Method;<br />import java.text.CollationKey;<br />import java.text.Collator;<br />import java.text.RuleBasedCollator;<br />import java.util.*;</p>
		<p>
				<br />/**<br /> * &lt;strong&gt;Title : ListComparator &lt;/strong&gt;. &lt;br&gt;<br /> * &lt;strong&gt;Description : List排序器（支持中文排序）.&lt;/strong&gt; &lt;br&gt;<br />  */<br />public class ListComparator implements Comparator {</p>
		<p>
				<br /> /**<br />  * &lt;code&gt;collator&lt;/code&gt; - 排序规则控制器.<br />  */<br /> private RuleBasedCollator collator = (RuleBasedCollator) Collator<br />   .getInstance(java.util.Locale.CHINA);</p>
		<p> /**<br />  * &lt;code&gt;methodName&lt;/code&gt; - 排序字段的方法名.<br />  */<br /> private String methodName;</p>
		<p> /**<br />  * &lt;code&gt;seq&lt;/code&gt; - 排序顺序.<br />  */<br /> private String seq;</p>
		<p> /**<br />  * &lt;code&gt;methodeArgs&lt;/code&gt; - 方法参数.<br />  */<br /> private Object[] methodeArgs;</p>
		<p> /**<br />  * 构造函数(List中存放复杂对象，并且获得排序字段值的方法需要参数).<br />  *<br />  * @param methodName<br />  *            -对象中的方法名<br />  * @param methodeArgs<br />  *            -方法参数<br />  * @param seq<br />  *            -排序顺序<br />  * @throws Exception<br />  */<br /> public ListComparator(String methodName, Object[] methodeArgs, String seq)<br />   throws Exception {</p>
		<p>  this.methodName = methodName;</p>
		<p>  this.methodeArgs = methodeArgs;</p>
		<p>  if (!"asc".equalsIgnoreCase(seq) &amp;&amp; !"desc".equalsIgnoreCase(seq)) {</p>
		<p>   throw new Exception("illegal value of parameter 'seq' for input '"<br />     + seq + "'");<br />  }</p>
		<p>  this.seq = seq;<br /> }</p>
		<p> /**<br />  * 构造函数(List中存放复杂对象，并且获得排序字段值的方法不需要参数).<br />  *<br />  * @param methodName<br />  * @param seq<br />  * @throws Exception<br />  */<br /> public ListComparator(String methodName, String seq) throws Exception {</p>
		<p>  this.methodName = methodName;</p>
		<p>  if (!"asc".equalsIgnoreCase(seq) &amp;&amp; !"desc".equalsIgnoreCase(seq)) {</p>
		<p>   throw new Exception("illegal value of parameter 'seq' for input '"<br />     + seq + "'");<br />  }</p>
		<p>  this.seq = seq;</p>
		<p> }</p>
		<p> /**<br />  * 构造函数(List中存放简单对象).<br />  *<br />  * @param seq<br />  * @throws Exception<br />  */<br /> public ListComparator(String seq) throws Exception {</p>
		<p>  if (!"asc".equalsIgnoreCase(seq) &amp;&amp; !"desc".equalsIgnoreCase(seq)) {</p>
		<p>   throw new Exception("illegal value of parameter 'seq' for input '"<br />     + seq + "'");<br />  }</p>
		<p>  this.seq = seq;<br /> }</p>
		<p> /**<br />  * (non-Javadoc).<br />  *<br />  * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)<br />  */<br /> public int compare(Object obj1, Object obj2) {</p>
		<p>  int t_ret = 0;</p>
		<p>  // 如果指定了方法名，则表示List中存放的是复杂对象<br />  if (this.methodName != null &amp;&amp; !"".equals(this.methodName)) {</p>
		<p>   // 执行Bean中的方法，得到方法返回的对象<br />   Object t_obj1 = invokeMethod(obj1, this.methodName,<br />     this.methodeArgs);<br />   Object t_obj2 = invokeMethod(obj2, this.methodName,<br />     this.methodeArgs);</p>
		<p>   t_ret = selectCompare(t_obj1, t_obj2);</p>
		<p>  } else {</p>
		<p>   t_ret = selectCompare(obj1, obj2);</p>
		<p>  }</p>
		<p>  return t_ret;<br /> }</p>
		<p> /**<br />  * 执行对象的某个方法.<br />  *<br />  * @param owner<br />  *            -对象<br />  * @param methodName<br />  *            -方法名<br />  * @param methodArgs<br />  *            -方法参数<br />  *<br />  * @return 方法返回对象<br />  * @throws InvocationTargetException<br />  * @throws IllegalAccessException<br />  * @throws IllegalArgumentException<br />  * @throws Exception<br />  */<br /> private Object invokeMethod(Object owner, String methodName,<br />   Object[] methodArgs) {</p>
		<p>  Class[] argsClass = null;</p>
		<p>  if (methodArgs != null &amp;&amp; methodArgs.length &gt; 0) {</p>
		<p>   argsClass = new Class[methodeArgs.length];</p>
		<p>   for (int i = 0, j = methodeArgs.length; i &lt; j; i++) {</p>
		<p>    argsClass[i] = methodeArgs[i].getClass();<br />   }<br />  }</p>
		<p>  Class ownerClass = owner.getClass();</p>
		<p>  Method method;<br />  Object t_object = null;<br />  try {<br />   method = ownerClass.getMethod(methodName, argsClass);<br />   t_object = method.invoke(owner, methodArgs);<br />  } catch (SecurityException e) {<br />  } catch (NoSuchMethodException e) {</p>
		<p>   argsClass = new Class[1];<br />   argsClass[0] = Object.class;<br />   try {<br />    method = ownerClass.getMethod(methodName, argsClass);<br />    t_object = method.invoke(owner, methodArgs);<br />   } catch (SecurityException e1) {<br />   } catch (NoSuchMethodException e1) {<br />   } catch (IllegalArgumentException e1) {<br />   } catch (IllegalAccessException e1) {<br />   } catch (InvocationTargetException e1) {<br />   }</p>
		<p>  } catch (IllegalArgumentException e) {<br />  } catch (IllegalAccessException e) {<br />  } catch (InvocationTargetException e) {<br />  }</p>
		<p>  return t_object;<br /> }</p>
		<p>
				<br /> private int selectCompare(Object obj1, Object obj2) {</p>
		<p>  int t_ret = 0;</p>
		<p>  if (obj1 instanceof String &amp;&amp; obj2 instanceof String) {</p>
		<p>   t_ret = compareString(obj1, obj2);<br />  }</p>
		<p>  if (obj1 instanceof Integer &amp;&amp; obj2 instanceof Integer) {</p>
		<p>   t_ret = compareInt(obj1, obj2);<br />  }</p>
		<p>  if (obj1 instanceof Long &amp;&amp; obj2 instanceof Long) {</p>
		<p>   t_ret = compareLong(obj1, obj2);<br />  }</p>
		<p>  if (obj1 instanceof Date &amp;&amp; obj2 instanceof Date) {</p>
		<p>   t_ret = compareDate(obj1, obj2);<br />  }</p>
		<p>  return t_ret;<br /> }</p>
		<p> private int compareString(Object obj1, Object obj2) {</p>
		<p>  int ret = 0;</p>
		<p>  String s1 = (String) obj1;<br />  String s2 = (String) obj2;</p>
		<p>  CollationKey c1 = collator.getCollationKey(s1);<br />  CollationKey c2 = collator.getCollationKey(s2);</p>
		<p>  ret = collator.compare(c1.getSourceString(), c2.getSourceString());</p>
		<p>  if (seq.equalsIgnoreCase("desc")) {</p>
		<p>   ret = ret * -1;<br />  }</p>
		<p>  return ret;<br /> }</p>
		<p> private int compareInt(Object obj1, Object obj2) {</p>
		<p>  int ret = 0;</p>
		<p>  int i1 = ((Integer) obj1).intValue();<br />  int i2 = ((Integer) obj2).intValue();</p>
		<p>  if (i1 &lt; i2)<br />   ret = -1;<br />  else if (i1 &gt; i2)<br />   ret = 1;<br />  else<br />   ret = 0;</p>
		<p>  if (seq.equalsIgnoreCase("desc")) {</p>
		<p>   ret = ret * -1;<br />  }</p>
		<p>  return ret;<br /> }</p>
		<p> private int compareLong(Object obj1, Object obj2) {</p>
		<p>  int ret = 0;</p>
		<p>  long l1 = ((Long) obj1).longValue();<br />  long l2 = ((Long) obj2).longValue();</p>
		<p>  if (l1 &lt; l2)<br />   ret = -1;<br />  else if (l1 &gt; l2)<br />   ret = 1;<br />  else<br />   ret = 0;</p>
		<p>  if (seq.equalsIgnoreCase("desc")) {</p>
		<p>   ret = ret * -1;<br />  }</p>
		<p>  return ret;<br /> }</p>
		<p> private int compareDate(Object obj1, Object obj2) {</p>
		<p>  int ret = 0;</p>
		<p>  Date d1 = (Date) obj1;<br />  Date d2 = (Date) obj2;</p>
		<p>  ret = d1.compareTo(d2);</p>
		<p>  if (seq.equalsIgnoreCase("desc")) {</p>
		<p>   ret = ret * -1;<br />  }</p>
		<p>  return ret;<br /> }<br />}<br /><br /><br /><br />-------------------------------------------------------------------<br />使用<br />-------------------------------------------------------------------<br />private List getSortedList(List unsortedList, String methodName,<br />   Object methodArgs[], String orderSequence) throws Exception {</p>
		<p>  ListComparator t_compare = null;</p>
		<p>  if (null != methodName &amp;&amp; !"".equals(methodName)) {</p>
		<p>   if (methodArgs != null &amp;&amp; methodArgs.length &gt; 0)<br />    t_compare = new ListComparator(methodName, methodArgs,<br />      orderSequence);<br />   else<br />    t_compare = new ListComparator(methodName, orderSequence);<br />  } else {<br />   t_compare = new ListComparator(orderSequence);<br />  }</p>
		<p>  List t_list = unsortedList;</p>
		<p>  Collections.sort(t_list, t_compare);</p>
		<p>  return t_list;<br /> }<br /><br /><br /><br /></p>
<img src ="http://www.blogjava.net/balajinima/aggbug/264418.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/balajinima/" target="_blank">李云泽</a> 2009-04-08 11:33 <a href="http://www.blogjava.net/balajinima/articles/264418.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java中集合类的区别</title><link>http://www.blogjava.net/balajinima/articles/200872.html</link><dc:creator>李云泽</dc:creator><author>李云泽</author><pubDate>Fri, 16 May 2008 04:57:00 GMT</pubDate><guid>http://www.blogjava.net/balajinima/articles/200872.html</guid><wfw:comment>http://www.blogjava.net/balajinima/comments/200872.html</wfw:comment><comments>http://www.blogjava.net/balajinima/articles/200872.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/balajinima/comments/commentRss/200872.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/balajinima/services/trackbacks/200872.html</trackback:ping><description><![CDATA[Array是数组,不在集合框架范畴之内,一旦选定了,它的容量大小就不能改变了,所以通常在编程中不选用数组来存放. <br /><br />集合 : <br />集合对象：用于管理其他若干对象的对象 <br />数组：长度不可变 <br /><br />List: 有顺序的，元素可以重复 <br />遍历：for 迭代 <br />排序：Comparable Comparator Collections.sort() <br />ArrayList：底层用数组实现的List <br />特点：查询效率高，增删效率低 轻量级 线程不安全 <br />LinkedList：底层用双向循环链表 实现的List <br />特点：查询效率低，增删效率高 <br />Vector: 底层用数组实现List接口的另一个类 <br />特点：重量级，占据更多的系统开销 线程安全 <br /><br />Set：无顺序的，元素不可重复（值不相同） <br />遍历：迭代 <br />排序：SortedSet <br />HashSet：采用哈希算法来实现Set接口 <br />唯一性保证：重复对象equals方法返回为true <br />重复对象hashCode方法返回相同的整数 <br />不同对象 哈希码 尽量保证不同（提高效率） <br /><br />SortedSet：对一个Set排序 <br />TreeSet：在元素添加的同时，进行排序。也要给出排序规则 <br />唯一性保证：根据排序规则，compareTo方法返回为0，就可以认定两个对象中有一个是重复对象。 <br /><br />Map：元素是键值对 key：唯一，不可重复 value：可重复 <br />遍历：先迭代遍历key的集合，再根据key得到value <br />HashMap:轻量级 线程不安全 允许key或者value是null <br />Hashtable：重量级 线程安全 不允许key或者value是null <br />Properties：Hashtable的子类，key和value都是String <br /><br />SortedMap：元素自动对key排序 <br />TreeMap： <br /><br />集合是指一个对象可以容纳了多个对象（不是引用），这个集合对象主要用来管理维护一系列相似的对象。 <br /><br />集合接口类层次 : <br />位于package java.util.*; <br />Collection <br />↑ <br />|ˉˉˉˉˉˉ| <br />Set List Map <br />↑ ↑ <br />| | <br />SortedSet SortedMap <br /><br />1) Set: 集合类中不允许有重复对象; <br />2) SortedSet: 和Set接口同，但元素按升序排列; <br />3) List: 元素加载和移出时按照顺序，可以保存重复对象。 <br />4) Map: (key-value对)存储了唯一关键字辨识和对应的值。 <br />5) SortedMap: 和Map类同，但对象按他们关键字的升序排列。 <br /><br />集合类层次 : <br />（注：JAVA1.5对JAVA1.4的最大改进就是增加了对范型的支持） <br /><br />Collection <br />↑ <br />|ˉˉˉˉˉˉ| <br />HashSet LinkedList Hashtable <br />(Set) Vector, ArrayList Hashmap <br />(List) (Map) <br />↑ ↑ <br />| | <br />TreeSet TreeMap <br />(SortedSet) (SortedMap) <br />Collection接口的方法： <br />add(Object o) <br />addAll(Collection c) <br />contains(Object o) <br />containsAll(Collection c) <br />remove(Object o) <br />removeAll(Collection c) <br />clear() <br />equals(Object o) <br />isEmpty() <br />iterator() <br />size() <br />toArray() <br />toArray(Object[] o) <br /><br /><br />五个最常用的集合类之间的区别和联系: <br />1．ArrayList: 元素单个，效率高，多用于查询 <br />2．Vector: 元素单个，线程安全，多用于查询 <br />3．LinkedList:元素单个，多用于插入和删除 <br />4．HashMap: 元素成对，元素可为空 <br />5．HashTable: 元素成对，线程安全，元素不可为空 <br /><br />ArrayList <br />底层是Object数组，所以ArrayList具有数组的查询速度快的优点以及增删速度慢的缺点。 <br />而在LinkedList的底层是一种双向循环链表。在此链表上每一个数据节点都由三部分组成：前指针（指向前面的节点的位置），数据，后指针（指向后面的节点的位置）。最后一个节点的后指针指向第一个节点的前指针，形成一个循环。 <br />双向循环链表的查询效率低但是增删效率高。 <br />ArrayList和LinkedList在用法上没有区别，但是在功能上还是有区别的。 <br /><br />LinkedList <br />经常用在增删操作较多而查询操作很少的情况下：队列和堆栈。 <br />队列：先进先出的数据结构。 <br />栈：后进先出的数据结构。 <br />注意：使用栈的时候一定不能提供方法让不是最后一个元素的元素获得出栈的机会。 <br /><br />Vector <br />（与ArrayList相似，区别是Vector是重量级的组件，使用使消耗的资源比较多。） <br />结论：在考虑并发的情况下用Vector（保证线程的安全）。 <br />在不考虑并发的情况下用ArrayList（不能保证线程的安全）。 <br /><br /><br />java.util.stack（stack即为堆栈）的父类为Vector。可是stack的父类是最不应该为Vector的。因为Vector的底层是数组，且Vector有get方法（意味着它可能访问到并不属于最后一个位置元素的其他元素，很不安全）。 <br />对于堆栈和队列只能用push类和get类。 <br />Stack类以后不要轻易使用。 <br />实现栈一定要用LinkedList。 <br />（在JAVA1.5中，collection有queue来实现队列。） <br /><br />Set-HashSet实现类： <br />遍历一个Set的方法只有一个：迭代器（interator）。 <br />HashSet中元素是无序的（这个无序指的是数据的添加顺序和后来的排列顺序不同），而且元素不可重复。 <br />在Object中除了有finalize()，toString()，equals()，还有hashCode()。 <br />HashSet底层用的也是数组。 <br />当向数组中利用add(Object o)添加对象的时候，系统先找对象的hashCode： <br />int hc=o.hashCode(); 返回的hashCode为整数值。 <br />Int I=hc%n;（n为数组的长度），取得余数后，利用余数向数组中相应的位置添加数据，以n为6为例，如果I=0则放在数组a[0]位置，如果I=1,则放在数组a[1]位置。如果equals()返回的值为true，则说明数据重复。如果equals()返回的值为false，则再找其他的位置进行比较。这样的机制就导致两个相同的对象有可能重复地添加到数组中，因为他们的hashCode不同。 <br />如果我们能够使两个相同的对象具有相同hashcode，才能在equals()返回为真。 <br />在实例中，定义student对象时覆盖它的hashcode。 <br />因为String类是自动覆盖的，所以当比较String类的对象的时候，就不会出现有两个相同的string对象的情况。 <br />现在，在大部分的JDK中，都已经要求覆盖了hashCode。 <br />结论：如将自定义类用hashSet来添加对象，一定要覆盖hashcode()和equals()，覆盖的原则是保证当两个对象hashcode返回相同的整数，而且equals()返回值为True。 <br />如果偷懒，没有设定equals()，就会造成返回hashCode虽然结果相同，但在程序执行的过程中会多次地调用equals()，从而影响程序执行的效率。 <br /><br />我们要保证相同对象的返回的hashCode一定相同，也要保证不相同的对象的hashCode尽可能不同（因为数组的边界性，hashCode还是可能相同的）。 <br /><br />例子： <br />public int hashCode(){ <br />return name.hashcode()+age; <br />} <br />这个例子保证了相同姓名和年龄的记录返回的hashCode是相同的。 <br /><br />使用hashSet的优点： <br />hashSet的底层是数组，其查询效率非常高。而且在增加和删除的时候由于运用的hashCode的比较开确定添加元素的位置，所以不存在元素的偏移，所以效率也非常高。因为hashSet查询和删除和增加元素的效率都非常高。 <br />但是hashSet增删的高效率是通过花费大量的空间换来的：因为空间越大，取余数相同的情况就越小。HashSet这种算法会建立许多无用的空间。 <br />使用hashSet类时要注意，如果发生冲突，就会出现遍历整个数组的情况，这样就使得效率非常的低。 <br /><br />1.1.4. 比较 <br />Collections类（工具类―――全是static 方法） <br />Public static int binarySearch(List list,Object key) <br />Public static void Sort(List list,Comparator com) <br />Public static void sort(List list) <br />方法一： <br />Comparator接口 <br />Int compare(Object a,Object b) <br />Boolean equals(Object o) <br />例子： <br />import java.util.*; <br />public class Test { <br />public static void main(String[] arg) { <br />ArrayList al = new ArrayList(); <br />Person p1 = new Person("dudi"); <br />Person p2 = new Person("cony"); <br />Person p3 = new Person("aihao"); <br />al.add(p1); <br />al.add(p2); <br />al.add(p3); <br />Collections.sort(al,p1); <br />for(Iterator it = al.iterator();it.hasNext();){ <br />Person p = (Person)it.next(); <br />System.out.println(p.name); <br />} <br />} <br />} <br />class Person implements java.util.Comparator <br />{ <br />public String name; <br />public Person(String name){ <br />this.name = name; <br />} <br />public int compare(Object a,Object b){ <br />if(a instanceof Person&amp;&amp;b instanceof Person){ <br />Person pa = (Person)a; <br />Person pb = (Person)b; <br />return pa.name.compareTo(pb.name); <br />} <br />return 0; <br />} <br />public boolean equals(Object a){return true;} <br />} <br />方法二 <br />Java.lang.Comparable <br />Public int compareTo(Object o) <br />Class Person implements java.lang.Comparable{ <br />Public int compareTo(Object o){ <br />Comparable c1=(Comparable)this; <br />Comparable c2=(Comparable)o; <br />Return c1.name.compareTo(c2.name ); <br />} <br />} <br />………………………………. <br />}<img src ="http://www.blogjava.net/balajinima/aggbug/200872.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/balajinima/" target="_blank">李云泽</a> 2008-05-16 12:57 <a href="http://www.blogjava.net/balajinima/articles/200872.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java程序的内存分配</title><link>http://www.blogjava.net/balajinima/articles/182203.html</link><dc:creator>李云泽</dc:creator><author>李云泽</author><pubDate>Tue, 26 Feb 2008 05:38:00 GMT</pubDate><guid>http://www.blogjava.net/balajinima/articles/182203.html</guid><wfw:comment>http://www.blogjava.net/balajinima/comments/182203.html</wfw:comment><comments>http://www.blogjava.net/balajinima/articles/182203.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/balajinima/comments/commentRss/182203.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/balajinima/services/trackbacks/182203.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: （最近感觉自己对java好无知啊！以下是转自网络上的文章，以供自己学习...........）								JAVA				文件编译执行与虚拟机(JVM)介绍																												Java				虚拟机(JVM)是可运行Java代码的假想计算机。只要根据JVM规格描述将解释器移植到特定的计算机上，就能保证经过编译的...&nbsp;&nbsp;<a href='http://www.blogjava.net/balajinima/articles/182203.html'>阅读全文</a><img src ="http://www.blogjava.net/balajinima/aggbug/182203.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/balajinima/" target="_blank">李云泽</a> 2008-02-26 13:38 <a href="http://www.blogjava.net/balajinima/articles/182203.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>String和StringBuffer之概览</title><link>http://www.blogjava.net/balajinima/articles/166913.html</link><dc:creator>李云泽</dc:creator><author>李云泽</author><pubDate>Tue, 11 Dec 2007 05:32:00 GMT</pubDate><guid>http://www.blogjava.net/balajinima/articles/166913.html</guid><wfw:comment>http://www.blogjava.net/balajinima/comments/166913.html</wfw:comment><comments>http://www.blogjava.net/balajinima/articles/166913.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/balajinima/comments/commentRss/166913.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/balajinima/services/trackbacks/166913.html</trackback:ping><description><![CDATA[String和StringBuffer之概览<br />　　非可变对象一旦创建之后就不能再被改变，可变对象则可以在创建之后被改变。String对象是非可变对象，StringBuffer对象则是可变对象。为获得更佳的性能你需要根据实际情况小心谨慎地选择到底使用这两者中的某一个。下面的话题会作详细的阐述。（注意：这个章节假设读者已经具备Java的String和StringBuffer的相关基础知识。）<br /> <br />创建字符串的较佳途径<br />你可以按照以下方式创建字符串对象：<br />1. String s1 = "hello"; <br />    String s2 = "hello"; <br />2. String s3 = new String("hello");<br />    String s4 = new String("hello");<br /> <br />上面哪种方式会带来更好的性能呢？下面的代码片断用来测量二者之间的区别。<br /><br />StringTest1.java<br />package com.performance.string;<br />/** This class shows the time taken for creation of<br /> *  String literals and String objects.<br /> */<br />public class StringTest1 {<br />public static void main(String[] args){<br />    // create String literals<br />    long startTime = System.currentTimeMillis();<br />    for(int i=0;i&lt;50000;i++){<br />    String s1 = "hello";<br />    String s2 = "hello";<br />    }<br />    long endTime = System.currentTimeMillis();<br />    System.out.println("Time taken for creation of String literals : "<br />                  + (endTime - startTime) + " milli seconds" );<br />    // create String objects using 'new' keyword       <br />    long startTime1 = System.currentTimeMillis();<br />    for(int i=0;i&lt;50000;i++){<br />    String s3 = new String("hello");<br />    String s4 = new String("hello");<br />    }<br />    long endTime1 = System.currentTimeMillis();<br />    System.out.println("Time taken for creation of String objects : "<br />                  + (endTime1 - startTime1)+" milli seconds");<br />    }<br />}<br />这段代码的输出：<br />Time taken for creation of String literals : 0 milli seconds<br />Time taken for creation of String objects : 170 milli seconds<br /> <br />JVM是怎样处理字符串的呢？<br />　　Java虚拟机会维护一个内部的滞留字符串对象的列表（唯一字符串的池）来避免在堆内存中产生重复的String对象。当JVM从class文件里加载字符串字面量并执行的时候，它会先检查一下当前的字符串是否已经存在于滞留字符串列表，如果已经存在，那就不会再创建一个新的String对象而是将引用指向已经存在的String对象，JVM会在内部为字符串字面量作这种检查，但并不会为通过new关键字创建的String对象作这种检查。当然你可以明确地使用String.intern()方法强制JVM为通过 new关键字创建的String对象作这样的检查。这样可以强制JVM检查内部列表而使用已有的String对象。<br />　　所以结论是，JVM会内在地为字符串字面量维护一些唯一的String对象，程序员不需要为字符串字面量而发愁，但是可能会被一些通过 new关键字创建的String对象而困扰，不过他们可以使用intern()方法来避免在堆内存上创建重复的String对象来改善Java的运行性能。下一小节会向大家展示更多的信息。<br /> <br />下图展示了未使用intern()方法来创建字符串的情况。<br /> <br />string_creating_without_intern() method<br />　　你可以自己使用==操作符和String.equals()方法来编码测试上面提到的区别。==操作符会返回true如果一些引用指向一个相同的对象但不会判断String对象的内容是否相同；String.equals()方法会返回true如果被操作的String对象的内容相同。对于上面的代码会有s1==s2，因为s1和s2两个引用指向同一个对象，对于上面的代码，s3.equals(s4)会返回true因为两个对象的内容都一样为”hello”。你可以从上图看出这种机制。在这里有三个独立的包含了相同的内容（”hello”）的对象，实际上我们不需要这么三个独立的对象—— 因为要运行它们的话既浪费时间又浪费内存。<br /> <br />　　那么怎样才能确保String对象不会重复呢？下一个话题会涵盖对于内建String机制的兴趣。<br /> <br />滞留字符串的优化作用<br />　　同一个字符串对象被重复地创建是不必要的，String.intern ()方法可以避免这种情况。下图说明了String.intern()方法是如何工作的，String.intern()方法检查字符串对象的存在性，如果需要的字符串对象已经存在，那么它会将引用指向已经存在的字符串对象而不是重新创建一个。下图描绘了使用了intern()方法的字符串字面量和字符串对象的创建情况。<br /> <br />string_creating_with_intern() method<br />下面的例程帮助大家了解String.intern()方法的重要性。<br />StringTest2.java<br /> <br />package com.performance.string;<br />// This class shows the use of intern() method to improve performance<br />public class StringTest2 {<br />public static void main(String[] args){<br />    // create String references like s1,s2,s3...so on..<br />    String variables[] = new String[50000];<br />    for( int i=0;i&lt;variables.length;i++){<br />        variables[i] = "s"+i;<br />    }<br />    // create String literals<br />    long startTime0 = System.currentTimeMillis();<br />    for(int i=0;i&lt;variables.length;i++){<br />        variables[i] = "hello";<br />    }<br />    long endTime0 = System.currentTimeMillis();<br />    System.out.println("Time taken for creation of String literals : "<br />                         + (endTime0 - startTime0) + " milli seconds" );<br />    // create String objects using 'new' keyword       <br />    long startTime1 = System.currentTimeMillis();<br />    for(int i=0;i&lt;variables.length;i++){<br />        variables[i] = new String("hello");<br />    }<br />    long endTime1 = System.currentTimeMillis();<br />    System.out.println("Time taken for creation of String objects with 'new' key word : "<br />                        + (endTime1 - startTime1)+" milli seconds");<br />    // intern String objects with intern() method   <br />    long startTime2 = System.currentTimeMillis();<br />    for(int i=0;i&lt;variables.length;i++){<br />        variables[i] = new String("hello");<br />        variables[i] = variables[i].intern();<br />    }<br />    long endTime2 = System.currentTimeMillis();<br />    System.out.println("Time taken for creation of String objects with intern(): "<br />                        + (endTime2 - startTime2)+" milli seconds");<br />    }<br />}<br />这是上面那段代码的输出结果：<br />Time taken for creation of String literals : 0 milli seconds<br />Time taken for creation of String objects with 'new' key word : 160 milli seconds<br />Time taken for creation of String objects with intern(): 60 milli seconds<br /> <br />连接字符串时候的优化技巧<br />　　你可以使用+操作符或者String.concat()或者StringBuffer.append()等办法来连接多个字符串，那一种办法具有最佳的性能呢？<br />　　如何作出选择取决于两种情景，第一种情景是需要连接的字符串是在编译期决定的还是在运行期决定的，第二种情景是你使用的是 StringBuffer还是String。通常程序员会认为StringBuffer.append()方法会优于+操作符或 String.concat()方法，但是在一些特定的情况下这个假想是不成立的。<br /> <br />1) 第一种情景：编译期决定相对于运行期决定<br />请看下面的StringTest3.java代码和输出结果。<br /><br />package com.performance.string;<br />/** This class shows the time taken by string concatenation at compile time and run time.*/<br />public class StringTest3 {<br />  public static void main(String[] args){<br />    //Test the String Concatination<br />    long startTime = System.currentTimeMillis();<br />    for(int i=0;i&lt;5000;i++){<br />    String result = "This is"+ "testing the"+ "difference"+ "between"+<br />            "String"+ "and"+ "StringBuffer";<br />    }<br />    long endTime = System.currentTimeMillis();<br />    System.out.println("Time taken for string concatenation using + operator : "<br />         + (endTime - startTime)+ " milli seconds");<br />    //Test the StringBuffer Concatination<br />    long startTime1 = System.currentTimeMillis();<br />    for(int i=0;i&lt;5000;i++){<br />    StringBuffer result = new StringBuffer();<br />         result.append("This is");<br />        result.append("testing the");<br />        result.append("difference");<br />        result.append("between");<br />       result.append("String");<br />       result.append("and");<br />       result.append("StringBuffer");<br />     }<br />    long endTime1 = System.currentTimeMillis();<br />    System.out.println("Time taken for String concatenation using StringBuffer : "<br />           + (endTime1 - startTime1)+ " milli seconds");<br />  }<br />}<br />这是上面的代码的输出结果：<br />Time taken for String concatenation using + operator : 0 milli seconds<br />Time taken for String concatenation using StringBuffer : 50 milli seconds<br />很有趣地，+操作符居然比StringBuffer.append()方法要快，为什么呢？<br /> <br />　　这里编译器的优化起了关键作用，编译器像下面举例的那样简单地在编译期连接多个字符串。它使用编译期决定取代运行期决定，在你使用new关键字来创建String对象的时候也是如此。<br /> <br />编译前：<br />String result = "This is"+"testing the"+"difference"+"between"+"String"+"and"+"StringBuffer";<br />编译后：<br />String result = "This is testing the difference between String and StringBuffer";<br /><br />这里String对象在编译期就决定了而StringBuffer对象是在运行期决定的。运行期决定需要额外的开销当字符串的值无法预先知道的时候，编译期决定作用于字符串的值可以预先知道的时候，下面是一个例子。<br /> <br />编译前：<br />public String getString(String str1,String str2) {<br />    return str1+str2;<br />}<br />编译后：<br />return new StringBuffer().append(str1).append(str2).toString();<br />运行期决定需要更多的时间来运行。<br /> <br />2) 第二种情景：使用StringBuffer取代String<br />看看下面的代码你会发现与情景一相反的结果——连接多个字符串的时候StringBuffer要比String快。<br />StringTest4.java<br /> <br />package com.performance.string;<br />/** This class shows the time taken by string concatenation<br />using + operator and StringBuffer  */<br />public class StringTest4 {<br /> public static void main(String[] args){<br />    //Test the String Concatenation using + operator<br />    long startTime = System.currentTimeMillis();<br />    String result = "hello";<br />    for(int i=0;i&lt;1500;i++){<br />        result += "hello";<br />    }<br />    long endTime = System.currentTimeMillis();<br />    System.out.println("Time taken for string concatenation using + operator : "<br />                  + (endTime - startTime)+ " milli seconds");<br />    //Test the String Concatenation using StringBuffer<br />    long startTime1 = System.currentTimeMillis();<br />    StringBuffer result1 = new StringBuffer("hello");<br />    for(int i=0;i&lt;1500;i++){<br />        result1.append("hello");<br />    }<br />    long endTime1 = System.currentTimeMillis();<br />    System.out.println("Time taken for string concatenation using StringBuffer :  "<br />                  + (endTime1 - startTime1)+ " milli seconds");<br />    }<br />}<br />这是上面的代码的输出结果：<br />Time taken for string concatenation using + operator : 280 milli seconds<br />Time taken for String concatenation using StringBuffer : 0 milli seconds<br />看得出StringBuffer.append()方法要比+操作符要快得多，为什么呢？<br /><br />　　原因是两者都是在运行期决定字符串对象，但是+操作符使用不同于StringBuffer.append()的规则通过String和StringBuffer来完成字符串连接操作。（译注：什么样的规则呢？）<br /> <br />借助StringBuffer的初始化过程的优化技巧<br />　　你可以通过StringBuffer的构造函数来设定它的初始化容量，这样可以明显地提升性能。这里提到的构造函数是StringBuffer(int length)，length参数表示当前的StringBuffer能保持的字符数量。你也可以使用ensureCapacity(int minimumcapacity)方法在StringBuffer对象创建之后设置它的容量。首先我们看看StringBuffer的缺省行为，然后再找出一条更好的提升性能的途径。<br /> <br />StringBuffer的缺省行为：<br />　　StringBuffer在内部维护一个字符数组，当你使用缺省的构造函数来创建StringBuffer对象的时候，因为没有设置初始化字符长度，StringBuffer的容量被初始化为16个字符，也就是说缺省容量就是16个字符。当StringBuffer达到最大容量的时候，它会将自身容量增加到当前的2倍再加2，也就是（2*旧值+2）。<br />　　如果你使用缺省值，初始化之后接着往里面追加字符，在你追加到第16个字符的时候它会将容量增加到34（2*16+2），当追加到34个字符的时候就会将容量增加到70（2*34+2）。无论何事只要StringBuffer到达它的最大容量它就不得不创建一个新的字符数组然后重新将旧字符和新字符都拷贝一遍——这也太昂贵了点。所以总是给StringBuffer设置一个合理的初始化容量值是错不了的，这样会带来立竿见影的性能增益。<br />　　我利用两个StringBuffer重新测试了上面的StringTest4.java代码，一个未使用初始化容量值而另一个使用了。这次我追加了50000个’hello’对象没有使用+操作符。区别是我使用StringBuffer(250000)的构造函数来初始化第二个 StringBuffer了。<br /> <br />输出结果如下：<br />Time taken for String concatenation using StringBuffer with out setting size: 280 milli seconds<br />Time taken for String concatenation using StringBuffer with setting size: 0 milli seconds<br />StringBuffer初始化过程的调整的作用由此可见一斑。所以，使用一个合适的容量值来初始化StringBuffer永远都是一个最佳的建议。<br /> <br />关键点<br />1. 无论何时只要可能的话使用字符串字面量来常见字符串而不是使用new关键字来创建字符串。<br />2. 无论何时当你要使用new关键字来创建很多内容重复的字符串的话，请使用String.intern()方法。<br />3. +操作符会为字符串连接提供最佳的性能——当字符串是在编译期决定的时候。<br />4. 如果字符串在运行期决定，使用一个合适的初期容量值初始化的StringBuffer会为字符串连接提供最佳的性能。<img src ="http://www.blogjava.net/balajinima/aggbug/166913.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/balajinima/" target="_blank">李云泽</a> 2007-12-11 13:32 <a href="http://www.blogjava.net/balajinima/articles/166913.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>详细解析抽象类和接口的区别</title><link>http://www.blogjava.net/balajinima/articles/159417.html</link><dc:creator>李云泽</dc:creator><author>李云泽</author><pubDate>Fri, 09 Nov 2007 09:39:00 GMT</pubDate><guid>http://www.blogjava.net/balajinima/articles/159417.html</guid><wfw:comment>http://www.blogjava.net/balajinima/comments/159417.html</wfw:comment><comments>http://www.blogjava.net/balajinima/articles/159417.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/balajinima/comments/commentRss/159417.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/balajinima/services/trackbacks/159417.html</trackback:ping><description><![CDATA[
		<div style="MARGIN-BOTTOM: 10px">
				<h4 class="mode_title" id="veryTitle"> </h4>
		</div>
		<div id="quoteinfo" style="MARGIN-BOTTOM: 10px">
		</div>
		<div id="voteAnchor">
		</div>
		<div style="POSITION: relative">
				<div class="lh3" id="veryContent" style="OVERFLOW: hidden; WIDTH: 100%">
						<table class="contentTable" cellspacing="0" cellpadding="0">
								<tbody>
										<tr>
												<td style="FONT-SIZE: 12px">
														<font size="4"> <font style="LINE-HEIGHT: 1.3em">abstract class和interface是语言中对于抽象类定义进行支持的两种机制，正是由于这两种机制的存在，才赋予了Java强大的面向对象能力。abstract class和interface之间在对于抽象类定义的支持方面具有很大的相似性，甚至可以相互替换，因此很多开发者在进行抽象类定义时对于abstract class和interface的选择显得比较随意。其实，两者之间还是有很大的区别的，对于它们的选择甚至反映出对于问题领域本质的理解、对于设计意图的理解是否正确、合理。本文将对它们之间的区别进行一番剖析，试图给开发者提供一个在二者之间进行选择的依据。   </font><wbr><br /><font style="LINE-HEIGHT: 1.3em"></font><wbr><br /><font style="LINE-HEIGHT: 1.3em">理解抽象类   </font><wbr><br /><font style="LINE-HEIGHT: 1.3em"></font><wbr><br /><font style="LINE-HEIGHT: 1.3em">abstract class和interface在Java语言中都是用来进行抽象类（本文中的抽象类并非从abstract class翻译而来，它表示的是一个抽象体，而abstract class为Java语言中用于定义抽象类的一种方法，请读者注意区分）定义的，那么什么是抽象类，使用抽象类能为我们带来什么好处呢？   </font><wbr><br /><font style="LINE-HEIGHT: 1.3em"></font><wbr><br /><font style="LINE-HEIGHT: 1.3em">在面向对象的概念中，我们知道所有的对象都是通过类来描绘的，但是反过来却不是这样。并不是所有的类都是用来描绘对象的，如果一个类中没有包含足够的信息来描绘一个具体的对象，这样的类就是抽象类。抽象类往往用来表征我们在对问题领域进行分析、设计中得出的抽象概念，是对一系列看上去不同，但是本质上相同的具体概念的抽象。比如：如果我们进行一个图形编辑软件的开发，就会发现问题领域存在着圆、三角形这样一些具体概念，它们是不同的，但是它们又都属于形状这样一个概念，形状这个概念在问题领域是不存在的，它就是一个抽象概念。正是因为抽象的概念在问题领域没有对应的具体概念，所以用以表征抽象概念的抽象类是不能够实例化的。   </font><wbr><br /><font style="LINE-HEIGHT: 1.3em"></font><wbr><br /><font style="LINE-HEIGHT: 1.3em">在面向对象领域，抽象类主要用来进行类型隐藏。我们可以构造出一个固定的一组行为的抽象描述，但是这组行为却能够有任意个可能的具体实现方式。这个抽象描述就是抽象类，而这一组任意个可能的具体实现则表现为所有可能的派生类。模块可以操作一个抽象体。由于模块依赖于一个固定的抽象体，因此它可以是不允许修改的；同时，通过从这个抽象体派生，也可扩展此模块的行为功能。熟悉OCP的读者一定知道，为了能够实现面向对象设计的一个最核心的原则OCP(Open-Closed Principle)，抽象类是其中的关键所在。   </font><wbr><br /><font style="LINE-HEIGHT: 1.3em"></font><wbr><br /><font style="LINE-HEIGHT: 1.3em">从语法定义层面看abstract class和interface   </font><wbr><br /><font style="LINE-HEIGHT: 1.3em"></font><wbr><br /><font style="LINE-HEIGHT: 1.3em">在语法层面，Java语言对于abstract class和interface给出了不同的定义方式，下面以定义一个名为Demo的抽象类为例来说明这种不同。   </font><wbr><br /><font style="LINE-HEIGHT: 1.3em"></font><wbr><br /><font style="LINE-HEIGHT: 1.3em">使用abstract class的方式定义Demo抽象类的方式如下：   </font><wbr><br /><font style="LINE-HEIGHT: 1.3em"></font><wbr><br /><font style="LINE-HEIGHT: 1.3em">abstract class Demo ｛   </font><wbr><br /><font style="LINE-HEIGHT: 1.3em"> abstract void method1();   </font><wbr><br /><font style="LINE-HEIGHT: 1.3em"> abstract void method2();   </font><wbr><br /><font style="LINE-HEIGHT: 1.3em"> …   </font><wbr><br /><font style="LINE-HEIGHT: 1.3em">｝   </font><wbr><br /><font style="LINE-HEIGHT: 1.3em"></font><wbr><br /><font style="LINE-HEIGHT: 1.3em">使用interface的方式定义Demo抽象类的方式如下：   </font><wbr><br /><font style="LINE-HEIGHT: 1.3em"></font><wbr><br /><font style="LINE-HEIGHT: 1.3em">interface Demo {   </font><wbr><br /><font style="LINE-HEIGHT: 1.3em"> void method1();   </font><wbr><br /><font style="LINE-HEIGHT: 1.3em"> void method2();   </font><wbr><br /><font style="LINE-HEIGHT: 1.3em"> …   </font><wbr><br /><font style="LINE-HEIGHT: 1.3em">}   </font><wbr><br /><font style="LINE-HEIGHT: 1.3em"></font><wbr><br /><font style="LINE-HEIGHT: 1.3em">在abstract class方式中，Demo可以有自己的数据成员，也可以有非abstarct的成员方法，而在interface方式的实现中，Demo只能够有静态的不能被修改的数据成员（也就是必须是static final的，不过在interface中一般不定义数据成员），所有的成员方法都是abstract的。从某种意义上说，interface是一种特殊形式的abstract class。   </font><wbr><br /><font style="LINE-HEIGHT: 1.3em"></font><wbr><br /><font style="LINE-HEIGHT: 1.3em">      从编程的角度来看，abstract class和interface都可以用来实现"design by contract"的。但是在具体的使用上面还是有一些区别的。   </font><wbr><br /><font style="LINE-HEIGHT: 1.3em"></font><wbr><br /><font style="LINE-HEIGHT: 1.3em">首先，abstract class在Java语言中表示的是一种继承关系，一个类只能使用一次继承关系。但是，一个类却可以实现多个interface。也许，这是Java语言的设计者在考虑Java对于多重继承的支持方面的一种折中考虑吧。   </font><wbr><br /><font style="LINE-HEIGHT: 1.3em"></font><wbr><br /><font style="LINE-HEIGHT: 1.3em">其次，在abstract class的定义中，我们可以赋予方法的默认行为。但是在interface的定义中，方法却不能拥有默认行为，为了绕过这个限制，必须使用委托，但是这会 增加一些复杂性，有时会造成很大的麻烦。   </font><wbr><br /><font style="LINE-HEIGHT: 1.3em"></font><wbr><br /><font style="LINE-HEIGHT: 1.3em">在抽象类中不能定义默认行为还存在另一个比较严重的问题，那就是可能会造成维护上的麻烦。因为如果后来想修改类的界面（一般通过abstract class或者interface来表示）以适应新的情况（比如，添加新的方法或者给已用的方法中添加新的参数）时，就会非常的麻烦，可能要花费很多的时间（对于派生类很多的情况，尤为如此）。但是如果界面是通过abstract class来实现的，那么可能就只需要修改定义在abstract class中的默认行为就可以了。   </font><wbr><br /><font style="LINE-HEIGHT: 1.3em"></font><wbr><br /><font style="LINE-HEIGHT: 1.3em">同样，如果不能在抽象类中定义默认行为，就会导致同样的方法实现出现在该抽象类的每一个派生类中，违反了"one rule，one place"原则，造成代码重复，同样不利于以后的维护。因此，在abstract class和interface间进行选择时要非常的小心。</font></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></font>
												</td>
										</tr>
								</tbody>
						</table>
				</div>
		</div>
<img src ="http://www.blogjava.net/balajinima/aggbug/159417.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/balajinima/" target="_blank">李云泽</a> 2007-11-09 17:39 <a href="http://www.blogjava.net/balajinima/articles/159417.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java 反射</title><link>http://www.blogjava.net/balajinima/articles/149623.html</link><dc:creator>李云泽</dc:creator><author>李云泽</author><pubDate>Sat, 29 Sep 2007 09:14:00 GMT</pubDate><guid>http://www.blogjava.net/balajinima/articles/149623.html</guid><wfw:comment>http://www.blogjava.net/balajinima/comments/149623.html</wfw:comment><comments>http://www.blogjava.net/balajinima/articles/149623.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/balajinima/comments/commentRss/149623.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/balajinima/services/trackbacks/149623.html</trackback:ping><description><![CDATA[Java提供了一套机制来动态执行方法和构造方法，以及数组操作等，这套机制就叫——反射。反射机制是如今很多流行框架的实现基础，其中包括Spring、Hibernate等。原理性的问题不是本文的重点，接下来让我们在实例中学习这套精彩的机制。<br /><br />1. 得到某个对象的属性<br /><br /><div style="BORDER-RIGHT: rgb(204,204,204) 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: rgb(204,204,204) 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: rgb(204,204,204) 1px solid; WIDTH: 98%; PADDING-TOP: 4px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BACKGROUND-COLOR: rgb(238,238,238)"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="COLOR: rgb(0,128,128)">1</span> <span style="COLOR: rgb(0,0,255)">public</span><span style="COLOR: rgb(0,0,0)"> Object getProperty(Object owner, String fieldName) </span><span style="COLOR: rgb(0,0,255)">throws</span><span style="COLOR: rgb(0,0,0)"> Exception {<br /></span><span style="COLOR: rgb(0,128,128)">2</span> <span style="COLOR: rgb(0,0,0)">    Class ownerClass </span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)"> owner.getClass();<br /></span><span style="COLOR: rgb(0,128,128)">3</span> <span style="COLOR: rgb(0,0,0)"><br /></span><span style="COLOR: rgb(0,128,128)">4</span> <span style="COLOR: rgb(0,0,0)">    Field field </span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)"> ownerClass.getField(fieldName);<br /></span><span style="COLOR: rgb(0,128,128)">5</span> <span style="COLOR: rgb(0,0,0)"><br /></span><span style="COLOR: rgb(0,128,128)">6</span> <span style="COLOR: rgb(0,0,0)">    Object property </span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)"> field.get(owner);<br /></span><span style="COLOR: rgb(0,128,128)">7</span> <span style="COLOR: rgb(0,0,0)"><br /></span><span style="COLOR: rgb(0,128,128)">8</span> <span style="COLOR: rgb(0,0,0)">    </span><span style="COLOR: rgb(0,0,255)">return</span><span style="COLOR: rgb(0,0,0)"> property;<br /></span><span style="COLOR: rgb(0,128,128)">9</span> <span style="COLOR: rgb(0,0,0)">}</span></div><br />Class ownerClass = owner.getClass()：得到该对象的Class。<br /><br />Field field = ownerClass.getField(fieldName)：通过Class得到类声明的属性。<br /><br />Object property = field.get(owner)：通过对象得到该属性的实例，如果这个属性是非公有的，这里会报IllegalAccessException。<br /><br /><br /><br />2. 得到某个类的静态属性<br /><br /><div style="BORDER-RIGHT: rgb(204,204,204) 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: rgb(204,204,204) 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: rgb(204,204,204) 1px solid; WIDTH: 98%; PADDING-TOP: 4px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BACKGROUND-COLOR: rgb(238,238,238)"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="COLOR: rgb(0,128,128)"> 1</span> <span style="COLOR: rgb(0,0,255)">public</span><span style="COLOR: rgb(0,0,0)"> Object getStaticProperty(String className, String fieldName)<br /></span><span style="COLOR: rgb(0,128,128)"> 2</span> <span style="COLOR: rgb(0,0,0)">            </span><span style="COLOR: rgb(0,0,255)">throws</span><span style="COLOR: rgb(0,0,0)"> Exception {<br /></span><span style="COLOR: rgb(0,128,128)"> 3</span> <span style="COLOR: rgb(0,0,0)">    Class ownerClass </span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)"> Class.forName(className);<br /></span><span style="COLOR: rgb(0,128,128)"> 4</span> <span style="COLOR: rgb(0,0,0)"><br /></span><span style="COLOR: rgb(0,128,128)"> 5</span> <span style="COLOR: rgb(0,0,0)">    Field field </span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)"> ownerClass.getField(fieldName);<br /></span><span style="COLOR: rgb(0,128,128)"> 6</span> <span style="COLOR: rgb(0,0,0)"><br /></span><span style="COLOR: rgb(0,128,128)"> 7</span> <span style="COLOR: rgb(0,0,0)">    Object property </span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)"> field.get(ownerClass);<br /></span><span style="COLOR: rgb(0,128,128)"> 8</span> <span style="COLOR: rgb(0,0,0)"><br /></span><span style="COLOR: rgb(0,128,128)"> 9</span> <span style="COLOR: rgb(0,0,0)">    </span><span style="COLOR: rgb(0,0,255)">return</span><span style="COLOR: rgb(0,0,0)"> property;<br /></span><span style="COLOR: rgb(0,128,128)">10</span> <span style="COLOR: rgb(0,0,0)">}</span></div><br /><br />Class ownerClass = Class.forName(className) ：首先得到这个类的Class。<br /><br />Field field = ownerClass.getField(fieldName)：和上面一样，通过Class得到类声明的属性。<br /><br />Object property = field.get(ownerClass) ：这里和上面有些不同，因为该属性是静态的，所以直接从类的Class里取。<br /><br /><br />3. 执行某对象的方法<br /><br /><div style="BORDER-RIGHT: rgb(204,204,204) 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: rgb(204,204,204) 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: rgb(204,204,204) 1px solid; WIDTH: 98%; PADDING-TOP: 4px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BACKGROUND-COLOR: rgb(238,238,238)"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="COLOR: rgb(0,128,128)"> 1</span> <span style="COLOR: rgb(0,0,255)">public</span><span style="COLOR: rgb(0,0,0)"> Object invokeMethod(Object owner, String methodName, Object[] args) </span><span style="COLOR: rgb(0,0,255)">throws</span><span style="COLOR: rgb(0,0,0)"> Exception {<br /></span><span style="COLOR: rgb(0,128,128)"> 2</span> <span style="COLOR: rgb(0,0,0)"><br /></span><span style="COLOR: rgb(0,128,128)"> 3</span> <span style="COLOR: rgb(0,0,0)">    Class ownerClass </span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)"> owner.getClass();<br /></span><span style="COLOR: rgb(0,128,128)"> 4</span> <span style="COLOR: rgb(0,0,0)"><br /></span><span style="COLOR: rgb(0,128,128)"> 5</span> <span style="COLOR: rgb(0,0,0)">    Class[] argsClass </span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)"> </span><span style="COLOR: rgb(0,0,255)">new</span><span style="COLOR: rgb(0,0,0)"> Class[args.length];<br /></span><span style="COLOR: rgb(0,128,128)"> 6</span> <span style="COLOR: rgb(0,0,0)"><br /></span><span style="COLOR: rgb(0,128,128)"> 7</span> <span style="COLOR: rgb(0,0,0)">    </span><span style="COLOR: rgb(0,0,255)">for</span><span style="COLOR: rgb(0,0,0)"> (</span><span style="COLOR: rgb(0,0,255)">int</span><span style="COLOR: rgb(0,0,0)"> i </span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)"> </span><span style="COLOR: rgb(0,0,0)">0</span><span style="COLOR: rgb(0,0,0)">, j </span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)"> args.length; i </span><span style="COLOR: rgb(0,0,0)">&lt;</span><span style="COLOR: rgb(0,0,0)"> j; i</span><span style="COLOR: rgb(0,0,0)">++</span><span style="COLOR: rgb(0,0,0)">) {<br /></span><span style="COLOR: rgb(0,128,128)"> 8</span> <span style="COLOR: rgb(0,0,0)">        argsClass[i] </span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)"> args[i].getClass();<br /></span><span style="COLOR: rgb(0,128,128)"> 9</span> <span style="COLOR: rgb(0,0,0)">    }<br /></span><span style="COLOR: rgb(0,128,128)">10</span> <span style="COLOR: rgb(0,0,0)"><br /></span><span style="COLOR: rgb(0,128,128)">11</span> <span style="COLOR: rgb(0,0,0)">    Method method </span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)"> ownerClass.getMethod(methodName, argsClass);<br /></span><span style="COLOR: rgb(0,128,128)">12</span> <span style="COLOR: rgb(0,0,0)"><br /></span><span style="COLOR: rgb(0,128,128)">13</span> <span style="COLOR: rgb(0,0,0)">    </span><span style="COLOR: rgb(0,0,255)">return</span><span style="COLOR: rgb(0,0,0)"> method.invoke(owner, args);<br /></span><span style="COLOR: rgb(0,128,128)">14</span> <span style="COLOR: rgb(0,0,0)">}</span></div><br />Class owner_class = owner.getClass() ：首先还是必须得到这个对象的Class。<br /><br />5～9行：配置参数的Class数组，作为寻找Method的条件。<br /><br />Method method = ownerClass.getMethod(methodName, argsClass)：通过Method名和参数的Class数组得到要执行的Method。<br /><br />method.invoke(owner, args)：执行该Method，invoke方法的参数是执行这个方法的对象，和参数数组。返回值是Object，也既是该方法的返回值。<br /><br /><br />4. 执行某个类的静态方法<br /><br /><div style="BORDER-RIGHT: rgb(204,204,204) 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: rgb(204,204,204) 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: rgb(204,204,204) 1px solid; WIDTH: 98%; PADDING-TOP: 4px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BACKGROUND-COLOR: rgb(238,238,238)"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="COLOR: rgb(0,128,128)"> 1</span> <span style="COLOR: rgb(0,0,255)">public</span><span style="COLOR: rgb(0,0,0)"> Object invokeStaticMethod(String className, String methodName,<br /></span><span style="COLOR: rgb(0,128,128)"> 2</span> <span style="COLOR: rgb(0,0,0)">            Object[] args) </span><span style="COLOR: rgb(0,0,255)">throws</span><span style="COLOR: rgb(0,0,0)"> Exception {<br /></span><span style="COLOR: rgb(0,128,128)"> 3</span> <span style="COLOR: rgb(0,0,0)">    Class ownerClass </span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)"> Class.forName(className);<br /></span><span style="COLOR: rgb(0,128,128)"> 4</span> <span style="COLOR: rgb(0,0,0)"><br /></span><span style="COLOR: rgb(0,128,128)"> 5</span> <span style="COLOR: rgb(0,0,0)">    Class[] argsClass </span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)"> </span><span style="COLOR: rgb(0,0,255)">new</span><span style="COLOR: rgb(0,0,0)"> Class[args.length];<br /></span><span style="COLOR: rgb(0,128,128)"> 6</span> <span style="COLOR: rgb(0,0,0)"><br /></span><span style="COLOR: rgb(0,128,128)"> 7</span> <span style="COLOR: rgb(0,0,0)">    </span><span style="COLOR: rgb(0,0,255)">for</span><span style="COLOR: rgb(0,0,0)"> (</span><span style="COLOR: rgb(0,0,255)">int</span><span style="COLOR: rgb(0,0,0)"> i </span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)"> </span><span style="COLOR: rgb(0,0,0)">0</span><span style="COLOR: rgb(0,0,0)">, j </span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)"> args.length; i </span><span style="COLOR: rgb(0,0,0)">&lt;</span><span style="COLOR: rgb(0,0,0)"> j; i</span><span style="COLOR: rgb(0,0,0)">++</span><span style="COLOR: rgb(0,0,0)">) {<br /></span><span style="COLOR: rgb(0,128,128)"> 8</span> <span style="COLOR: rgb(0,0,0)">        argsClass[i] </span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)"> args[i].getClass();<br /></span><span style="COLOR: rgb(0,128,128)"> 9</span> <span style="COLOR: rgb(0,0,0)">    }<br /></span><span style="COLOR: rgb(0,128,128)">10</span> <span style="COLOR: rgb(0,0,0)"><br /></span><span style="COLOR: rgb(0,128,128)">11</span> <span style="COLOR: rgb(0,0,0)">    Method method </span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)"> ownerClass.getMethod(methodName, argsClass);<br /></span><span style="COLOR: rgb(0,128,128)">12</span> <span style="COLOR: rgb(0,0,0)"><br /></span><span style="COLOR: rgb(0,128,128)">13</span> <span style="COLOR: rgb(0,0,0)">    </span><span style="COLOR: rgb(0,0,255)">return</span><span style="COLOR: rgb(0,0,0)"> method.invoke(</span><span style="COLOR: rgb(0,0,255)">null</span><span style="COLOR: rgb(0,0,0)">, args);<br /></span><span style="COLOR: rgb(0,128,128)">14</span> <span style="COLOR: rgb(0,0,0)">}</span></div><br /><br />基本的原理和实例3相同，不同点是最后一行，invoke的一个参数是null，因为这是静态方法，不需要借助实例运行。<br /><br /><br /><br />5. 新建实例<br /><div style="BORDER-RIGHT: rgb(204,204,204) 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: rgb(204,204,204) 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: rgb(204,204,204) 1px solid; WIDTH: 98%; PADDING-TOP: 4px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BACKGROUND-COLOR: rgb(238,238,238)"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="COLOR: rgb(0,128,128)"> 1</span> <span style="COLOR: rgb(0,0,0)"><br /></span><span style="COLOR: rgb(0,128,128)"> 2</span> <span style="COLOR: rgb(0,0,0)"></span><span style="COLOR: rgb(0,0,255)">public</span><span style="COLOR: rgb(0,0,0)"> Object newInstance(String className, Object[] args) </span><span style="COLOR: rgb(0,0,255)">throws</span><span style="COLOR: rgb(0,0,0)"> Exception {<br /></span><span style="COLOR: rgb(0,128,128)"> 3</span> <span style="COLOR: rgb(0,0,0)">    Class newoneClass </span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)"> Class.forName(className);<br /></span><span style="COLOR: rgb(0,128,128)"> 4</span> <span style="COLOR: rgb(0,0,0)"><br /></span><span style="COLOR: rgb(0,128,128)"> 5</span> <span style="COLOR: rgb(0,0,0)">    Class[] argsClass </span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)"> </span><span style="COLOR: rgb(0,0,255)">new</span><span style="COLOR: rgb(0,0,0)"> Class[args.length];<br /></span><span style="COLOR: rgb(0,128,128)"> 6</span> <span style="COLOR: rgb(0,0,0)"><br /></span><span style="COLOR: rgb(0,128,128)"> 7</span> <span style="COLOR: rgb(0,0,0)">    </span><span style="COLOR: rgb(0,0,255)">for</span><span style="COLOR: rgb(0,0,0)"> (</span><span style="COLOR: rgb(0,0,255)">int</span><span style="COLOR: rgb(0,0,0)"> i </span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)"> </span><span style="COLOR: rgb(0,0,0)">0</span><span style="COLOR: rgb(0,0,0)">, j </span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)"> args.length; i </span><span style="COLOR: rgb(0,0,0)">&lt;</span><span style="COLOR: rgb(0,0,0)"> j; i</span><span style="COLOR: rgb(0,0,0)">++</span><span style="COLOR: rgb(0,0,0)">) {<br /></span><span style="COLOR: rgb(0,128,128)"> 8</span> <span style="COLOR: rgb(0,0,0)">        argsClass[i] </span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)"> args[i].getClass();<br /></span><span style="COLOR: rgb(0,128,128)"> 9</span> <span style="COLOR: rgb(0,0,0)">    }<br /></span><span style="COLOR: rgb(0,128,128)">10</span> <span style="COLOR: rgb(0,0,0)"><br /></span><span style="COLOR: rgb(0,128,128)">11</span> <span style="COLOR: rgb(0,0,0)">    Constructor cons </span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)"> newoneClass.getConstructor(argsClass);<br /></span><span style="COLOR: rgb(0,128,128)">12</span> <span style="COLOR: rgb(0,0,0)"><br /></span><span style="COLOR: rgb(0,128,128)">13</span> <span style="COLOR: rgb(0,0,0)">    </span><span style="COLOR: rgb(0,0,255)">return</span><span style="COLOR: rgb(0,0,0)"> cons.newInstance(args);<br /></span><span style="COLOR: rgb(0,128,128)">14</span> <span style="COLOR: rgb(0,0,0)"><br /></span><span style="COLOR: rgb(0,128,128)">15</span> <span style="COLOR: rgb(0,0,0)">}</span></div><br /><br />这里说的方法是执行带参数的构造函数来新建实例的方法。如果不需要参数，可以直接使用newoneClass.newInstance()来实现。<br /><br />Class newoneClass = Class.forName(className)：第一步，得到要构造的实例的Class。<br /><br />第5～第9行：得到参数的Class数组。<br /><br />Constructor cons = newoneClass.getConstructor(argsClass)：得到构造子。<br /><br />cons.newInstance(args)：新建实例。<br /><br /><br />6. 判断是否为某个类的实例<br /><br /><div style="BORDER-RIGHT: rgb(204,204,204) 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: rgb(204,204,204) 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: rgb(204,204,204) 1px solid; WIDTH: 98%; PADDING-TOP: 4px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BACKGROUND-COLOR: rgb(238,238,238)"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="COLOR: rgb(0,128,128)">1</span> <span style="COLOR: rgb(0,0,255)">public</span><span style="COLOR: rgb(0,0,0)"> </span><span style="COLOR: rgb(0,0,255)">boolean</span><span style="COLOR: rgb(0,0,0)"> isInstance(Object obj, Class cls) {<br /></span><span style="COLOR: rgb(0,128,128)">2</span> <span style="COLOR: rgb(0,0,0)">    </span><span style="COLOR: rgb(0,0,255)">return</span><span style="COLOR: rgb(0,0,0)"> cls.isInstance(obj);<br /></span><span style="COLOR: rgb(0,128,128)">3</span> <span style="COLOR: rgb(0,0,0)">}</span></div><br /><br /><br />7. 得到数组中的某个元素<br /><div style="BORDER-RIGHT: rgb(204,204,204) 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: rgb(204,204,204) 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: rgb(204,204,204) 1px solid; WIDTH: 98%; PADDING-TOP: 4px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BACKGROUND-COLOR: rgb(238,238,238)"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="COLOR: rgb(0,128,128)">1</span> <span style="COLOR: rgb(0,0,255)">public</span><span style="COLOR: rgb(0,0,0)"> Object getByArray(Object array, </span><span style="COLOR: rgb(0,0,255)">int</span><span style="COLOR: rgb(0,0,0)"> index) {<br /></span><span style="COLOR: rgb(0,128,128)">2</span> <span style="COLOR: rgb(0,0,0)">    </span><span style="COLOR: rgb(0,0,255)">return</span><span style="COLOR: rgb(0,0,0)"> Array.get(array,index);<br /></span><span style="COLOR: rgb(0,128,128)">3</span> <span style="COLOR: rgb(0,0,0)">}</span></div><br /><br /><br />附完整源码：<br /><br /><div style="BORDER-RIGHT: rgb(204,204,204) 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: rgb(204,204,204) 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: rgb(204,204,204) 1px solid; WIDTH: 98%; PADDING-TOP: 4px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BACKGROUND-COLOR: rgb(238,238,238)"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="COLOR: rgb(0,0,255)">import</span><span style="COLOR: rgb(0,0,0)"> java.lang.reflect.Array;<br /></span><span style="COLOR: rgb(0,0,255)">import</span><span style="COLOR: rgb(0,0,0)"> java.lang.reflect.Constructor;<br /></span><span style="COLOR: rgb(0,0,255)">import</span><span style="COLOR: rgb(0,0,0)"> java.lang.reflect.Field;<br /></span><span style="COLOR: rgb(0,0,255)">import</span><span style="COLOR: rgb(0,0,0)"> java.lang.reflect.Method;<br /><br /><br /></span><span style="COLOR: rgb(0,128,0)">/**</span><span style="COLOR: rgb(0,128,0)"><br /> * Java Reflection Cookbook<br /> *<br /> * </span><span style="COLOR: rgb(128,128,128)">@author</span><span style="COLOR: rgb(0,128,0)"> Michael Lee<br /> * </span><span style="COLOR: rgb(128,128,128)">@since</span><span style="COLOR: rgb(0,128,0)"> 2006-8-23<br /> * </span><span style="COLOR: rgb(128,128,128)">@version</span><span style="COLOR: rgb(0,128,0)"> 0.1a<br /> </span><span style="COLOR: rgb(0,128,0)">*/</span><span style="COLOR: rgb(0,0,0)"><br /><br /></span><span style="COLOR: rgb(0,0,255)">public</span><span style="COLOR: rgb(0,0,0)"> </span><span style="COLOR: rgb(0,0,255)">class</span><span style="COLOR: rgb(0,0,0)"> Reflection {<br />    </span><span style="COLOR: rgb(0,128,0)">/**</span><span style="COLOR: rgb(0,128,0)"><br />     * 得到某个对象的公共属性<br />     *<br />     * </span><span style="COLOR: rgb(128,128,128)">@param</span><span style="COLOR: rgb(0,128,0)"> owner, fieldName<br />     * </span><span style="COLOR: rgb(128,128,128)">@return</span><span style="COLOR: rgb(0,128,0)"> 该属性对象<br />     * </span><span style="COLOR: rgb(128,128,128)">@throws</span><span style="COLOR: rgb(0,128,0)"> Exception<br />     *<br />     </span><span style="COLOR: rgb(0,128,0)">*/</span><span style="COLOR: rgb(0,0,0)"><br />    </span><span style="COLOR: rgb(0,0,255)">public</span><span style="COLOR: rgb(0,0,0)"> Object getProperty(Object owner, String fieldName) </span><span style="COLOR: rgb(0,0,255)">throws</span><span style="COLOR: rgb(0,0,0)"> Exception {<br />        Class ownerClass </span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)"> owner.getClass();<br /><br />        Field field </span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)"> ownerClass.getField(fieldName);<br /><br />        Object property </span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)"> field.get(owner);<br /><br />        </span><span style="COLOR: rgb(0,0,255)">return</span><span style="COLOR: rgb(0,0,0)"> property;<br />    }<br /><br />    </span><span style="COLOR: rgb(0,128,0)">/**</span><span style="COLOR: rgb(0,128,0)"><br />     * 得到某类的静态公共属性<br />     *<br />     * </span><span style="COLOR: rgb(128,128,128)">@param</span><span style="COLOR: rgb(0,128,0)"> className   类名<br />     * </span><span style="COLOR: rgb(128,128,128)">@param</span><span style="COLOR: rgb(0,128,0)"> fieldName   属性名<br />     * </span><span style="COLOR: rgb(128,128,128)">@return</span><span style="COLOR: rgb(0,128,0)"> 该属性对象<br />     * </span><span style="COLOR: rgb(128,128,128)">@throws</span><span style="COLOR: rgb(0,128,0)"> Exception<br />     </span><span style="COLOR: rgb(0,128,0)">*/</span><span style="COLOR: rgb(0,0,0)"><br />    </span><span style="COLOR: rgb(0,0,255)">public</span><span style="COLOR: rgb(0,0,0)"> Object getStaticProperty(String className, String fieldName)<br />            </span><span style="COLOR: rgb(0,0,255)">throws</span><span style="COLOR: rgb(0,0,0)"> Exception {<br />        Class ownerClass </span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)"> Class.forName(className);<br /><br />        Field field </span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)"> ownerClass.getField(fieldName);<br /><br />        Object property </span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)"> field.get(ownerClass);<br /><br />        </span><span style="COLOR: rgb(0,0,255)">return</span><span style="COLOR: rgb(0,0,0)"> property;<br />    }<br /><br /><br />    </span><span style="COLOR: rgb(0,128,0)">/**</span><span style="COLOR: rgb(0,128,0)"><br />     * 执行某对象方法<br />     *<br />     * </span><span style="COLOR: rgb(128,128,128)">@param</span><span style="COLOR: rgb(0,128,0)"> owner<br />     *            对象<br />     * </span><span style="COLOR: rgb(128,128,128)">@param</span><span style="COLOR: rgb(0,128,0)"> methodName<br />     *            方法名<br />     * </span><span style="COLOR: rgb(128,128,128)">@param</span><span style="COLOR: rgb(0,128,0)"> args<br />     *            参数<br />     * </span><span style="COLOR: rgb(128,128,128)">@return</span><span style="COLOR: rgb(0,128,0)"> 方法返回值<br />     * </span><span style="COLOR: rgb(128,128,128)">@throws</span><span style="COLOR: rgb(0,128,0)"> Exception<br />     </span><span style="COLOR: rgb(0,128,0)">*/</span><span style="COLOR: rgb(0,0,0)"><br />    </span><span style="COLOR: rgb(0,0,255)">public</span><span style="COLOR: rgb(0,0,0)"> Object invokeMethod(Object owner, String methodName, Object[] args)<br />            </span><span style="COLOR: rgb(0,0,255)">throws</span><span style="COLOR: rgb(0,0,0)"> Exception {<br /><br />        Class ownerClass </span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)"> owner.getClass();<br /><br />        Class[] argsClass </span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)"> </span><span style="COLOR: rgb(0,0,255)">new</span><span style="COLOR: rgb(0,0,0)"> Class[args.length];<br /><br />        </span><span style="COLOR: rgb(0,0,255)">for</span><span style="COLOR: rgb(0,0,0)"> (</span><span style="COLOR: rgb(0,0,255)">int</span><span style="COLOR: rgb(0,0,0)"> i </span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)"> </span><span style="COLOR: rgb(0,0,0)">0</span><span style="COLOR: rgb(0,0,0)">, j </span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)"> args.length; i </span><span style="COLOR: rgb(0,0,0)">&lt;</span><span style="COLOR: rgb(0,0,0)"> j; i</span><span style="COLOR: rgb(0,0,0)">++</span><span style="COLOR: rgb(0,0,0)">) {<br />            argsClass[i] </span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)"> args[i].getClass();<br />        }<br /><br />        Method method </span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)"> ownerClass.getMethod(methodName, argsClass);<br /><br />        </span><span style="COLOR: rgb(0,0,255)">return</span><span style="COLOR: rgb(0,0,0)"> method.invoke(owner, args);<br />    }<br /><br /><br />      </span><span style="COLOR: rgb(0,128,0)">/**</span><span style="COLOR: rgb(0,128,0)"><br />     * 执行某类的静态方法<br />     *<br />     * </span><span style="COLOR: rgb(128,128,128)">@param</span><span style="COLOR: rgb(0,128,0)"> className<br />     *            类名<br />     * </span><span style="COLOR: rgb(128,128,128)">@param</span><span style="COLOR: rgb(0,128,0)"> methodName<br />     *            方法名<br />     * </span><span style="COLOR: rgb(128,128,128)">@param</span><span style="COLOR: rgb(0,128,0)"> args<br />     *            参数数组<br />     * </span><span style="COLOR: rgb(128,128,128)">@return</span><span style="COLOR: rgb(0,128,0)"> 执行方法返回的结果<br />     * </span><span style="COLOR: rgb(128,128,128)">@throws</span><span style="COLOR: rgb(0,128,0)"> Exception<br />     </span><span style="COLOR: rgb(0,128,0)">*/</span><span style="COLOR: rgb(0,0,0)"><br />    </span><span style="COLOR: rgb(0,0,255)">public</span><span style="COLOR: rgb(0,0,0)"> Object invokeStaticMethod(String className, String methodName,<br />            Object[] args) </span><span style="COLOR: rgb(0,0,255)">throws</span><span style="COLOR: rgb(0,0,0)"> Exception {<br />        Class ownerClass </span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)"> Class.forName(className);<br /><br />        Class[] argsClass </span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)"> </span><span style="COLOR: rgb(0,0,255)">new</span><span style="COLOR: rgb(0,0,0)"> Class[args.length];<br /><br />        </span><span style="COLOR: rgb(0,0,255)">for</span><span style="COLOR: rgb(0,0,0)"> (</span><span style="COLOR: rgb(0,0,255)">int</span><span style="COLOR: rgb(0,0,0)"> i </span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)"> </span><span style="COLOR: rgb(0,0,0)">0</span><span style="COLOR: rgb(0,0,0)">, j </span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)"> args.length; i </span><span style="COLOR: rgb(0,0,0)">&lt;</span><span style="COLOR: rgb(0,0,0)"> j; i</span><span style="COLOR: rgb(0,0,0)">++</span><span style="COLOR: rgb(0,0,0)">) {<br />            argsClass[i] </span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)"> args[i].getClass();<br />        }<br /><br />        Method method </span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)"> ownerClass.getMethod(methodName, argsClass);<br /><br />        </span><span style="COLOR: rgb(0,0,255)">return</span><span style="COLOR: rgb(0,0,0)"> method.invoke(</span><span style="COLOR: rgb(0,0,255)">null</span><span style="COLOR: rgb(0,0,0)">, args);<br />    }<br /><br /><br /><br />    </span><span style="COLOR: rgb(0,128,0)">/**</span><span style="COLOR: rgb(0,128,0)"><br />     * 新建实例<br />     *<br />     * </span><span style="COLOR: rgb(128,128,128)">@param</span><span style="COLOR: rgb(0,128,0)"> className<br />     *            类名<br />     * </span><span style="COLOR: rgb(128,128,128)">@param</span><span style="COLOR: rgb(0,128,0)"> args<br />     *            构造函数的参数<br />     * </span><span style="COLOR: rgb(128,128,128)">@return</span><span style="COLOR: rgb(0,128,0)"> 新建的实例<br />     * </span><span style="COLOR: rgb(128,128,128)">@throws</span><span style="COLOR: rgb(0,128,0)"> Exception<br />     </span><span style="COLOR: rgb(0,128,0)">*/</span><span style="COLOR: rgb(0,0,0)"><br />    </span><span style="COLOR: rgb(0,0,255)">public</span><span style="COLOR: rgb(0,0,0)"> Object newInstance(String className, Object[] args) </span><span style="COLOR: rgb(0,0,255)">throws</span><span style="COLOR: rgb(0,0,0)"> Exception {<br />        Class newoneClass </span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)"> Class.forName(className);<br /><br />        Class[] argsClass </span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)"> </span><span style="COLOR: rgb(0,0,255)">new</span><span style="COLOR: rgb(0,0,0)"> Class[args.length];<br /><br />        </span><span style="COLOR: rgb(0,0,255)">for</span><span style="COLOR: rgb(0,0,0)"> (</span><span style="COLOR: rgb(0,0,255)">int</span><span style="COLOR: rgb(0,0,0)"> i </span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)"> </span><span style="COLOR: rgb(0,0,0)">0</span><span style="COLOR: rgb(0,0,0)">, j </span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)"> args.length; i </span><span style="COLOR: rgb(0,0,0)">&lt;</span><span style="COLOR: rgb(0,0,0)"> j; i</span><span style="COLOR: rgb(0,0,0)">++</span><span style="COLOR: rgb(0,0,0)">) {<br />            argsClass[i] </span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)"> args[i].getClass();<br />        }<br /><br />        Constructor cons </span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)"> newoneClass.getConstructor(argsClass);<br /><br />        </span><span style="COLOR: rgb(0,0,255)">return</span><span style="COLOR: rgb(0,0,0)"> cons.newInstance(args);<br /><br />    }<br /><br /><br />    <br />    </span><span style="COLOR: rgb(0,128,0)">/**</span><span style="COLOR: rgb(0,128,0)"><br />     * 是不是某个类的实例<br />     * </span><span style="COLOR: rgb(128,128,128)">@param</span><span style="COLOR: rgb(0,128,0)"> obj 实例<br />     * </span><span style="COLOR: rgb(128,128,128)">@param</span><span style="COLOR: rgb(0,128,0)"> cls 类<br />     * </span><span style="COLOR: rgb(128,128,128)">@return</span><span style="COLOR: rgb(0,128,0)"> 如果 obj 是此类的实例，则返回 true<br />     </span><span style="COLOR: rgb(0,128,0)">*/</span><span style="COLOR: rgb(0,0,0)"><br />    </span><span style="COLOR: rgb(0,0,255)">public</span><span style="COLOR: rgb(0,0,0)"> </span><span style="COLOR: rgb(0,0,255)">boolean</span><span style="COLOR: rgb(0,0,0)"> isInstance(Object obj, Class cls) {<br />        </span><span style="COLOR: rgb(0,0,255)">return</span><span style="COLOR: rgb(0,0,0)"> cls.isInstance(obj);<br />    }<br />    <br />    </span><span style="COLOR: rgb(0,128,0)">/**</span><span style="COLOR: rgb(0,128,0)"><br />     * 得到数组中的某个元素<br />     * </span><span style="COLOR: rgb(128,128,128)">@param</span><span style="COLOR: rgb(0,128,0)"> array 数组<br />     * </span><span style="COLOR: rgb(128,128,128)">@param</span><span style="COLOR: rgb(0,128,0)"> index 索引<br />     * </span><span style="COLOR: rgb(128,128,128)">@return</span><span style="COLOR: rgb(0,128,0)"> 返回指定数组对象中索引组件的值<br />     </span><span style="COLOR: rgb(0,128,0)">*/</span><span style="COLOR: rgb(0,0,0)"><br />    </span><span style="COLOR: rgb(0,0,255)">public</span><span style="COLOR: rgb(0,0,0)"> Object getByArray(Object array, </span><span style="COLOR: rgb(0,0,255)">int</span><span style="COLOR: rgb(0,0,0)"> index) {<br />        </span><span style="COLOR: rgb(0,0,255)">return</span><span style="COLOR: rgb(0,0,0)"> Array.get(array,index);<br />    }<br />}</span></div><img src ="http://www.blogjava.net/balajinima/aggbug/149623.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/balajinima/" target="_blank">李云泽</a> 2007-09-29 17:14 <a href="http://www.blogjava.net/balajinima/articles/149623.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>体验JAVA 5的新增语言特性 </title><link>http://www.blogjava.net/balajinima/articles/146905.html</link><dc:creator>李云泽</dc:creator><author>李云泽</author><pubDate>Thu, 20 Sep 2007 12:10:00 GMT</pubDate><guid>http://www.blogjava.net/balajinima/articles/146905.html</guid><wfw:comment>http://www.blogjava.net/balajinima/comments/146905.html</wfw:comment><comments>http://www.blogjava.net/balajinima/articles/146905.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/balajinima/comments/commentRss/146905.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/balajinima/services/trackbacks/146905.html</trackback:ping><description><![CDATA[		<br />
		<div style="MARGIN-TOP: 1px; MARGIN-LEFT: 15px">
				<h2>
						<a title="永久链接：体验JAVA 5的新增语言特性" href="http://kenshinlk.javaeye.com/blog/60570">
								<font color="#002c99">体验JAVA 5的新增语言特性</font>
						</a>
				</h2>
		</div>
		<div style="MARGIN-TOP: 5px; MARGIN-LEFT: 15px">
				<b>关键字:</b> &#160; 体验JAVA 5的新增语言特性&#160;&#160;&#160;&#160; </div>
		<div style="MARGIN-TOP: 10px; MARGIN-LEFT: 15px; OVERFLOW: auto">
				<table width="100%">
						<tbody>
								<tr>
										<td>
												<p>
														<img height="1" alt="" src="http://dev2dev.bea.com.cn/images/dot6B6B6B.gif" width="100%" />
												</p>
												<p>　　Java 5.0发布了，许多人都将开始使用这个JDK版本的一些新增特性。从增强的for循环到诸如泛型(generic)之类更复杂的特性，都将很快出现在您所编写的代码中。我们刚刚完成了一个基于Java 5.0的大型任务，而本文就是要介绍我们使用这些新特性的体验。本文不是一篇入门性的文章，而是对这些特性以及它们所产生的影响的深入介绍，同时还给出了一些在项目中更有效地使用这些特性的技巧。 </p>
												<p>
														<strong>简介</strong>
														<br />　　在JDK 1.5的beta阶段，我们为BEA的Java IDE开发了一个Java 5编译器。因为我们实现了许多新特性，所以人们开始以新的方式利用它们；有些用法很聪明，而有些用法明显应该被列入禁用清单。编译器本身使用了新的语言特性，所以我们也获得了使用这些特性维护代码的直接体验。本文将介绍其中的许多特性和使用它们的体验。 <br />　　我们假定您已经熟悉了这些新特性，所以不再全面介绍每个特性，而是谈论一些有趣的、但很可能不太明显的内容和用法。这些技巧出自我们的实际体验，并大致按照语言特性进行了分类。 <br />　　我们将从最简单的特性开始，逐步过渡到高级特性。泛型所包含的内容特别丰富，因此占了本文一半的篇幅。</p>
												<p>
														<strong>增强的for循环</strong>
														<br />　　为了迭代集合和数组，增强的for循环提供了一个简单、兼容的语法。有两点值得一提： </p>
												<p>
														<strong>Init表达式</strong>
														<br />　　在循环中，初始化表达式只计算一次。这意味着您通常可以移除一个变量声明。在这个例子中，我们必须创建一个整型数组来保存computeNumbers()的结果，以防止每一次循环都重新计算该方法。您可以看到，下面的代码要比上面的代码整洁一些，并且没有泄露变量numbers： <br /></p>
												<pre class="code">未增强的For：
int sum = 0;
Integer[] numbers = computeNumbers();
for (int i=0; i &lt; numbers.length ; i++)
    sum += numbers[i];
增强后的For： 
int sum = 0;

for ( int number: computeNumbers() )
    sum += number;</pre>
												<p>
														<strong>局限性</strong>
														<br />有时需要在迭代期间访问迭代器或下标，看起来增强的for循环应该允许该操作，但事实上不是这样，请看下面的例子： </p>
												<pre class="code">for (int i=0; i &lt; numbers.length ; i++) {
    if (i != 0) System.out.print(",");
    System.out.print(numbers[i]);
}</pre>
												<p>　　我们希望将数组中的值打印为一个用逗号分隔的清单。我们需要知道目前是否是第一项，以便确定是否应该打印逗号。使用增强的for循环是无法获知这种信息的。我们需要自己保留一个下标或一个布尔值来指示是否经过了第一项。 　　这是另一个例子： </p>
												<pre class="code">for (Iterator<integer></integer> it = n.iterator() ; it.hasNext() ; )
    if (it.next() &lt; 0)
        it.remove();</pre>
												<p>　　在此例中，我们想从整数集合中删除负数项。为此，需要对迭代器调用一个方法，但是当使用增强的for 循环时，迭代器对我们来说是看不到的。因此，我们只能使用Java 5之前版本的迭代方法。 　　顺便说一下，这里需要注意的是，由于Iterator是泛型，所以其声明是Iterator<integer></integer>。许多人都忘记了这一点而使用了Iterator的原始格式。 </p>
												<p>
														<strong>注释</strong>
														<br />　　注释处理是一个很大的话题。因为本文只关注核心的语言特性，所以我们不打算涵盖它所有的可能形式和陷阱。　　我们将讨论内置的注释（SuppressWarnings，Deprecated和Override）以及一般注释处理的局限性。 </p>
												<p>
														<strong>Suppress Warnings</strong>
														<br />　　该注释关闭了类或方法级别的编译器警告。有时候您比编译器更清楚地知道，代码必须使用一个被否决的方法或执行一些无法静态确定是否类型安全的动作，而使用：</p>
												<pre class="code">@SuppressWarnings("deprecation")
public static void selfDestruct() {
    Thread.currentThread().stop();
}</pre>
												<p>　　这可能是内置注释最有用的地方。遗憾的是，1.5.0_04的javac不支持它。但是1.6支持它，并且Sun正在努力将其向后移植到1.5中。 <br />Eclipse 3.1中支持该注释，其他IDE也可能支持它。这允许您把代码彻底地从警告中解脱出来。如果在编译时出现警告，可以确定是您刚刚把它添加进来——以帮助查看那些可能不安全的代码。随着泛型的添加，它使用起来将更趁手。 </p>
												<p>
														<strong>Deprecated</strong>
														<br />　　遗憾的是，Deprecated没那么有用。它本来旨在替换@deprecated javadoc标签，但是由于它不包含任何字段，所以也就没有方法来建议deprecated类或方法的用户应该使用什么做为替代品。大多数用法都同时需要javadoc标签和这个注释。 </p>
												<p>
														<strong>Override</strong>
														<br />　　Override表示，它所注释的方法应该重写超类中具有相同签名的方法： </p>
												<pre class="code">@Override
public int hashCode() {
    ...
}</pre>
												<p>　　看上面的例子，如果没有在hashCode中将&#8220;C&#8221;大写，在编译时不会出现错误，但是在运行时将无法像期望的那样调用该方法。通过添加Override标签，编译器会提示它是否真正地执行了重写。 <br />　　在超类发生改变的情况中，这也很有帮助。如果向该方法中添加一个新参数，而且方法本身也被重命名了，那么子类将突然不能编译，因为它不再重写超类的任何东西。 </p>
												<p>
														<strong>其它注释<br /></strong>　　注释在其他场景中非常有用。当不是直接修改行为而是增强行为时，特别是在添加样板代码的情况下，注释在诸如EJB和<a href="http://dev2dev.bea.com/pub/a/2004/10/Anil_WServices.html" target="_blank"><font color="#002c99">Web services</font></a>这样的框架中运行得非常好。 <br />注释不能用做预处理器。Sun的设计特别预防了完全因为注释而修改类的字节码。这样可以正确地理解该语言的成果，而且IDE之类的工具也可以执行深入的代码分析和重构之类的功能。 <br />注释不是银弹。第一次遇到的时候，人们试图尝试各种技巧。请看下面这个从别人那里获得的建议： </p>
												<pre class="code">public class Foo {
&#160;
    @Property
    private int bar;
&#160;
}</pre>
												<p>　　其思想是为私有字段bar自动创建getter和setter方法。遗憾的是，这个想法有两个失败之处：1)它不能运行，2)它使代码难以阅读和处理。 　　它是无法实现的，因为前面已经提到了，Sun特别阻止了对出现注释的类进行修改。 <br />　　即使是可能的，它也不是一个好主意，因为它使代码可读性差。第一次看到这段代码的人会不知道该注释创建了方法。此外，如果将来您需要在这些方法内部执行一些操作，注释也是没用的。 　　总之，不要试图用注释去做那些常规代码可以完成的事情。 </p>
												<p>
														<strong>枚举 </strong>
														<br />　　enum非常像public static final int声明，后者作为枚举值已经使用了很多年。对int所做的最大也是最明显的改进是类型安全——您不能错误地用枚举的一种类型代替另一种类型，这一点和int不同，所有的int对编译器来说都是一样的。除去极少数例外的情况，通常都应该用enum实例替换全部的枚举风格的int结构。 <br />　　枚举提供了一些附加的特性。EnumMap和EnumSet这两个实用类是专门为枚举优化的标准集合实现。如果知道集合只包含枚举类型，那么应该使用这些专门的集合来代替HashMap或HashSet。 <br />　　大部分情况下，可以使用enum对代码中的所有public static final int做插入替换。它们是可比的，并且可以静态导入，所以对它们的引用看起来是等同的，即使是对于内部类（或内部枚举类型）。注意，比较枚举类型的时候，声明它们的指令表明了它们的顺序值。 <br /><br /><strong>&#8220;隐藏的&#8221;静态方法 </strong><br />　　两个静态方法出现在所有枚举类型声明中。因为它们是枚举子类上的静态方法，而不是Enum本身的方法，所以它们在java.lang.Enum的javadoc中没有出现。 <br />　　第一个是values()，返回一个枚举类型所有可能值的数组。 <br />　　第二个是valueOf()，为提供的字符串返回一个枚举类型，该枚举类型必须精确地匹配源代码声明。 <br /><strong>方法<br /></strong>　　关于枚举类型，我们最喜欢的一个方面是它可以有方法。过去您可能需要编写一些代码，对public static final int进行转换，把它从数据库类型转换为JDBC URL。而现在则可以让枚举类型本身带一个整理代码的方法。下面就是一个例子，包括DatabaseType枚举类型的抽象方法以及每个枚举实例中提供的实现： <br /></p>
												<pre class="code">  public enum  DatabaseType {
  ORACLE {
  public String getJdbcUrl() {...}
  },
  MYSQL {
  public String getJdbcUrl() {...}
  };
  public abstract String getJdbcUrl();
  }</pre>
												<p>　　现在枚举类型可以直接提供它的实用方法。例如：<br /><br />DatabaseType dbType = ...;<br />String jdbcURL = dbType.getJdbcUrl();<br /><br />　　要获取URL，必须预先知道该实用方法在哪里。 </p>
												<p>
														<br />
														<strong>可变参数(Vararg)</strong>
														<br />　　正确地使用可变参数确实可以清理一些垃圾代码。典型的例子是一个带有可变的String参数个数的log方法： <br /></p>
												<pre class="code">    Log.log(String code)
    Log.log(String code,  String arg)
    Log.log(String code,  String arg1, String arg2)
    Log.log(String code,  String[] args)</pre>
												<p>　　当讨论可变参数时，比较有趣的是，如果用新的可变参数替换前四个例子，将是兼容的： <br />Log.log(String code, String... args)<br />　　所有的可变参数都是源兼容的——那就是说，如果重新编译log()方法的所有调用程序，可以直接替换全部的四个方法。然而，如果需要向后的二进制兼容性，那么就需要舍去前三个方法。只有最后那个带一个字符串数组参数的方法等效于可变参数版本，因此可以被可变参数版本替换。 <br /><strong><br />类型强制转换 </strong><br />　　如果希望调用程序了解应该使用哪种类型的参数，那么应该避免用可变参数进行类型强制转换。看下面这个例子，第一项希望是String，第二项希望是Exception： <br /></p>
												<pre class="code">    Log.log(Object...  objects) {
    String message = (String)objects[0];
    if (objects.length &gt; 1) {
    Exception e = (Exception)objects[1];
    // Do something with the exception
    }
    }</pre>
												<p>　　方法签名应该如下所示，相应的可变参数分别使用String和Exception声明： <br /><br />Log.log(String message, Exception e, Object... objects) {...}<br /><br />　　不要使用可变参数破坏类型系统。需要强类型化时才可以使用它。对于这个规则，PrintStream.printf()是一个有趣的例外：它提供类型信息作为自己的第一个参数，以便稍后可以接受那些类型。 <br /><strong><br />协变返回 </strong><br />　　协变返回的基本用法是用于在已知一个实现的返回类型比API更具体的时候避免进行类型强制转换。在下面这个例子中，有一个返回Animal对象的Zoo接口。我们的实现返回一个AnimalImpl对象，但是在JDK 1.5之前，要返回一个Animal对象就必须声明。:<br /></p>
												<pre class="code">    public interface Zoo  {
    public Animal getAnimal();
    }
  public class ZooImpl  implements Zoo {
  public Animal getAnimal(){
  return new AnimalImpl();
  }
  }</pre>
												<p>　　协变返回的使用替换了三个反模式： </p>
												<p>&#160;</p>
												<ul>
														<li>直接字段访问。为了规避API限制，一些实现把子类直接暴露为字段： </li>
												</ul>
												<p align="left">ZooImpl._animal</p>
												<ul>
														<li>另一种形式是，在知道实现的实际上是特定的子类的情况下，在调用程序中执行向下转换： </li>
												</ul>
												<p align="left">((AnimalImpl)ZooImpl.getAnimal()).implMethod();</p>
												<ul>
														<li>我看到的最后一种形式是一个具体的方法，该方法用来避免由一个完全不同的签名所引发的问题： </li>
												</ul>
												<p align="left">ZooImpl._getAnimal();<br /><br />　　这三种模式都有它们的问题和局限性。要么是不够整洁，要么就是暴露了不必要的实现细节。 <br /><strong><br />协变 </strong><br />　　协变返回模式就比较整洁、安全并且易于维护，它也不需要类型强制转换或特定的方法或字段： <br />public AnimalImpl getAnimal(){<br />return new AnimalImpl();<br />}<br />　　使用结果： <br />ZooImpl.getAnimal().implMethod();<br /><br /><strong>使用泛型<br />　　</strong>我们将从两个角度来了解泛型：使用泛型和构造泛型。我们不讨论List、Set和Map的显而易见的用法。知道泛型集合是强大的并且应该经常使用就足够了。 <br />　　我们将讨论泛型方法的使用以及编译器推断类型的方法。通常这些都不会出问题，但是当出问题时，错误信息会非常令人费解，所以需要了解如何修复这些问题。 </p>
												<p>
														<strong>泛型方法<br />　　</strong>除了泛型类型，Java 5还引入了泛型方法。在这个来自java.util.Collections的例子中，构造了一个单元素列表。新的List的元素类型是根据传入方法的对象的类型来推断的： </p>
												<pre class="code">static <t></t> List<t></t> Collections.singletonList(T o)
示例用法：
public List<integer></integer> getListOfOne() {
    return Collections.singletonList(1);
}</pre>
												<p>　　在示例用法中，我们传入了一个int。所以方法的返回类型就是List<integer></integer>。编译器把T推断为Integer。这和泛型类型是不同的，因为您通常不需要显式地指定类型参数。 <br />这也显示了自动装箱和泛型的相互作用。类型参数必须是引用类型：这就是为什么我们得到的是List<integer></integer>而不是List<int></int>。 </p>
												<p>
														<strong>不带参数的泛型方法<br />　　</strong>emptyList()方法与泛型一起引入，作为java.util.Collections中EMPTY_LIST字段的类型安全置换： </p>
												<pre class="code">static <t></t> List<t></t> Collections.emptyList()
示例用法： 
public List<integer></integer> getNoIntegers() {
    return Collections.emptyList();
}</pre>
												<p>　　与先前的例子不同，这个方法没有参数，那么编译器如何推断T的类型呢？基本上，它将尝试使用一次参数。如果没有起作用，它再次尝试使用返回或赋值类型。在本例中，返回的是List<integer></integer>，所以T被推断为Integer。 <br />　　如果在返回语句或赋值语句之外的位置调用泛型方法会怎么样呢？那么编译器将无法执行类型推断的第二次传送。在下面这个例子中，emptyList()是从条件运算符内部调用的： </p>
												<pre class="code">public List<integer></integer> getNoIntegers() {
    return x ? Collections.emptyList() : null;
}</pre>
												<p>　　因为编译器看不到返回上下文，也不能推断T，所以它放弃并采用Object。您将看到一个错误消息，比如：&#8220;无法将List&lt; Object &gt;转换为List<integer></integer>。&#8221; <br />为了修复这个错误，应显式地向方法调用传递类型参数。这样，编译器就不会试图推断类型参数，就可以获得正确的结果： </p>
												<pre class="code">return x ? Collections.<integer></integer>emptyList() : null;</pre>
												<p>　　这种情况经常发生的另一个地方是在方法调用中。如果一个方法带一个List<string></string>参数，并且需要为那个参数调用这个传递的emptyList()，那么也需要使用这个语法。 </p>
												<p>
														<strong>集合之外<br /></strong>　　这里有三个泛型类型的例子，它们不是集合，而是以一种新颖的方式使用泛型。这三个例子都来自标准的Java库： </p>
												<ul>
														<li>Class<t></t><br />Class在类的类型上被参数化了。这就使无需类型强制转换而构造一个newInstance成为可能。 
</li>
														<li>Comparable<t></t><br />Comparable被实际的比较类型参数化。这就在compareTo()调用时提供了更强的类型化。例如，String实现Comparable<string></string>。对除String之外的任何东西调用compareTo()，都会在编译时失败。 
</li>
														<li>Enum<e extends=""></e>&gt;<br />Enum被枚举类型参数化。一个名为Color的枚举类型将扩展Enum<color></color>。getDeclaringClass()方法返回枚举类型的类对象，在这个例子中就是一个Color对象。它与getClass()不同，后者可能返回一个无名类。 </li>
												</ul>
												<p>
														<strong>通配符<br />　　</strong>泛型最复杂的部分是对通配符的理解。我们将讨论三种类型的通配符以及它们的用途。 <br />　　首先让我们了解一下数组是如何工作的。可以从一个Integer[]为一个Number[]赋值。如果尝试把一个Float写到Number[]中，那么可以编译，但在运行时会失败，出现一个ArrayStoreException： </p>
												<pre class="code">Integer[] ia = new Integer[5];
Number[] na = ia;
na[0] = 0.5; // compiles, but fails at runtime
如果试图把该例直接转换成泛型，那么会在编译时失败，因为赋值是不被允许的：
List<integer></integer> iList = new ArrayList<integer></integer>();
List<number></number> nList = iList; // not allowed
nList.add(0.5);</pre>
												<p>　　如果使用泛型，只要代码在编译时没有出现警告，就不会遇到运行时ClassCastException。 </p>
												<p>
														<strong>上限通配符</strong>
														<br />　　我们想要的是一个确切元素类型未知的列表，这一点与数组是不同的。 <br />List<number></number>是一个列表，其元素类型是具体类型Number。 <br />List&lt;!--xtends Numb--&gt;是一个确切元素类型未知的列表。它是Number或其子类型。 </p>
												<p>
														<strong>上限<br />　　</strong>如果我们更新初始的例子，并赋值给List&lt;!--xtends Numb--&gt;，那么现在赋值就会成功了： </p>
												<pre class="code">List<integer></integer> iList = new ArrayList<integer></integer>();
List&lt;!--xtends Numb--&gt; nList = iList;
Number n = nList.get(0);
nList.add(0.5); // Not allowed</pre>
												<p>　　我们可以从列表中得到Number，因为无论列表的确切元素类型是什么（Float、Integer或Number），我们都可以把它赋值给Number。 <br />　　我们仍然不能把浮点类型插入列表中。这会在编译时失败，因为我们不能证明这是安全的。如果我们想要向列表中添加浮点类型，它将破坏iList的初始类型安全——它只存储Integer。 <br />　　通配符给了我们比数组更多的表达能力。 </p>
												<p>
														<strong>为什么使用通配符<br /></strong>　　在下面这个例子中，通配符用于向API的用户隐藏类型信息。在内部，Set被存储为CustomerImpl。而API的用户只知道他们正在获取一个Set，从中可以读取Customer。 <br />此处通配符是必需的，因为无法从Set<customerimpl></customerimpl>向Set<customer></customer>赋值： </p>
												<pre class="code">public class CustomerFactory {
    private Set<customerimpl></customerimpl> _customers;
    public Set&lt;!--xtends Custom--&gt; getCustomers() {
        return _customers;
    }
}</pre>
												<p>
														<strong>通配符和协变返回</strong>
														<br />　　通配符的另一种常见用法是和协变返回一起使用。与赋值相同的规则可以应用到协变返回上。如果希望在重写的方法中返回一个更具体的泛型类型，声明的方法必须使用通配符： </p>
												<pre class="code">public interface NumberGenerator {
    public List&lt;!--xtends Numb--&gt; generate();
}
public class FibonacciGenerator extends NumberGenerator {
    public List<integer></integer> generate() {
        ...
    }
}</pre>
												<p>　　如果要使用数组，接口可以返回Number[]，而实现可以返回Integer[]。 </p>
												<p>
														<strong>下限 </strong>
														<br />　　我们所谈的主要是关于上限通配符的。还有一个下限通配符。List&lt;!--uper Numb--&gt;是一个确切&#8220;元素类型&#8221;未知的列表，但是可能是Mnumber，或者Number的超类型。所以它可能是一个List<number></number>或一个List&lt; Object&gt;。 <br />　　下限通配符远没有上限通配符那样常见，但是当需要它们的时候，它们就是必需的。 </p>
												<p>
														<strong>下限与上限<br /></strong>
												</p>
												<pre class="code">List&lt;!--xtends Numb--&gt; readList = new ArrayList<integer></integer>();
Number n = readList.get(0);

List&lt;!--uper Numb--&gt; writeList = new ArrayList&lt; Object&gt;();
writeList.add(new Integer(5));</pre>
												<p>　　第一个是可以从中读数的列表。 <br />　　第二个是可以向其写数的列表。 </p>
												<p>
														<strong>无界通配符</strong>
														<br />　　最后，List列表的内容可以是任何类型，而且它与List&lt;!--xtends Obje--&gt;几乎相同。可以随时读取Object，但是不能向列表中写入内容。 </p>
												<p>
														<strong>公共API中的通配符 </strong>
														<br />　　总之，正如前面所说，通配符在向调用程序隐藏实现细节方面是非常重要的，但即使下限通配符看起来是提供只读访问，由于remove(int position)之类的非泛型方法，它们也并非如此。如果您想要一个真正不变的集合，可以使用java.util.Collection上的方法，比如unmodifiableList()。 <br />　　编写API的时候要记得通配符。通常，在传递泛型类型时，应该尝试使用通配符。它使更多的调用程序可以访问API。 <br />　　通过接收List&lt;!--xtends Numb--&gt;而不是List<number></number>，下面的方法可以由许多不同类型的列表调用： </p>
												<pre class="code">void removeNegatives(List&lt;!--xtends Numb--&gt; list);</pre>
												<p>
														<strong>构造泛型类型</strong>
														<br />　　现在我们将讨论构造自己的泛型类型。我们将展示一些例子，其中通过使用泛型可以提高类型安全性，我们还将讨论一些实现泛型类型时的常见问题。</p>
												<p>
														<strong>集合风格(Collection-like)的函数</strong>
														<br />　　第一个泛型类的例子是一个集合风格的例子。Pair有两个类型参数，而且字段是类型的实例： </p>
												<pre class="code">public final class Pair {
    public final A first;
    public final B second;

    public Pair(A first, B second) {
        this.first = first;
        this.second = second;
    }
}</pre>
												<p>　　这使从方法返回两个项而无需为每个两种类型的组合编写专用的类成为可能。另一种方法是返回Object[]，而这样是类型不安全或者不整洁的。 <br />在下面的用法中，我们从方法返回一个File和一个Boolean。方法的客户端可以直接使用字段而无需类型强制转换： </p>
												<pre class="code">public Pair getFileAndWriteStatus(String path){
    // create file and status
    return new Pair(file, status);
}

Pair result = getFileAndWriteStatus("...");
File f = result.first;
boolean writeable = result.second;</pre>
												<p>
														<strong>集合之外 </strong>
														<br />　　在下面这个例子中，泛型被用于附加的编译时安全性。通过把DBFactory类参数化为所创建的Peer类型，您实际上是在强制Factory子类返回一个Peer的特定子类型： </p>
												<pre class="code">public abstract class DBFactory<t extends="" dbpeer=""></t> {
    protected abstract T createEmptyPeer();
    public List<t></t> get(String constraint) {
        List<t></t> peers = new ArrayList<t></t>();
        // database magic
        return peers;
    }
}
通过实现DBFactory<customer></customer>，CustomerFactory必须从createEmptyPeer()返回一个Customer：
public class CustomerFactory extends DBFactory<customer></customer>{

    public Customer createEmptyPeer() {
        return new Customer();
    }
}</pre>
												<p>
														<strong>泛型方法<br /></strong>　　不管想要对参数之间还是参数与返回类型之间的泛型类型施加约束，都可以使用泛型方法： <br />　　例如，如果编写的反转函数是在位置上反转，那么可能不需要泛型方法。然而，如果希望反转返回一个新的List，那么可能会希望新List的元素类型与传入的List的类型相同。在这种情况下，就需要一个泛型方法： </p>
												<p>
														<br />
														<t>
														</t>List<t></t> reverse(List<t></t> list) </p>
												<p>
														<strong>具体化<br /></strong>　　当实现一个泛型类时，您可能想要构造一个数组T[]。因为泛型是通过擦除(erasure)实现的，所以这是不允许的。 <br />　　您可以尝试把Object[]强制转换为T[]。但这是不安全的。 </p>
												<p>
														<strong>具体化解决方案<br />　　</strong>按照泛型教程的惯例，解决方案使用的是&#8220;类型令牌&#8221;，通过向构造函数添加一个Class<t></t>参数，可以强制客户端为类的类型参数提供正确的类对象： </p>
												<pre class="code">public class ArrayExample<t></t> {
    private Class<t></t> clazz;

    public ArrayExample(Class<t></t> clazz) {
        this.clazz = clazz;
    }

    public T[] getArray(int size) {
        return (T[])Array.newInstance(clazz, size);
    }
}</pre>
												<p>　　为了构造ArrayExample<string></string>，客户端必须把String.class传递给构造函数，因为String.class的类型是Class<string></string>。 <br />拥有类对象使构造一个具有正确元素类型的数组成为可能。 </p>
												<p>
														<strong>结束语</strong>
														<br />　　总而言之，新的语言特性有助于从根本上改变Java。通过了解在什么场景下使用以及如何使用这些新特性，您将会编写出更好的代码。</p>
												<p>
														<strong>补充阅读 </strong>
												</p>
												<ul>
														<li>
																<a href="http://java.sun.com/j2se/1.5.0/docs/guide/language/" target="_blank">
																		<font color="#002c99">Enhancements in JDK 5</font>
																</a>——JDK 5中新特性的官方列表 
</li>
														<li>
																<a href="http://java.sun.com/j2se/1.5/pdf/generics-tutorial.pdf" target="_blank">
																		<font color="#002c99">Generics Tutorial</font>
																</a>(PDF)——Gilad Bracha的泛型教程 
</li>
														<li>dev2dev <a href="http://dev2dev.bea.com/devcenters/" target="_blank"><font color="#002c99">Developer Centers</font></a></li>
												</ul>
												<p>&#160;</p>
												<p>
														<strong>原文出处:</strong>Experiences with the New Java 5 Language Features <a href="http://dev2dev.bea.com/pub/a/2005/09/java_5_features.html" target="_blank"><font color="#002c99">http://dev2dev.bea.com/pub/a/2005/09/java_5_features.html</font></a> &lt;!--文章其他信息--&gt;</p>
												<div class="dot001">
														<img height="1" alt="" src="http://dev2dev.bea.com.cn/images/_.gif" width="100%" />
												</div>
												<p>
												</p>
												<table cellspacing="0" cellpadding="3" width="100%" border="0">
														<tbody>
																<tr valign="bottom">
																		<td colspan="2" height="20">&#160;<span class="h2b">作者简介</span></td>
																</tr>
																<tr>
																		<td valign="top" align="middle">&#160;</td>
																		<td>
																				<a href="http://dev2dev.bea.com/pub/au/333" target="_blank">
																						<font color="#002c99">Jess Garms</font>
																				</a>是BEA Systems中Javelin编译器团队的领导者。在此之前，Jess致力于BEA的 Java IDE，WebLogic Workshop。此外，他在密码学方面也具有丰富的经验。他还与他人合著了&#8220;Professional Java Security&#8221;，由Wrox出版社出版。</td>
																</tr>
																<tr>
																		<td valign="top" align="middle">&#160;</td>
																		<td>
																				<a href="http://dev2dev.bea.com/pub/au/334" target="_blank">
																						<font color="#002c99">Tim Hanson</font>
																				</a>是BEA Systems中Javelin编译器的架构师。Tim对BEA的Java编译器做了很多开发工作，该编译器是最早兼容1.5的实现之一。他曾经编写过许多其他的编译器，包括他在IBM时编写的CORBA/IDL编译器，以及XQuery编译器。</td>
																</tr>
														</tbody>
												</table>
										</td>
								</tr>
						</tbody>
				</table>
		</div>
 <img src ="http://www.blogjava.net/balajinima/aggbug/146905.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/balajinima/" target="_blank">李云泽</a> 2007-09-20 20:10 <a href="http://www.blogjava.net/balajinima/articles/146905.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java Collection 学习笔记</title><link>http://www.blogjava.net/balajinima/articles/144901.html</link><dc:creator>李云泽</dc:creator><author>李云泽</author><pubDate>Thu, 13 Sep 2007 08:29:00 GMT</pubDate><guid>http://www.blogjava.net/balajinima/articles/144901.html</guid><wfw:comment>http://www.blogjava.net/balajinima/comments/144901.html</wfw:comment><comments>http://www.blogjava.net/balajinima/articles/144901.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/balajinima/comments/commentRss/144901.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/balajinima/services/trackbacks/144901.html</trackback:ping><description><![CDATA[
		<p>
				<br />支持类集的接口如下：<br />Collection<br />List<br />Set<br />SortedSet<br />Comparator 定义两个对象如何比较<br />Iterator 枚举类集中的对象<br />ListIterator枚举类集中的对象 <br />Collection接口（省略常用的方法）<br />Boolean add(Object obj) 添加一个Object元素<br />boolean addAll(Collection c) <br />boolean contains(Object obj)  判断obj是否是调用类集的一个元素（属于）<br />boolean containsAll(Collection c)  判断c是否是调用类集的子集（包含）<br />boolean equals(Collection c) 判断c是否与调用类集相等<br />int hashCode() 返回调用类集的hash码<br />Iterator iterator() 返回调用类集的迭代程序<br />boolean removeAll(Collection c) 从调用类集中去掉所有c中包含的元素（差集）<br />boolean retainAll(Collection c) 从调用类集中去掉包含在c中以外的元素（补集）<br />Object[] toArray() 返回类集的元素组成的数组<br /> <br />Void clear() <br />boolean isEmpty() <br />int size() </p>
		<p>类集包含一个add(Object obj)方法，因此可以包含任意Object数据，但是不能直接存储：int，char,Double等数据。可以使用下面的方法实现：<br />ArrayList a=new ArrayList();<br />a.add(new Integer(1));<br />a.add(new Integer(2));<br />……</p>
		<p>当类集不能被修改时，可能引发 UnsupportedOperationException异常。企图将一个不兼容的对象加入到一个类集中时可能引发ClassCastException异常。</p>
		<p>List接口（从Collection继承而来，使用基于0的下标）<br />void add(int index,Object obj) 插入点以后的元素将后移<br />boolean addAll(int index,Collection c) 如果调用列表改变了，返回true,否则返回false<br />Object get(int index) <br />int indexOf(Object obj) 返回obj对象在列表中的索引，不存在返回-1<br />int lastIndexOf(Object obj) 返回obj在列表中的最后一个实例的下标，不存在返回-1<br />ListIterator listIterator() <br />ListIterator listIterator(int index) 返回index开始的迭代程序<br />Object set(int index,Object obj) 对列表index处的值进行修改<br />List subList(int start,int end) 从start到end-1<br /> </p>
		<p>Set接口（从Collection派生，没有定义新的方法）<br />Set不允许有重复的元素。<br />对Set调用add（Object obj）方法，如果obj已经存在集合中，将返回false。</p>
		<p>SortedSet接口<br />Comparator comparator() 返回调用排序集合的比较函数，如果改集合使用自然顺序，则返回null<br />Object first() 返回被排序集合的第一个元素<br />SortedSet headSet(Object end) 返回一个包含小于end元素的SortedSet<br />Object last() 返回调用排序集合的最后一个元素<br />SortedSet subSet(Object start,Object end) 包括从start到end-1<br />SortedSet tailSet(Object start) 返回包含大于等于start的元素<br /> </p>
		<p>ArrayList扩展AstractList类，并执行List接口。ArrayList支持动态长度的数组。<br />LinkList扩展了AbstractSequentialList，执行List接口。提供连接列表。<br />HashSet扩展AbstractSet实现Set接口，元素没有顺序。对于大集合提供常量级基本操作。<br />TreeSet使用树来存储的Set，对象按升序存储。访问和检索非常快。</p>
		<p>iterator实现Iterator接口或者ListIterator接口。<br />Iterator接口<br />boolean hasNext() <br />Object next() 如果没有下一个元素则引发NoSuchElementException异常。<br />void remove() 删除当前元素，如果试图在调用next()方法后调用remove()方法则引发IllegalStateException异常。<br /> <br /> </p>
		<p>ListIterator接口<br />void add(Object obj) 将一个元素插入到当前元素之前，调用next()方法将返回该元素。<br />boolean hasNext() <br />boolean hasPrevious() <br />Object next() 如果不存在引发NoSuchElementException<br />int nextIndex() 如果不存在返回列表的大小<br />void remove() <br />void set(Object obj) 修改当前元素</p>
		<p>public void test1() {<br />  ArrayList al = new ArrayList();<br />  for (int i = 1; i &lt; 10; i++) {<br />  al.add("ArrayList Element:" + i);<br />  }<br />  Iterator itr = al.listIterator();<br />  while (itr.hasNext()) {<br />  Object obj = itr.next();<br />  System.out.println(obj);<br />  }<br />  }</p>
		<p>public void test2() {<br />  HashSet hs = new HashSet();<br />  System.out.println("HashSet");<br />  for (int i = 1; i &lt; 10; i++) {<br />  hs.add("HashSet Element:" + i);<br />  }<br />  Iterator itr = hs.iterator();<br />  while (itr.hasNext()) {<br />  Object obj = itr.next();<br />  System.out.println(obj);<br />  }<br />  }</p>
		<p>  public void test3() {<br />  TreeSet ts = new TreeSet();<br />  System.out.println("TreeSet");<br />  for (int i = 1; i &lt; 10; i++) {<br />  ts.add("TreeSet Element:" + i);<br />  }<br />  Iterator itr = ts.iterator();<br />  while (itr.hasNext()) {<br />  Object obj = itr.next();<br />  System.out.println(obj);<br />  }<br />  }</p>
		<p>  public void test4()<br />  {<br />  HashMap hm=new HashMap();<br />  for ( int i=0;i&lt;10;i++)<br />  {<br />  hm.put("item"+i,"value"+i);<br />  }</p>
		<p>  Set set=hm.entrySet();<br />  Iterator itr=set.iterator();<br />  while (itr.hasNext())<br />  {<br />  Map.Entry me=(Map.Entry)itr.next();<br />  System.out.println(me.getKey()+";"+me.getValue());<br />  }</p>
		<p>  hm.put("item5","modifyed value");<br />  System.out.println(hm.get("item5") );</p>
		<p>  set=hm.entrySet();<br />  itr=set.iterator();<br />  while (itr.hasNext())<br />  {<br />  Map.Entry me=(Map.Entry)itr.next();<br />  System.out.println(me.getKey()+";"+me.getValue());<br />  }</p>
		<p>  }</p>
		<p> </p>
		<p> </p>
<img src ="http://www.blogjava.net/balajinima/aggbug/144901.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/balajinima/" target="_blank">李云泽</a> 2007-09-13 16:29 <a href="http://www.blogjava.net/balajinima/articles/144901.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java反射机制</title><link>http://www.blogjava.net/balajinima/articles/144748.html</link><dc:creator>李云泽</dc:creator><author>李云泽</author><pubDate>Thu, 13 Sep 2007 02:38:00 GMT</pubDate><guid>http://www.blogjava.net/balajinima/articles/144748.html</guid><wfw:comment>http://www.blogjava.net/balajinima/comments/144748.html</wfw:comment><comments>http://www.blogjava.net/balajinima/articles/144748.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/balajinima/comments/commentRss/144748.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/balajinima/services/trackbacks/144748.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 摘要																								Reflection 						是						Java						被视为动态（或准动态）语言的一个关键性质。这个机制允许程序在运行时透过						Reflection APIs						取得任何一个已知名称的						class						的内部信息，包括其						modifie...&nbsp;&nbsp;<a href='http://www.blogjava.net/balajinima/articles/144748.html'>阅读全文</a><img src ="http://www.blogjava.net/balajinima/aggbug/144748.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/balajinima/" target="_blank">李云泽</a> 2007-09-13 10:38 <a href="http://www.blogjava.net/balajinima/articles/144748.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>抽象类与接口的区别</title><link>http://www.blogjava.net/balajinima/articles/144688.html</link><dc:creator>李云泽</dc:creator><author>李云泽</author><pubDate>Thu, 13 Sep 2007 01:03:00 GMT</pubDate><guid>http://www.blogjava.net/balajinima/articles/144688.html</guid><wfw:comment>http://www.blogjava.net/balajinima/comments/144688.html</wfw:comment><comments>http://www.blogjava.net/balajinima/articles/144688.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/balajinima/comments/commentRss/144688.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/balajinima/services/trackbacks/144688.html</trackback:ping><description><![CDATA[
		<p>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-ClosedPrinciple)，抽象类是其中的关键所在。 <br /> <br />从语法定义层面看abstract class和interface <br /> <br />在语法层面，Java语言对于abstract class和interface给出了不同的定义方式，下面以定义一个名为Demo的抽象类为例来说明这种不同。 <br /> <br />使用abstract class的方式定义Demo抽象类的方式如下： <br /> <br />abstract class Demo｛ <br /> <br />abstract void method1(); <br /> <br />abstract void method2(); <br /> <br />… <br /> <br />｝ <br /> <br />使用interface的方式定义Demo抽象类的方式如下： <br /> <br />interface Demo{ <br /> <br />void method1(); <br /> <br />void method2(); <br /> <br />… <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 />从设计理念层面看abstract class和interface <br /> <br />上面主要从语法定义和编程的角度论述了abstract class和interface的区别，这些层面的区别是比较低层次的、非本质的。本小节将从另一个层面：abstract class和interface所反映出的设计理念，来分析一下二者的区别。作者认为，从这个层面进行分析才能理解二者概念的本质所在。 <br /> <br />前面已经提到过，abstarct class在Java语言中体现了一种继承关系，要想使得继承关系合理，父类和派生类之间必须存在"isa"关系，即父类和派生类在概念本质上应该是相同的（参考文献〔3〕中有关于"isa"关系的大篇幅深入的论述，有兴趣的读者可以参考）。对于interface来说则不然，并不要求interface的实现者和interface定义在概念本质上是一致的，仅仅是实现了interface定义的契约而已。为了使论述便于理解，下面将通过一个简单的实例进行说明。 <br /> <br />考虑这样一个例子，假设在我们的问题领域中有一个关于Door的抽象概念，该Door具有执行两个动作open和close，此时我们可以通过abstract  class或者interface来定义一个表示该抽象概念的类型，定义方式分别如下所示： <br /> <br />使用abstract class方式定义Door： <br /> <br />abstract class Door{ <br /> <br />abstract void open(); <br /> <br />abstract void close()； <br /> <br />} <br /> <br />使用interface方式定义Door： <br /> <br />interface Door{ <br /> <br />void open(); <br /> <br />void close(); <br /> <br />} <br /> <br />其他具体的Door类型可以extends使用abstract  class方式定义的Door或者implements使用interface方式定义的Door。看起来好像使用abstract  class和interface没有大的区别。</p>
		<p> </p>
		<p>如果现在要求Door还要具有报警的功能。我们该如何设计针对该例子的类结构呢（在本例中，主要是为了展示abstract   class和interface反映在设计理念上的区别，其他方面无关的问题都做了简化或者忽略）？下面将罗列出可能的解决方案，并从设计理念层面对这些不同的方案进行分析。 <br /> <br />解决方案一： <br /> <br />简单的在Door的定义中增加一个alarm方法，如下： <br /> <br />abstract class Door{ <br /> <br />abstract void open(); <br /> <br />abstract void close()； <br /> <br />abstract void alarm(); <br /> <br />} <br /> <br />或者 <br /> <br />interface Door{ <br /> <br />void open(); <br /> <br />void close(); <br /> <br />void alarm(); <br /> <br />} <br /> <br />那么具有报警功能的AlarmDoor的定义方式如下： <br /> <br />class AlarmDoor  extends Door{ <br /> <br />void open(){…} <br /> <br />void close(){…} <br /> <br />void alarm(){…} <br /> <br />} <br /> <br />或者 <br /> <br />class  AlarmDoor implements  Door｛ <br /> <br />void  open(){…} <br /> <br />void  close(){…} <br /> <br />void  alarm(){…} <br /> <br />｝ <br /> <br />这种方法违反了面向对象设计中的一个核心原则ISP（InterfaceSegregationPriciple），在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语言中表示一种继承关系，而继承关系在本质上是"isa"关系。所以对于Door这个概念，我们应该使用abstarct class方式来定义。另外，AlarmDoor又具有报警功能，说明它又能够完成报警概念中定义的行为，所以报警概念可以通过interface方式定义。如下所示： <br /> <br />abstract  class  Door{ <br /> <br />abstract  void  open(); <br /> <br />abstract  void  close()； <br /> <br />} <br /> <br />interface  Alarm{ <br /> <br />void  alarm(); <br /> <br />} <br /> <br />class  AlarmDoor  extends  Door   implements  Alarm{ <br /> <br />void  open(){…} <br /> <br />void  close(){…} <br /> <br />void  alarm(){…} <br /> <br />} <br /> <br />这种实现方式基本上能够明确的反映出我们对于问题领域的理解，正确的揭示我们的设计意图。其实abstract  class表示的是"isa"关系，interface表示的是"likea"关系，大家在选择时可以作为一个依据，当然这是建立在对问题领域的理解上的，比如：如果我们认为AlarmDoor在概念本质上是报警器，同时又具有Door的功能，那么上述的定义方式就要反过来了。</p>
		<p> </p>
		<p> </p>
<img src ="http://www.blogjava.net/balajinima/aggbug/144688.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/balajinima/" target="_blank">李云泽</a> 2007-09-13 09:03 <a href="http://www.blogjava.net/balajinima/articles/144688.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java 读写txt文本文件(转发)</title><link>http://www.blogjava.net/balajinima/articles/140810.html</link><dc:creator>李云泽</dc:creator><author>李云泽</author><pubDate>Wed, 29 Aug 2007 03:01:00 GMT</pubDate><guid>http://www.blogjava.net/balajinima/articles/140810.html</guid><wfw:comment>http://www.blogjava.net/balajinima/comments/140810.html</wfw:comment><comments>http://www.blogjava.net/balajinima/articles/140810.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/balajinima/comments/commentRss/140810.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/balajinima/services/trackbacks/140810.html</trackback:ping><description><![CDATA[
		<p>
				<br />读取所有的文件数据<br />&lt;%@ page contentType="text/html;charset=gb2312"%&gt;<br />&lt;%@ page import="java.io.*,java.lang.*"%&gt;<br />&lt;html&gt;<br />&lt;head&gt;<br />&lt;title&gt;读取所有的文件数据&lt;/title&gt;<br />&lt;/head&gt;<br />&lt;body&gt;<br />&lt;%<br />String path=request.getRealPath(".");<br />FileReader fr=new FileReader(path + "<a href="file://ReadData.txt/">file://ReadData.txt/</a>");<br />//关键在于读取过程中，要判断所读取的字符是否已经到了文件的末尾，并且这个字符是不是文件中的断行符，即判断该字符值是否为13。<br />int c=fr.read();//从文件中读取一个字符<br />//判断是否已读到文件结尾<br />while(c!=-1){<br /> out.print((char)c);//输出读到的数据<br /> c=fr.read();//从文件中继续读取数据<br /> if(c==13){//判断是否为断行字符<br />  out.print("&lt;br&gt;");//输出分行标签<br />  fr.skip(1);//略过一个字符<br />  //c=fr.read();//读取一个字符<br /> }<br />}<br />fr.close();<br />%&gt;<br />&lt;/body&gt;<br />&lt;/html&gt;</p>
		<p>一行一行读取数据<br />&lt;%@ page contentType="text/html;charset=gb2312"%&gt;<br />&lt;%@ page import="java.io.*"%&gt;<br />&lt;html&gt;<br />&lt;head&gt;<br />&lt;title&gt;文件读取&lt;/title&gt;<br />&lt;/head&gt;<br />&lt;body&gt;<br />&lt;%<br /> String path=request.getRealPath("");//取得当前目录的路径<br /> FileReader fr=new FileReader(path + "<a href="file://file//inc//t.txt%22);//">file://file//inc//t.txt%22);//</a>建立FileReader对象，并实例化为fr<br /> BufferedReader br=new BufferedReader(fr);//建立BufferedReader对象，并实例化为br<br /> String Line=br.readLine();//从文件读取一行字符串<br /> //判断读取到的字符串是否不为空<br /> while(Line!=null){<br />  out.println(Line + "&lt;br&gt;");//输出从文件中读取的数据<br />  Line=br.readLine();//从文件中继续读取一行数据<br /> }<br /> br.close();//关闭BufferedReader对象<br /> fr.close();//关闭文件<br />%&gt;<br />&lt;/body&gt;<br />&lt;/html&gt;</p>
		<p>略过文件中的字符不读取<br />&lt;%@ page contentType="text/html;charset=gb2312"%&gt;<br />&lt;%@ page import="java.io.*"%&gt;<br />&lt;html&gt;<br />&lt;head&gt;<br />&lt;title&gt;略过字节不读取&lt;/title&gt;<br />&lt;/head&gt;<br />&lt;body&gt;<br />&lt;%<br />String path=request.getRealPath(".");<br />FileReader fr=new FileReader(path + "<a href="file://ReadData.txt/">file://ReadData.txt/</a>");<br />fr.skip(2);//跳过2个字节<br />int c=fr.read();//读取一个字节<br />while(c!=-1){<br /> out.print((char)c);<br /> c=fr.read();<br />}<br />fr.close();<br />%&gt;<br />&lt;/body&gt;<br />&lt;/html&gt;</p>
		<p>将数据写入文件<br />&lt;%@ page contentType="text/html;charset=gb2312"%&gt;<br />&lt;%@ page import="java.io.*"%&gt;<br />&lt;html&gt;<br />&lt;head&gt;<br />&lt;title&gt;将数据写入文件&lt;/title&gt;<br />&lt;/head&gt;<br />&lt;body&gt;<br />&lt;%<br />String path=request.getRealPath(".");<br />FileWriter fw=new FileWriter(path + "<a href="file://WriteData.txt%22);//">file://WriteData.txt%22);//</a>建立FileWriter对象，并实例化fw<br />//将字符串写入文件<br />fw.write("大家好！");<br />fw.write("本书是《JSP编程技巧》");<br />fw.write("请多多指教！");<br />fw.write("email:stride@sina.com");<br />fw.close();<br />FileReader fr=new FileReader(path + "<a href="file://WriteData.txt/">file://WriteData.txt/</a>");<br />BufferedReader br=new BufferedReader(fr);//建立BufferedReader对象，并实例化为br<br />String Line=br.readLine();<br />//读取一行数据<br />out.println(Line + "&lt;br&gt;");<br />br.close();//关闭BufferedReader对象<br />fr.close();<br />%&gt;<br />&lt;/body&gt;<br />&lt;/html&gt;</p>
		<p>将写入文件的数据分行<br />&lt;%@ page contentType="text/html;charset=gb2312"%&gt;<br />&lt;%@ page import="java.io.*"%&gt;<br />&lt;html&gt;<br />&lt;head&gt;<br />&lt;title&gt;将写入文件的数据分行&lt;/title&gt;<br />&lt;/head&gt;<br />&lt;body&gt;<br />&lt;%<br />String path=request.getRealPath(".");<br />FileWriter fw=new FileWriter(path + "<a href="file://WriteData.txt/">file://WriteData.txt/</a>");<br />BufferedWriter bw=new BufferedWriter(fw);<br />bw.write("大家好！");<br />bw.write("本书是《JSP编程技巧》。");<br />bw.newLine();//断行<br />bw.write("请多多指教！");<br />bw.newLine();//断行<br />bw.write("email: <a href="mailto:stride@sina.com">stride@sina.com</a>");<br />bw.flush();//将数据更新至文件<br />fw.close();//关闭文件流<br />out.println("写入文件内容为：&lt;br&gt;");<br />FileReader fr=new FileReader(path + "<a href="file://WriteData.txt/">file://WriteData.txt/</a>");<br />BufferedReader br=new BufferedReader(fr);<br />String Line=br.readLine();//读取一行数据<br />while(Line!=null){<br /> out.println(Line + "&lt;br&gt;");<br /> Line=br.readLine();<br />}<br />fr.close();<br />%&gt;<br />&lt;/body&gt;<br />&lt;/html&gt;</p>
		<p>如何将数据追加写入到文件<br />&lt;%@ page contentType="text/html;charset=gb2312"%&gt;<br />&lt;%@ page import="java.io.*"%&gt;<br />&lt;html&gt;<br />&lt;head&gt;<br />&lt;title&gt;将写入文件的数据分行&lt;/title&gt;<br />&lt;/head&gt;<br />&lt;body&gt;<br />&lt;%<br />String path=request.getRealPath(".");<br />RandomAccessFile rf=new RandomAccessFile(path + "<a href="file://WriteData.txt%22,%22rw%22);//">file://WriteData.txt%22,%22rw%22);//</a>定义一个类RandomAccessFile的对象，并实例化<br />rf.seek(rf.length());//将指针移动到文件末尾<br />rf.writeBytes("\nAppend a line to the file!");<br />rf.close();//关闭文件流<br />out.println("写入文件内容为：&lt;br&gt;");<br />FileReader fr=new FileReader(path + "<a href="file://WriteData.txt/">file://WriteData.txt/</a>");<br />BufferedReader br=new BufferedReader(fr);//读取文件的BufferedRead对象<br />String Line=br.readLine();<br />while(Line!=null){<br /> out.println(Line + "&lt;br&gt;");<br /> Line=br.readLine();<br />}<br />fr.close();//关闭文件<br />%&gt;<br />&lt;/body&gt;<br />&lt;/html&gt;<br /> <br />import java.util.*;<br />import java.io.*;<br />public class ReadIni<br />{<br />  public static void main(String[] args)<br />    throws Exception<br />  {<br />    Properties proDB = new Properties();<br />    FileInputStream in = new FileInputStream("DBConfig.ini");<br />    proDB.load(in);<br />    String jdbc = proDB.getProperty("jdbc");<br />    String dburl = proDB.getProperty("dburl");<br />    String userid = proDB.getProperty("userid");<br />    String password = proDB.getProperty("password"); </p>
		<p>    System.out.println(jdbc);<br />    System.out.println(dburl);<br />    System.out.println(userid);<br />    System.out.println(password);<br />  }<br />} </p>
		<p>DBConfig.ini: </p>
		<p>dburl=jdbcracle:thin:@202.16.147.104:1521ub<br />userid=user<br />password=password<br />jdbc=oracle.jdbc.driver.OracleDriver</p>
		<p> </p>
<img src ="http://www.blogjava.net/balajinima/aggbug/140810.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/balajinima/" target="_blank">李云泽</a> 2007-08-29 11:01 <a href="http://www.blogjava.net/balajinima/articles/140810.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>