??xml version="1.0" encoding="utf-8" standalone="yes"?>亚洲第一综合天堂另类专,中文字幕乱码亚洲精品一区,亚洲日产无码中文字幕http://www.tkk7.com/balajinima/category/24467.htmlzh-cnTue, 03 Nov 2009 08:20:18 GMTTue, 03 Nov 2009 08:20:18 GMT60Java对象的序列化和反序列化实?/title><link>http://www.tkk7.com/balajinima/articles/286124.html</link><dc:creator>李云?/dc:creator><author>李云?/author><pubDate>Thu, 09 Jul 2009 09:52:00 GMT</pubDate><guid>http://www.tkk7.com/balajinima/articles/286124.html</guid><wfw:comment>http://www.tkk7.com/balajinima/comments/286124.html</wfw:comment><comments>http://www.tkk7.com/balajinima/articles/286124.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.tkk7.com/balajinima/comments/commentRss/286124.html</wfw:commentRss><trackback:ping>http://www.tkk7.com/balajinima/services/trackbacks/286124.html</trackback:ping><description><![CDATA[<p> </p>   <div class="6111111" id="artibody"><!-- Error --> <div id="1611611" class="clear1">  当两个进E在q行q程通信Ӟ彼此可以发送各U类型的数据。无论是何种cd的数据,都会以二q制序列的Ş式在|络上传送。发送方需要把q个Java对象转换为字节序列,才能在网l上传送;接收方则需要把字节序列再恢复ؓJava对象?<br /> <br />   把Java对象转换为字节序列的q程UCؓ对象的序列化?br /> <br />   把字节序列恢复ؓJava对象的过E称为对象的反序列化?br /> <br />   对象的序列化主要有两U用途:<br /> <br />   1Q?把对象的字节序列怹C存到<a class="fllink" target="_bank">盘</a>上,通常存放在一个文件中Q?br /> <br />   2Q?在网l上传送对象的字节序列?br /> <br />   <strong>一Q?JDKcd中的序列化API</strong><br /> <br />   java.io.ObjectOutputStream代表对象输出,它的writeObject(Object obj)Ҏ可对参数指定的obj对象q行序列化,把得到的字节序列写到一个目标输出流中?br /> <br />   java.io.ObjectInputStream代表对象输入,它的readObject()Ҏ从一个源输入中d字节序列Q再把它们反序列化ؓ一个对象,q将其返回。?br /> <br />   只有实现了Serializable和Externalizable接口的类的对象才能被序列化。Externalizable接口l承自Serializable接口Q实现Externalizable接口的类完全pw来控制序列化的行ؓQ而仅实现Serializable接口的类可以采用默认的序列化方式 ?br /> <br />   对象序列化包括如下步骤:<br /> <br />   1Q?创徏一个对象输出流Q它可以包装一个其他类型的目标输出,如文件输出流Q?br /> <br />   2Q?通过对象输出的writeObject()Ҏ写对象?br /> <br />   对象反序列化的步骤如下:<br /> <br />   1Q?创徏一个对象输入流Q它可以包装一个其他类型的源输入流Q如文g输入;<br /> <br />   2Q?通过对象输入的readObject()Ҏd对象?br /> <br />   下面让我们来看一个对应的例子Q类的内容如下:<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 <a href="mailto:xiexingxing1121@126.com">AmigoXie</a><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 <a href="mailto:xiexingxing1121@126.com">AmigoXie</a><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); //写入基本cd数据<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 />   输出l果如下Q?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接口的类的对象进行序列化。默认情况下QObjectOutputStream按照默认方式序列化,q种序列化方式仅仅对对象的非transient的实例变量进行序列化Q而不会序列化对象的transient的实例变量,也不会序列化静态变量?br /> <br />   当ObjectOutputStream按照默认方式反序列化Ӟh如下特点Q?br /> <br />   1Q?如果?a class="fllink" target="_bank">内存</a>中对象所属的c还没有被加载,那么会先加蝲q初始化q个cR如果在classpath中不存在相应的类文gQ那么会抛出ClassNotFoundExceptionQ?br /> <br />   2Q?在反序列化时不会调用cȝM构造方法?br /> <br />   如果用户希望控制cȝ序列化方式,可以在可序列化类中提供以下Ş式的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对象q行序列化时Q如果该对象hwriteObject()ҎQ那么就会执行这一ҎQ否则就按默认方式序列化。在该对象的writeObjectt()Ҏ中,可以先调用ObjectOutputStream的defaultWriteObject()ҎQ得对象输出流先执行默认的序列化操作。同理可得出反序列化的情况,不过q次是defaultReadObject()Ҏ?br /> <br />   有些对象中包含一些敏感信息,q些信息不宜对外公开。如果按照默认方式对它们序列化,那么它们的序列化数据在网l上传输Ӟ可能会被不法份子H取。对于这cM息,可以对它们进行加密后再序列化Q在反序列化时则需要解密,再恢复ؓ原来的信息?br /> <br />   默认的序列化方式会序列化整个对象图,q需要递归遍历对象图。如果对象图很复杂,递归遍历操作需要消耗很多的I间和时_它的内部数据l构为双向列表?br /> <br />   在应用时Q如果对某些成员变量都改为transientcdQ将节省I间和时_提高序列化的性能?br /> <br />   <strong>三. 实现Externalizable接口</strong><br /> <br />   Externalizable接口l承自Serializable接口Q如果一个类实现了Externalizable接口Q那么将完全p个类控制自n的序列化行ؓ。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 />   前者负责序列化操作Q后者负责反序列化操作?br /> <br />   在对实现了Externalizable接口的类的对象进行反序列化时Q会先调用类的不带参数的构造方法,q是有别于默认反序列方式的。如果把cȝ不带参数的构造方法删除,或者把该构造方法的讉K权限讄为private、默认或protectedU别Q会抛出java.io.InvalidException: no valid constructor异常?br /> <br />   <strong>四. 可序列化cȝ不同版本的序列化兼容?/strong><br /> <br />   凡是实现Serializable接口的类都有一个表C序列化版本标识W的静态变量:<br /> <br /> <table width="90%" bgcolor="#d8d7d3" align="center"> <tbody> <tr> <td>private static final long serialVersionUID;</td> </tr> </tbody> </table> <br />   以上serialVersionUID的取值是Javaq行时环境根据类的内部细节自动生成的。如果对cȝ源代码作了修改,再重新编译,新生成的cL件的serialVersionUID的取值有可能也会发生变化?br /> <br />   cȝserialVersionUID的默认值完全依赖于Java~译器的实现Q对于同一个类Q用不同的Java~译器编译,有可能会D不同的serialVersionUIDQ也有可能相同。ؓ了提高哦啊serialVersionUID的独立性和定性,强烈在一个可序列化类中显C的定义serialVersionUIDQؓ它赋予明的倹{显式地定义serialVersionUID有两U用途:<br /> <br />   1Q?在某些场合,希望cȝ不同版本对序列化兼容Q因此需要确保类的不同版本具有相同的serialVersionUIDQ?br /> <br />   2Q?在某些场合,不希望类的不同版本对序列化兼容,因此需要确保类的不同版本具有不同的serialVersionUID?br /> </div> </div> <img src ="http://www.tkk7.com/balajinima/aggbug/286124.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.tkk7.com/balajinima/" target="_blank">李云?/a> 2009-07-09 17:52 <a href="http://www.tkk7.com/balajinima/articles/286124.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> List排序Q{载)http://www.tkk7.com/balajinima/articles/264418.html李云?/dc:creator>李云?/author>Wed, 08 Apr 2009 03:33:00 GMThttp://www.tkk7.com/balajinima/articles/264418.htmlhttp://www.tkk7.com/balajinima/comments/264418.htmlhttp://www.tkk7.com/balajinima/articles/264418.html#Feedback0http://www.tkk7.com/balajinima/comments/commentRss/264418.htmlhttp://www.tkk7.com/balajinima/services/trackbacks/264418.html 

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.CollationKey;
import java.text.Collator;
import java.text.RuleBasedCollator;
import java.util.*;


/**
 * <strong>Title : ListComparator </strong>. <br>
 * <strong>Description : List排序器(支持中文排序Q?</strong> <br>
  */
public class ListComparator implements Comparator {


 /**
  * <code>collator</code> - 排序规则控制?
  */
 private RuleBasedCollator collator = (RuleBasedCollator) Collator
   .getInstance(java.util.Locale.CHINA);

 /**
  * <code>methodName</code> - 排序字段的方法名.
  */
 private String methodName;

 /**
  * <code>seq</code> - 排序序.
  */
 private String seq;

 /**
  * <code>methodeArgs</code> - Ҏ参数.
  */
 private Object[] methodeArgs;

 /**
  * 构造函?List中存攑֤杂对象,q且获得排序字段值的Ҏ需要参?.
  *
  * @param methodName
  *            -对象中的Ҏ?br />  * @param methodeArgs
  *            -Ҏ参数
  * @param seq
  *            -排序序
  * @throws Exception
  */
 public ListComparator(String methodName, Object[] methodeArgs, String seq)
   throws Exception {

  this.methodName = methodName;

  this.methodeArgs = methodeArgs;

  if (!"asc".equalsIgnoreCase(seq) && !"desc".equalsIgnoreCase(seq)) {

   throw new Exception("illegal value of parameter 'seq' for input '"
     + seq + "'");
  }

  this.seq = seq;
 }

 /**
  * 构造函?List中存攑֤杂对象,q且获得排序字段值的Ҏ不需要参?.
  *
  * @param methodName
  * @param seq
  * @throws Exception
  */
 public ListComparator(String methodName, String seq) throws Exception {

  this.methodName = methodName;

  if (!"asc".equalsIgnoreCase(seq) && !"desc".equalsIgnoreCase(seq)) {

   throw new Exception("illegal value of parameter 'seq' for input '"
     + seq + "'");
  }

  this.seq = seq;

 }

 /**
  * 构造函?List中存攄单对?.
  *
  * @param seq
  * @throws Exception
  */
 public ListComparator(String seq) throws Exception {

  if (!"asc".equalsIgnoreCase(seq) && !"desc".equalsIgnoreCase(seq)) {

   throw new Exception("illegal value of parameter 'seq' for input '"
     + seq + "'");
  }

  this.seq = seq;
 }

 /**
  * (non-Javadoc).
  *
  * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
  */
 public int compare(Object obj1, Object obj2) {

  int t_ret = 0;

  // 如果指定了方法名Q则表示List中存攄是复杂对?br />  if (this.methodName != null && !"".equals(this.methodName)) {

   // 执行Bean中的ҎQ得到方法返回的对象
   Object t_obj1 = invokeMethod(obj1, this.methodName,
     this.methodeArgs);
   Object t_obj2 = invokeMethod(obj2, this.methodName,
     this.methodeArgs);

   t_ret = selectCompare(t_obj1, t_obj2);

  } else {

   t_ret = selectCompare(obj1, obj2);

  }

  return t_ret;
 }

 /**
  * 执行对象的某个方?
  *
  * @param owner
  *            -对象
  * @param methodName
  *            -Ҏ?br />  * @param methodArgs
  *            -Ҏ参数
  *
  * @return Ҏq回对象
  * @throws InvocationTargetException
  * @throws IllegalAccessException
  * @throws IllegalArgumentException
  * @throws Exception
  */
 private Object invokeMethod(Object owner, String methodName,
   Object[] methodArgs) {

  Class[] argsClass = null;

  if (methodArgs != null && methodArgs.length > 0) {

   argsClass = new Class[methodeArgs.length];

   for (int i = 0, j = methodeArgs.length; i < j; i++) {

    argsClass[i] = methodeArgs[i].getClass();
   }
  }

  Class ownerClass = owner.getClass();

  Method method;
  Object t_object = null;
  try {
   method = ownerClass.getMethod(methodName, argsClass);
   t_object = method.invoke(owner, methodArgs);
  } catch (SecurityException e) {
  } catch (NoSuchMethodException e) {

   argsClass = new Class[1];
   argsClass[0] = Object.class;
   try {
    method = ownerClass.getMethod(methodName, argsClass);
    t_object = method.invoke(owner, methodArgs);
   } catch (SecurityException e1) {
   } catch (NoSuchMethodException e1) {
   } catch (IllegalArgumentException e1) {
   } catch (IllegalAccessException e1) {
   } catch (InvocationTargetException e1) {
   }

  } catch (IllegalArgumentException e) {
  } catch (IllegalAccessException e) {
  } catch (InvocationTargetException e) {
  }

  return t_object;
 }


 private int selectCompare(Object obj1, Object obj2) {

  int t_ret = 0;

  if (obj1 instanceof String && obj2 instanceof String) {

   t_ret = compareString(obj1, obj2);
  }

  if (obj1 instanceof Integer && obj2 instanceof Integer) {

   t_ret = compareInt(obj1, obj2);
  }

  if (obj1 instanceof Long && obj2 instanceof Long) {

   t_ret = compareLong(obj1, obj2);
  }

  if (obj1 instanceof Date && obj2 instanceof Date) {

   t_ret = compareDate(obj1, obj2);
  }

  return t_ret;
 }

 private int compareString(Object obj1, Object obj2) {

  int ret = 0;

  String s1 = (String) obj1;
  String s2 = (String) obj2;

  CollationKey c1 = collator.getCollationKey(s1);
  CollationKey c2 = collator.getCollationKey(s2);

  ret = collator.compare(c1.getSourceString(), c2.getSourceString());

  if (seq.equalsIgnoreCase("desc")) {

   ret = ret * -1;
  }

  return ret;
 }

 private int compareInt(Object obj1, Object obj2) {

  int ret = 0;

  int i1 = ((Integer) obj1).intValue();
  int i2 = ((Integer) obj2).intValue();

  if (i1 < i2)
   ret = -1;
  else if (i1 > i2)
   ret = 1;
  else
   ret = 0;

  if (seq.equalsIgnoreCase("desc")) {

   ret = ret * -1;
  }

  return ret;
 }

 private int compareLong(Object obj1, Object obj2) {

  int ret = 0;

  long l1 = ((Long) obj1).longValue();
  long l2 = ((Long) obj2).longValue();

  if (l1 < l2)
   ret = -1;
  else if (l1 > l2)
   ret = 1;
  else
   ret = 0;

  if (seq.equalsIgnoreCase("desc")) {

   ret = ret * -1;
  }

  return ret;
 }

 private int compareDate(Object obj1, Object obj2) {

  int ret = 0;

  Date d1 = (Date) obj1;
  Date d2 = (Date) obj2;

  ret = d1.compareTo(d2);

  if (seq.equalsIgnoreCase("desc")) {

   ret = ret * -1;
  }

  return ret;
 }
}



-------------------------------------------------------------------
使用
-------------------------------------------------------------------
private List getSortedList(List unsortedList, String methodName,
   Object methodArgs[], String orderSequence) throws Exception {

  ListComparator t_compare = null;

  if (null != methodName && !"".equals(methodName)) {

   if (methodArgs != null && methodArgs.length > 0)
    t_compare = new ListComparator(methodName, methodArgs,
      orderSequence);
   else
    t_compare = new ListComparator(methodName, orderSequence);
  } else {
   t_compare = new ListComparator(orderSequence);
  }

  List t_list = unsortedList;

  Collections.sort(t_list, t_compare);

  return t_list;
 }





]]>
Java中集合类的区?/title><link>http://www.tkk7.com/balajinima/articles/200872.html</link><dc:creator>李云?/dc:creator><author>李云?/author><pubDate>Fri, 16 May 2008 04:57:00 GMT</pubDate><guid>http://www.tkk7.com/balajinima/articles/200872.html</guid><wfw:comment>http://www.tkk7.com/balajinima/comments/200872.html</wfw:comment><comments>http://www.tkk7.com/balajinima/articles/200872.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.tkk7.com/balajinima/comments/commentRss/200872.html</wfw:commentRss><trackback:ping>http://www.tkk7.com/balajinima/services/trackbacks/200872.html</trackback:ping><description><![CDATA[Array是数l?不在集合框架范畴之内,一旦选定?它的定w大小׃能改变了,所以通常在编E中不选用数组来存? <br /><br />集合 : <br />集合对象Q用于管理其他若q对象的对象 <br />数组Q长度不可变 <br /><br />List: 有顺序的Q元素可以重?<br />遍历Qfor q代 <br />排序QComparable Comparator Collections.sort() <br />ArrayListQ底层用数组实现的List <br />特点Q查询效率高Q增删效率低 轻量U?U程不安?<br />LinkedListQ底层用双向循环链表 实现的List <br />特点Q查询效率低Q增删效率高 <br />Vector: 底层用数l实现List接口的另一个类 <br />特点Q重量Q占据更多的pȝ开销 U程安全 <br /><br />SetQ无序的,元素不可重复Qg相同Q?<br />遍历QP?<br />排序QSortedSet <br />HashSetQ采用哈希算法来实现Set接口 <br />唯一性保证:重复对象equalsҎq回为true <br />重复对象hashCodeҎq回相同的整?<br />不同对象 哈希?量保证不同Q提高效率) <br /><br />SortedSetQ对一个Set排序 <br />TreeSetQ在元素d的同Ӟq行排序。也要给出排序规?<br />唯一性保证:Ҏ排序规则QcompareToҎq回?Q就可以认定两个对象中有一个是重复对象?<br /><br />MapQ元素是键值对 keyQ唯一Q不可重?valueQ可重复 <br />遍历Q先q代遍历key的集合,再根据key得到value <br />HashMap:轻量U?U程不安?允许key或者value是null <br />HashtableQ重量 U程安全 不允许key或者value是null <br />PropertiesQHashtable的子c,key和value都是String <br /><br />SortedMapQ元素自动对key排序 <br />TreeMapQ?<br /><br />集合是指一个对象可以容U了多个对象Q不是引用)Q这个集合对象主要用来管理维护一pd怼的对象?<br /><br />集合接口cd?: <br />位于package java.util.*; <br />Collection <br />?<br />|ˉˉˉˉˉˉ| <br />Set List Map <br />??<br />| | <br />SortedSet SortedMap <br /><br />1) Set: 集合cM不允许有重复对象; <br />2) SortedSet: 和Set接口同,但元素按升序排列; <br />3) List: 元素加蝲和移出时按照序Q可以保存重复对象?<br />4) Map: (key-value?存储了唯一关键字L识和对应的倹{?<br />5) SortedMap: 和MapcdQ但对象按他们关键字的升序排列?<br /><br />集合cd?: <br />Q注QJAVA1.5对JAVA1.4的最大改q就是增加了对范型的支持Q?<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 />1QArrayList: 元素单个Q效率高Q多用于查询 <br />2QVector: 元素单个Q线E安全,多用于查?<br />3QLinkedList:元素单个Q多用于插入和删?<br />4QHashMap: 元素成对Q元素可为空 <br />5QHashTable: 元素成对Q线E安全,元素不可为空 <br /><br />ArrayList <br />底层是Object数组Q所以ArrayListh数组的查询速度快的优点以及增删速度慢的~点?<br />而在LinkedList的底层是一U双向@环链表。在此链表上每一个数据节炚w׃部分l成Q前指针Q指向前面的节点的位|)Q数据,后指针(指向后面的节点的位置Q。最后一个节点的后指针指向第一个节点的前指针,形成一个@环?<br />双向循环链表的查询效率低但是增删效率高?<br />ArrayList和LinkedList在用法上没有区别Q但是在功能上还是有区别的?<br /><br />LinkedList <br />l常用在增删操作较多而查询操作很的情况下:队列和堆栈?<br />队列Q先q先出的数据l构?<br />栈:后进先出的数据结构?<br />注意Q用栈的时候一定不能提供方法让不是最后一个元素的元素获得出栈的机会?<br /><br />Vector <br />Q与ArrayList怼Q区别是Vector是重量的组Ӟ使用使消耗的资源比较多。) <br />l论Q在考虑q发的情况下用VectorQ保证线E的安全Q?<br />在不考虑q发的情况下用ArrayListQ不能保证线E的安全Q?<br /><br /><br />java.util.stackQstack即ؓ堆栈Q的父类为Vector。可是stack的父cL最不应该ؓVector的。因为Vector的底层是数组Q且Vector有getҎQ意味着它可能访问到q不属于最后一个位|元素的其他元素Q很不安全)?<br />对于堆栈和队列只能用pushcdgetcR?<br />StackcM后不要轻易用?<br />实现栈一定要用LinkedList?<br />Q在JAVA1.5中,collection有queue来实现队列。) <br /><br />Set-HashSet实现c: <br />遍历一个Set的方法只有一个:q代器(interatorQ?<br />HashSet中元素是无序的(q个无序指的是数据的d序和后来的排列序不同Q,而且元素不可重复?<br />在Object中除了有finalize()QtoString()Qequals()Q还有hashCode()?<br />HashSet底层用的也是数组?<br />当向数组中利用add(Object o)d对象的时候,pȝ先找对象的hashCodeQ?<br />int hc=o.hashCode(); q回的hashCode为整数倹{?<br />Int I=hc%n;Qn为数l的长度Q,取得余数后,利用余数向数l中相应的位|添加数据,以n?ZQ如果I=0则放在数la[0]位置Q如果I=1,则放在数la[1]位置。如果equals()q回的gؓtrueQ则说明数据重复。如果equals()q回的gؓfalseQ则再找其他的位|进行比较。这L机制导致两个相同的对象有可能重复地d到数l中Q因Z们的hashCode不同?<br />如果我们能够使两个相同的对象h相同hashcodeQ才能在equals()q回为真?<br />在实例中Q定义student对象时覆盖它的hashcode?<br />因ؓStringcL自动覆盖的,所以当比较Stringcȝ对象的时候,׃会出现有两个相同的string对象的情c?<br />现在Q在大部分的JDK中,都已l要求覆盖了hashCode?<br />l论Q如自定义cȝhashSet来添加对象,一定要覆盖hashcode()和equals()Q覆盖的原则是保证当两个对象hashcodeq回相同的整敎ͼ而且equals()q回gؓTrue?<br />如果hQ没有设定equals()Q就会造成q回hashCode虽然l果相同Q但在程序执行的q程中会多次地调用equals()Q从而媄响程序执行的效率?<br /><br />我们要保证相同对象的q回的hashCode一定相同,也要保证不相同的对象的hashCode可能不同(因ؓ数组的边界性,hashCodeq是可能相同的)?<br /><br />例子Q?<br />public int hashCode(){ <br />return name.hashcode()+age; <br />} <br />q个例子保证了相同姓名和q龄的记录返回的hashCode是相同的?<br /><br />使用hashSet的优点: <br />hashSet的底层是数组Q其查询效率非常高。而且在增加和删除的时候由于运用的hashCode的比较开定d元素的位|,所以不存在元素的偏U,所以效率也非常高。因为hashSet查询和删除和增加元素的效率都非常高?<br />但是hashSet增删的高效率是通过p大量的空间换来的Q因为空间越大,取余数相同的情况p。HashSetq种法会徏立许多无用的I间?<br />使用hashSetcL要注意,如果发生冲突Q就会出现遍历整个数l的情况Q这样就使得效率非常的低?<br /><br />1.1.4. 比较 <br />Collectionsc(工具cZ――全是static ҎQ?<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 />Ҏ一Q?<br />Comparator接口 <br />Int compare(Object a,Object b) <br />Boolean equals(Object o) <br />例子Q?<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&&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.tkk7.com/balajinima/aggbug/200872.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.tkk7.com/balajinima/" target="_blank">李云?/a> 2008-05-16 12:57 <a href="http://www.tkk7.com/balajinima/articles/200872.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>javaE序的内存分?/title><link>http://www.tkk7.com/balajinima/articles/182203.html</link><dc:creator>李云?/dc:creator><author>李云?/author><pubDate>Tue, 26 Feb 2008 05:38:00 GMT</pubDate><guid>http://www.tkk7.com/balajinima/articles/182203.html</guid><wfw:comment>http://www.tkk7.com/balajinima/comments/182203.html</wfw:comment><comments>http://www.tkk7.com/balajinima/articles/182203.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.tkk7.com/balajinima/comments/commentRss/182203.html</wfw:commentRss><trackback:ping>http://www.tkk7.com/balajinima/services/trackbacks/182203.html</trackback:ping><description><![CDATA[     摘要: Q最q感觉自己对java好无知啊Q以下是转自|络上的文章Q以供自己学?..........Q? JAVA 文g~译执行与虚拟机(JVM)介绍 Java 虚拟?JVM)是可q行Java代码的假惌机。只要根据JVM规格描述解释器UL到特定的计算ZQ就能保证经q编译的...  <a href='http://www.tkk7.com/balajinima/articles/182203.html'>阅读全文</a><img src ="http://www.tkk7.com/balajinima/aggbug/182203.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.tkk7.com/balajinima/" target="_blank">李云?/a> 2008-02-26 13:38 <a href="http://www.tkk7.com/balajinima/articles/182203.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>String和StringBuffer之概?/title><link>http://www.tkk7.com/balajinima/articles/166913.html</link><dc:creator>李云?/dc:creator><author>李云?/author><pubDate>Tue, 11 Dec 2007 05:32:00 GMT</pubDate><guid>http://www.tkk7.com/balajinima/articles/166913.html</guid><wfw:comment>http://www.tkk7.com/balajinima/comments/166913.html</wfw:comment><comments>http://www.tkk7.com/balajinima/articles/166913.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.tkk7.com/balajinima/comments/commentRss/166913.html</wfw:commentRss><trackback:ping>http://www.tkk7.com/balajinima/services/trackbacks/166913.html</trackback:ping><description><![CDATA[String和StringBuffer之概?br />  非可变对象一旦创Z后就不能再被改变Q可变对象则可以在创Z后被改变。String对象是非可变对象QStringBuffer对象则是可变对象。ؓ获得更佳的性能你需要根据实际情况小心}慎地选择到底使用q两者中的某一个。下面的话题会作详细的阐q。(注意Q这个章节假设读者已l具备Java的String和StringBuffer的相兛_知识。)<br /> <br />创徏字符串的较佳途径<br />你可以按照以下方式创建字W串对象Q?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<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<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 />q段代码的输出:<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虚拟Zl护一个内部的滞留字符串对象的列表Q唯一字符串的池)来避免在堆内存中产生重复的String对象。当JVM从class文g里加载字W串字面量ƈ执行的时候,它会先检查一下当前的字符串是否已l存在于滞留字符串列表,如果已经存在Q那׃会再创徏一个新的String对象而是引用指向已l存在的String对象QJVM会在内部为字W串字面量作q种查,但ƈ不会为通过new关键字创建的String对象作这U检查。当然你可以明确C用String.intern()Ҏ强制JVM为通过 new关键字创建的String对象作这L查。这样可以强制JVM查内部列表而用已有的String对象?br />  所以结论是QJVM会内在地为字W串字面量维护一些唯一的String对象Q程序员不需要ؓ字符串字面量而发愁,但是可能会被一些通过 new关键字创建的String对象而困扎ͼ不过他们可以使用intern()Ҏ来避免在堆内存上创徏重复的String对象来改善Java的运行性能。下一节会向大家展示更多的信息?br /> <br />下图展示了未使用intern()Ҏ来创建字W串的情c?br /> <br />string_creating_without_intern() method<br />  你可以自׃?=操作W和String.equals()Ҏ来编码测试上面提到的区别?=操作W会q回true如果一些引用指向一个相同的对象但不会判断String对象的内Ҏ否相同;String.equals()Ҏ会返回true如果被操作的String对象的内容相同。对于上面的代码会有s1==s2Q因为s1和s2两个引用指向同一个对象,对于上面的代码,s3.equals(s4)会返回true因ؓ两个对象的内定w一样ؓ”hello”。你可以从上囄U机制。在q里有三个独立的包含了相同的内容Q”hello”)的对象,实际上我们不需要这么三个独立的对象—— 因q行它们的话既浪Ҏ间又费内存?br /> <br />  那么怎样才能保String对象不会重复呢?下一个话题会늛对于内徏String机制的兴?br /> <br />滞留字符串的优化作用<br />  同一个字W串对象被重复地创徏是不必要的,String.intern ()Ҏ可以避免q种情况。下图说明了String.intern()Ҏ是如何工作的QString.intern()Ҏ查字W串对象的存在性,如果需要的字符串对象已l存在,那么它会引用指向已l存在的字符串对象而不是重新创Z个。下图描l了使用了intern()Ҏ的字W串字面量和字符串对象的创徏情况?br /> <br />string_creating_with_intern() method<br />下面的例E帮助大家了解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<variables.length;i++){<br />        variables[i] = "s"+i;<br />    }<br />    // create String literals<br />    long startTime0 = System.currentTimeMillis();<br />    for(int i=0;i<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<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<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 />q是上面那段代码的输出结果:<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 />q接字符串时候的优化技?br />  你可以?操作W或者String.concat()或者StringBuffer.append(){办法来q接多个字符Ԍ那一U办法具有最佳的性能呢?<br />  如何作出选择取决于两U情景,W一U情景是需要连接的字符串是在编译期军_的还是在q行期决定的Q第二种情景是你使用的是 StringBufferq是String。通常E序员会认ؓStringBuffer.append()Ҏ会优?操作W或 String.concat()ҎQ但是在一些特定的情况下这个假x不成立的?br /> <br />1) W一U情景:~译期决定相对于q行期决?br />L下面的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<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<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 />q是上面的代码的输出l果Q?br />Time taken for String concatenation using + operator : 0 milli seconds<br />Time taken for String concatenation using StringBuffer : 50 milli seconds<br />很有地Q?操作W居然比StringBuffer.append()Ҏ要快Qؓ什么呢Q?br /> <br />  q里~译器的优化起了关键作用Q编译器像下面D例的那样单地在编译期q接多个字符丌Ӏ它使用~译期决定取代运行期军_Q在你用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 />q里String对象在编译期决定了而StringBuffer对象是在q行期决定的。运行期军_需要额外的开销当字W串的值无法预先知道的时候,~译期决定作用于字符串的值可以预先知道的时候,下面是一个例子?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 />q行期决定需要更多的旉来运行?br /> <br />2) W二U情景:使用StringBuffer取代String<br />看看下面的代码你会发C情景一相反的结果——连接多个字W串的时候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<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<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 />q是上面的代码的输出l果Q?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()Ҏ要比+操作W要快得多,Z么呢Q?br /><br />  原因是两者都是在q行期决定字W串对象Q但?操作W用不同于StringBuffer.append()的规则通过String和StringBuffer来完成字W串q接操作。(译注Q什么样的规则呢Q)<br /> <br />借助StringBuffer的初始化q程的优化技?br />  你可以通过StringBuffer的构造函数来讑֮它的初始化容量,q样可以明显地提升性能。这里提到的构造函数是StringBuffer(int length)Qlength参数表示当前的StringBuffer能保持的字符数量。你也可以用ensureCapacity(int minimumcapacity)Ҏ在StringBuffer对象创徏之后讄它的定w。首先我们看看StringBuffer的缺省行为,然后再找Z条更好的提升性能的途径?br /> <br />StringBuffer的缺省行为:<br />  StringBuffer在内部维护一个字W数l,当你使用~省的构造函数来创徏StringBuffer对象的时候,因ؓ没有讄初始化字W长度,StringBuffer的容量被初始化ؓ16个字W,也就是说~省定w是16个字W。当StringBuffer辑ֈ最大容量的时候,它会自w容量增加到当前?倍再?Q也是Q?*旧?2Q?br />  如果你用缺省|初始化之后接着往里面q加字符Q在你追加到W?6个字W的时候它会将定w增加?4Q?*16+2Q,当追加到34个字W的时候就会将定w增加?0Q?*34+2Q。无Z事只要StringBuffer到达它的最大容量它׃得不创徏一个新的字W数l然后重新将旧字W和新字W都拯一遍——这也太昂贵了点。所以LlStringBuffer讄一个合理的初始化容量值是错不了的Q这样会带来立竿见媄的性能增益?br />  我利用两个StringBuffer重新试了上面的StringTest4.java代码Q一个未使用初始化容量D另一个用了。这ơ我q加?0000个’hello’对象没有?操作W。区别是我用StringBuffer(250000)的构造函数来初始化第二个 StringBuffer了?br /> <br />输出l果如下Q?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初始化过E的调整的作用由此可见一斑。所以,使用一个合适的定w值来初始化StringBuffer永远都是一个最佳的?br /> <br />关键?br />1. 无论何时只要可能的话使用字符串字面量来常见字W串而不是用new关键字来创徏字符丌Ӏ?br />2. 无论何时当你要用new关键字来创徏很多内容重复的字W串的话Q请使用String.intern()Ҏ?br />3. +操作W会为字W串q接提供最佳的性能——当字符串是在编译期军_的时候?br />4. 如果字符串在q行期决定,使用一个合适的初期定w值初始化的StringBuffer会ؓ字符串连接提供最佳的性能?img src ="http://www.tkk7.com/balajinima/aggbug/166913.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.tkk7.com/balajinima/" target="_blank">李云?/a> 2007-12-11 13:32 <a href="http://www.tkk7.com/balajinima/articles/166913.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>详细解析抽象cd接口的区?/title><link>http://www.tkk7.com/balajinima/articles/159417.html</link><dc:creator>李云?/dc:creator><author>李云?/author><pubDate>Fri, 09 Nov 2007 09:39:00 GMT</pubDate><guid>http://www.tkk7.com/balajinima/articles/159417.html</guid><wfw:comment>http://www.tkk7.com/balajinima/comments/159417.html</wfw:comment><comments>http://www.tkk7.com/balajinima/articles/159417.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.tkk7.com/balajinima/comments/commentRss/159417.html</wfw:commentRss><trackback:ping>http://www.tkk7.com/balajinima/services/trackbacks/159417.html</trackback:ping><description><![CDATA[ <div style="MARGIN-BOTTOM: 10px"> <h4 class="mode_title" id="veryTitle"> </h4> </div> <div class="1161611" id="quoteinfo" style="MARGIN-BOTTOM: 10px"> </div> <div class="6611111" id="voteAnchor"> </div> <div style="POSITION: relative"> <div id="1616661" 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是语a中对于抽象类定义q行支持的两U机Ӟ正是׃q两U机制的存在Q才赋予了Java强大的面向对象能力。abstract class和interface之间在对于抽象类定义的支持方面具有很大的怼性,甚至可以怺替换Q因此很多开发者在q行抽象cd义时对于abstract class和interface的选择昑־比较随意。其实,两者之间还是有很大的区别的Q对于它们的选择甚至反映出对于问题领域本质的理解、对于设计意囄理解是否正确、合理。本文将对它们之间的区别q行一番剖析,试图l开发者提供一个在二者之间进行选择的依据。  ?/font><wbr><br /><font style="LINE-HEIGHT: 1.3em"></font><wbr><br /><font style="LINE-HEIGHT: 1.3em">理解抽象c  ?/font><wbr><br /><font style="LINE-HEIGHT: 1.3em"></font><wbr><br /><font style="LINE-HEIGHT: 1.3em">abstract class和interface在Java语言中都是用来进行抽象类Q本文中的抽象类q从abstract class译而来Q它表示的是一个抽象体Q而abstract class为Java语言中用于定义抽象类的一U方法,误者注意区分)定义的,那么什么是抽象c,使用抽象c能为我们带来什么好处呢Q  ?/font><wbr><br /><font style="LINE-HEIGHT: 1.3em"></font><wbr><br /><font style="LINE-HEIGHT: 1.3em">在面向对象的概念中,我们知道所有的对象都是通过cL描绘的,但是反过来却不是q样。ƈ不是所有的c都是用来描l对象的Q如果一个类中没有包含够的信息来描l一个具体的对象Q这Lcd是抽象类。抽象类往往用来表征我们在对问题领域q行分析、设计中得出的抽象概念,是对一pd看上M同,但是本质上相同的具体概念的抽象。比如:如果我们q行一个图形编辑Y件的开发,׃发现问题领域存在着圆、三角Şq样一些具体概念,它们是不同的Q但是它们又都属于Ş状这样一个概念,形状q个概念在问题领域是不存在的Q它是一个抽象概c正是因为抽象的概念在问题领域没有对应的具体概念Q所以用以表征抽象概늚抽象cL不能够实例化的。  ?/font><wbr><br /><font style="LINE-HEIGHT: 1.3em"></font><wbr><br /><font style="LINE-HEIGHT: 1.3em">在面向对象领域,抽象cM要用来进行类型隐藏。我们可以构造出一个固定的一l行为的抽象描述Q但是这l行为却能够有Q意个可能的具体实现方式。这个抽象描q就是抽象类Q而这一lQ意个可能的具体实现则表现为所有可能的zcR模块可以操作一个抽象体。由于模块依赖于一个固定的抽象体,因此它可以是不允怿改的Q同Ӟ通过从这个抽象体zQ也可扩展此模块的行为功能。熟悉OCP的读者一定知道,Z能够实现面向对象设计的一个最核心的原则OCP(Open-Closed Principle)Q抽象类是其中的关键所在。  ?/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和interfacel出了不同的定义方式Q下面以定义一个名为Demo的抽象类Z来说明这U不同。  ?/font><wbr><br /><font style="LINE-HEIGHT: 1.3em"></font><wbr><br /><font style="LINE-HEIGHT: 1.3em">使用abstract class的方式定义Demo抽象cȝ方式如下Q  ?/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抽象cȝ方式如下Q  ?/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可以有自q数据成员Q也可以有非abstarct的成员方法,而在interface方式的实CQDemo只能够有静态的不能被修改的数据成员Q也是必须是static final的,不过在interface中一般不定义数据成员Q,所有的成员Ҏ都是abstract的。从某种意义上说Qinterface是一U特DŞ式的abstract class。  ?/font><wbr><br /><font style="LINE-HEIGHT: 1.3em"></font><wbr><br /><font style="LINE-HEIGHT: 1.3em">      从编E的角度来看Qabstract class和interface都可以用来实?design by contract"的。但是在具体的用上面还是有一些区别的。  ?/font><wbr><br /><font style="LINE-HEIGHT: 1.3em"></font><wbr><br /><font style="LINE-HEIGHT: 1.3em">首先Qabstract class在Java语言中表C的是一U承关p,一个类只能使用一ơ承关pR但是,一个类却可以实现多个interface。也许,q是Java语言的设计者在考虑Java对于多重l承的支持方面的一U折中考虑吧。  ?/font><wbr><br /><font style="LINE-HEIGHT: 1.3em"></font><wbr><br /><font style="LINE-HEIGHT: 1.3em">其次Q在abstract class的定义中Q我们可以赋予方法的默认行ؓ。但是在interface的定义中Q方法却不能拥有默认行ؓQؓ了绕q这个限Ӟ必须使用委托Q但是这会 增加一些复杂性,有时会造成很大的麻烦。  ?/font><wbr><br /><font style="LINE-HEIGHT: 1.3em"></font><wbr><br /><font style="LINE-HEIGHT: 1.3em">在抽象类中不能定义默认行存在另一个比较严重的问题Q那是可能会造成l护上的ȝ。因为如果后来想修改cȝ界面Q一般通过abstract class或者interface来表C)以适应新的情况Q比如,d新的Ҏ或者给已用的方法中d新的参数Q时Q就会非常的ȝQ可能要p很多的时_对于zcd多的情况Q尤为如此)。但是如果界面是通过abstract class来实现的Q那么可能就只需要修改定义在abstract class中的默认行ؓ可以了。  ?/font><wbr><br /><font style="LINE-HEIGHT: 1.3em"></font><wbr><br /><font style="LINE-HEIGHT: 1.3em">同样Q如果不能在抽象cM定义默认行ؓQ就会导致同LҎ实现出现在该抽象cȝ每一个派生类中,q反?one ruleQone place"原则Q造成代码重复Q同样不利于以后的维护。因此,在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.tkk7.com/balajinima/aggbug/159417.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.tkk7.com/balajinima/" target="_blank">李云?/a> 2007-11-09 17:39 <a href="http://www.tkk7.com/balajinima/articles/159417.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java 反射http://www.tkk7.com/balajinima/articles/149623.html李云?/dc:creator>李云?/author>Sat, 29 Sep 2007 09:14:00 GMThttp://www.tkk7.com/balajinima/articles/149623.htmlhttp://www.tkk7.com/balajinima/comments/149623.htmlhttp://www.tkk7.com/balajinima/articles/149623.html#Feedback0http://www.tkk7.com/balajinima/comments/commentRss/149623.htmlhttp://www.tkk7.com/balajinima/services/trackbacks/149623.html
1. 得到某个对象的属?br />
1 public Object getProperty(Object owner, String fieldName) throws Exception {
2     Class ownerClass = owner.getClass();
3 
4     Field field = ownerClass.getField(fieldName);
5 
6     Object property = field.get(owner);
7 
8     return property;
9 }

Class ownerClass = owner.getClass()Q得到该对象的Class?br />
Field field = ownerClass.getField(fieldName)Q通过Class得到cd明的属性?br />
Object property = field.get(owner)Q通过对象得到该属性的实例Q如果这个属性是非公有的Q这里会报IllegalAccessException?br />


2. 得到某个cȝ静态属?br />
 1 public Object getStaticProperty(String className, String fieldName)
 2             throws Exception {
 3     Class ownerClass = Class.forName(className);
 4 
 5     Field field = ownerClass.getField(fieldName);
 6 
 7     Object property = field.get(ownerClass);
 8 
 9     return property;
10 }


Class ownerClass = Class.forName(className) Q首先得到这个类的Class?br />
Field field = ownerClass.getField(fieldName)Q和上面一P通过Class得到cd明的属性?br />
Object property = field.get(ownerClass) Q这里和上面有些不同Q因属性是静态的Q所以直接从cȝClass里取?br />

3. 执行某对象的Ҏ

 1 public Object invokeMethod(Object owner, String methodName, Object[] args) throws Exception {
 2 
 3     Class ownerClass = owner.getClass();
 4 
 5     Class[] argsClass = new Class[args.length];
 6 
 7     for (int i = 0, j = args.length; i < j; i++) {
 8         argsClass[i] = args[i].getClass();
 9     }
10 
11     Method method = ownerClass.getMethod(methodName, argsClass);
12 
13     return method.invoke(owner, args);
14 }

Class owner_class = owner.getClass() Q首先还是必d到这个对象的Class?br />
5?行:配置参数的Class数组Q作为寻找Method的条件?br />
Method method = ownerClass.getMethod(methodName, argsClass)Q通过Method名和参数的Class数组得到要执行的Method?br />
method.invoke(owner, args)Q执行该MethodQinvokeҎ的参数是执行q个Ҏ的对象,和参数数l。返回值是ObjectQ也既是该方法的q回倹{?br />

4. 执行某个cȝ静态方?br />
 1 public Object invokeStaticMethod(String className, String methodName,
 2             Object[] args) throws Exception {
 3     Class ownerClass = Class.forName(className);
 4 
 5     Class[] argsClass = new Class[args.length];
 6 
 7     for (int i = 0, j = args.length; i < j; i++) {
 8         argsClass[i] = args[i].getClass();
 9     }
10 
11     Method method = ownerClass.getMethod(methodName, argsClass);
12 
13     return method.invoke(null, args);
14 }


基本的原理和实例3相同Q不同点是最后一行,invoke的一个参数是nullQ因是静态方法,不需要借助实例q行?br />


5. 新徏实例
 1 
 2 public Object newInstance(String className, Object[] args) throws Exception {
 3     Class newoneClass = Class.forName(className);
 4 
 5     Class[] argsClass = new Class[args.length];
 6 
 7     for (int i = 0, j = args.length; i < j; i++) {
 8         argsClass[i] = args[i].getClass();
 9     }
10 
11     Constructor cons = newoneClass.getConstructor(argsClass);
12 
13     return cons.newInstance(args);
14 
15 }


q里说的Ҏ是执行带参数的构造函数来新徏实例的方法。如果不需要参敎ͼ可以直接使用newoneClass.newInstance()来实现?br />
Class newoneClass = Class.forName(className)Q第一步,得到要构造的实例的Class?br />
W?~第9行:得到参数的Class数组?br />
Constructor cons = newoneClass.getConstructor(argsClass)Q得到构造子?br />
cons.newInstance(args)Q新建实例?br />

6. 判断是否为某个类的实?br />
1 public boolean isInstance(Object obj, Class cls) {
2     return cls.isInstance(obj);
3 }



7. 得到数组中的某个元素
1 public Object getByArray(Object array, int index) {
2     return Array.get(array,index);
3 }



附完整源码:

import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;


/**
 * Java Reflection Cookbook
 *
 * 
@author Michael Lee
 * 
@since 2006-8-23
 * 
@version 0.1a
 
*/

public class Reflection {
    
/**
     * 得到某个对象的公共属?br />     *
     * 
@param owner, fieldName
     * 
@return 该属性对?br />     * @throws Exception
     *
     
*/
    
public Object getProperty(Object owner, String fieldName) throws Exception {
        Class ownerClass 
= owner.getClass();

        Field field 
= ownerClass.getField(fieldName);

        Object property 
= field.get(owner);

        
return property;
    }

    
/**
     * 得到某类的静态公共属?br />     *
     * 
@param className   cd
     * 
@param fieldName   属性名
     * 
@return 该属性对?br />     * @throws Exception
     
*/
    
public Object getStaticProperty(String className, String fieldName)
            
throws Exception {
        Class ownerClass 
= Class.forName(className);

        Field field 
= ownerClass.getField(fieldName);

        Object property 
= field.get(ownerClass);

        
return property;
    }


    
/**
     * 执行某对象方?br />     *
     * 
@param owner
     *            对象
     * 
@param methodName
     *            Ҏ?br />     * 
@param args
     *            参数
     * 
@return Ҏq回?br />     * @throws Exception
     
*/
    
public Object invokeMethod(Object owner, String methodName, Object[] args)
            
throws Exception {

        Class ownerClass 
= owner.getClass();

        Class[] argsClass 
= new Class[args.length];

        
for (int i = 0, j = args.length; i < j; i++) {
            argsClass[i] 
= args[i].getClass();
        }

        Method method 
= ownerClass.getMethod(methodName, argsClass);

        
return method.invoke(owner, args);
    }


      
/**
     * 执行某类的静态方?br />     *
     * 
@param className
     *            cd
     * 
@param methodName
     *            Ҏ?br />     * 
@param args
     *            参数数组
     * 
@return 执行Ҏq回的结?br />     * @throws Exception
     
*/
    
public Object invokeStaticMethod(String className, String methodName,
            Object[] args) 
throws Exception {
        Class ownerClass 
= Class.forName(className);

        Class[] argsClass 
= new Class[args.length];

        
for (int i = 0, j = args.length; i < j; i++) {
            argsClass[i] 
= args[i].getClass();
        }

        Method method 
= ownerClass.getMethod(methodName, argsClass);

        
return method.invoke(null, args);
    }



    
/**
     * 新徏实例
     *
     * 
@param className
     *            cd
     * 
@param args
     *            构造函数的参数
     * 
@return 新徏的实?br />     * @throws Exception
     
*/
    
public Object newInstance(String className, Object[] args) throws Exception {
        Class newoneClass 
= Class.forName(className);

        Class[] argsClass 
= new Class[args.length];

        
for (int i = 0, j = args.length; i < j; i++) {
            argsClass[i] 
= args[i].getClass();
        }

        Constructor cons 
= newoneClass.getConstructor(argsClass);

        
return cons.newInstance(args);

    }


    
    
/**
     * 是不是某个类的实?br />     * 
@param obj 实例
     * 
@param cls c?br />     * @return 如果 obj 是此cȝ实例Q则q回 true
     
*/
    
public boolean isInstance(Object obj, Class cls) {
        
return cls.isInstance(obj);
    }
    
    
/**
     * 得到数组中的某个元素
     * 
@param array 数组
     * 
@param index 索引
     * 
@return q回指定数组对象中烦引组件的?br />     */
    
public Object getByArray(Object array, int index) {
        
return Array.get(array,index);
    }
}


]]>
体验JAVA 5的新增语aҎ?http://www.tkk7.com/balajinima/articles/146905.html李云?/dc:creator>李云?/author>Thu, 20 Sep 2007 12:10:00 GMThttp://www.tkk7.com/balajinima/articles/146905.htmlhttp://www.tkk7.com/balajinima/comments/146905.htmlhttp://www.tkk7.com/balajinima/articles/146905.html#Feedback0http://www.tkk7.com/balajinima/comments/commentRss/146905.htmlhttp://www.tkk7.com/balajinima/services/trackbacks/146905.html
关键?   体验JAVA 5的新增语aҎ?#160;   

  Java 5.0发布了,许多人都开始用这个JDK版本的一些新增特性。从增强的for循环到诸如泛?generic)之类更复杂的Ҏ,都将很快出现在您所~写的代码中。我们刚刚完成了一个基于Java 5.0的大型Q务,而本文就是要介绍我们使用q些新特性的体验。本文不是一入门性的文章Q而是对这些特性以及它们所产生的媄响的深入介绍Q同时还l出了一些在目中更有效C用这些特性的技巧?

?/strong>
  在JDK 1.5的beta阶段Q我们ؓBEA的Java IDE开发了一个Java 5~译器。因为我们实C许多新特性,所以h们开始以新的方式利用它们Q有些用法很聪明Q而有些用法明昑ֺ该被列入用清单。编译器本n使用了新的语aҎ,所以我们也获得了用这些特性维护代码的直接体验。本文将介绍其中的许多特性和使用它们的体验?
  我们假定您已l熟悉了q些新特性,所以不再全面介l每个特性,而是谈论一些有的、但很可能不太明昄内容和用法。这些技巧出自我们的实际体验Qƈ大致按照语言Ҏ进行了分类?
  我们从最单的Ҏ开始,逐步q渡到高U特性。泛型所包含的内容特别丰富,因此占了本文一半的幅?/p>

增强的for循环
  Zq代集合和数l,增强的for循环提供了一个简单、兼容的语法。有两点值得一提:

Init表达?/strong>
  在@环中Q初始化表达式只计算一ơ。这意味着您通常可以U除一个变量声明。在q个例子中,我们必须创徏一个整型数l来保存computeNumbers()的结果,以防止每一ơ@环都重新计算该方法。您可以看到Q下面的代码要比上面的代码整z一些,q且没有泄露变量numbersQ?

未增强的ForQ?
int sum = 0;
Integer[] numbers = computeNumbers();
for (int i=0; i < numbers.length ; i++)
    sum += numbers[i];
增强后的ForQ?
int sum = 0;

for ( int number: computeNumbers() )
    sum += number;

局限?/strong>
有时需要在q代期间讉Kq代器或下标Q看h增强的for循环应该允许该操作,但事实上不是q样Q请看下面的例子Q?

for (int i=0; i < numbers.length ; i++) {
    if (i != 0) System.out.print(",");
    System.out.print(numbers[i]);
}

  我们希望数l中的值打Cؓ一个用逗号分隔的清单。我们需要知道目前是否是W一,以便定是否应该打印逗号。用增强的for循环是无法获知这U信息的。我们需要自׃留一个下标或一个布值来指示是否l过了第一V?  q是另一个例子:

for (Iterator it = n.iterator() ; it.hasNext() ; )
    if (it.next() < 0)
        it.remove();

  在此例中Q我们想从整数集合中删除负数Vؓ此,需要对q代器调用一个方法,但是当用增强的for 循环Ӟq代器对我们来说是看不到的。因此,我们只能使用Java 5之前版本的P代方法?  Z说一下,q里需要注意的是,׃Iterator是泛型,所以其声明是Iterator。许多h都忘Cq一点而用了Iterator的原始格式?

注释
  注释处理是一个很大的话题。因为本文只x核心的语aҎ,所以我们不打算늛它所有的可能形式和陷阱。  我们讨论内|的注释QSuppressWarningsQDeprecated和OverrideQ以及一般注释处理的局限性?

Suppress Warnings
  该注释关闭了cLҎU别的编译器警告。有时候您比编译器更清楚地知道Q代码必M用一个被否决的方法或执行一些无法静态确定是否类型安全的动作Q而用:

@SuppressWarnings("deprecation")
public static void selfDestruct() {
    Thread.currentThread().stop();
}

  q可能是内置注释最有用的地斏V遗憄是,1.5.0_04的javac不支持它。但?.6支持它,q且Sun正在努力其向后UL?.5中?
Eclipse 3.1中支持该注释Q其他IDE也可能支持它。这允许您把代码dC警告中解脱出来。如果在~译时出现警告,可以定是您刚刚把它dq来——以帮助查看那些可能不安全的代码。随着泛型的添加,它用v来将更趁手?

Deprecated
  遗憾的是QDeprecated没那么有用。它本来旨在替换@deprecated javadoc标签Q但是由于它不包含Q何字D,所以也没有方法来deprecatedcLҎ的用户应该用什么做为替代品。大多数用法都同旉要javadoc标签和这个注释?

Override
  Override表示Q它所注释的方法应该重写超cMh相同{֐的方法:

@Override
public int hashCode() {
    ...
}

  看上面的例子Q如果没有在hashCode中将“C”大写Q在~译时不会出现错误,但是在运行时无法像期望的那栯用该Ҏ。通过dOverride标签Q编译器会提C它是否真正地执行了重写?
  在超cd生改变的情况中,q也很有帮助。如果向该方法中d一个新参数Q而且Ҏ本n也被重命名了Q那么子cdH然不能~译Q因为它不再重写类的Q何东ѝ?

其它注释
  注释在其他场景中非常有用。当不是直接修改行ؓ而是增强行ؓӞ特别是在dh代码的情况下Q注释在诸如EJB?a target="_blank">Web servicesq样的框架中q行得非常好?
注释不能用做预处理器。Sun的设计特别预防了完全因ؓ注释而修改类的字节码。这样可以正地理解该语a的成果,而且IDE之类的工具也可以执行深入的代码分析和重构之类的功能?
注释不是银弹。第一ơ遇到的时候,Z试图试各种技巧。请看下面这个从别h那里获得的徏议:

public class Foo {
 
    @Property
    private int bar;
 
}

  其思想是ؓU有字段bar自动创徏getter和setterҎ。遗憄是,q个x有两个失败之处:1)它不能运行,2)它代码难以阅读和处理?  它是无法实现的,因ؓ前面已经提到了,Sun特别L了对出现注释的类q行修改?
  即是可能的Q它也不是一个好LQ因为它使代码可L差。第一ơ看到这D代码的Z不知道该注释创徏了方法。此外,如果来您需要在q些Ҏ内部执行一些操作,注释也是没用的?  MQ不要试囄注释d那些常规代码可以完成的事情?

枚D
  enum非常像public static final int声明Q后者作为枚丑ր已l用了很多q。对int所做的最大也是最明显的改q是cd安全——您不能错误地用枚D的一U类型代替另一U类型,q一点和int不同Q所有的int对编译器来说都是一L。除L数例外的情况,通常都应该用enum实例替换全部的枚N格的intl构?
  枚D提供了一些附加的Ҏ。EnumMap和EnumSetq两个实用类是专门ؓ枚D优化的标准集合实现。如果知道集合只包含枚DcdQ那么应该用这些专门的集合来代替HashMap或HashSet?
  大部分情况下Q可以用enum对代码中的所有public static final int做插入替换。它们是可比的,q且可以静态导入,所以对它们的引用看h是等同的Q即使是对于内部c(或内部枚丄型)。注意,比较枚Dcd的时候,声明它们的指令表明了它们的顺序倹{?

“隐藏?#8221;静态方?
  两个静态方法出现在所有枚丄型声明中。因为它们是枚D子类上的静态方法,而不是Enum本n的方法,所以它们在java.lang.Enum的javadoc中没有出现?
  W一个是values()Q返回一个枚丄型所有可能值的数组?
  W二个是valueOf()Qؓ提供的字W串q回一个枚丄型,该枚丄型必ȝ地匚w源代码声明?
Ҏ
  关于枚DcdQ我们最喜欢的一个方面是它可以有Ҏ。过L可能需要编写一些代码,对public static final intq行转换Q把它从数据库类型{换ؓJDBC URL。而现在则可以让枚丄型本w带一个整理代码的Ҏ。下面就是一个例子,包括DatabaseType枚Dcd的抽象方法以及每个枚丑֮例中提供的实玎ͼ

  public enum  DatabaseType {
  ORACLE {
  public String getJdbcUrl() {...}
  },
  MYSQL {
  public String getJdbcUrl() {...}
  };
  public abstract String getJdbcUrl();
  }

  现在枚Dcd可以直接提供它的实用Ҏ。例如:

DatabaseType dbType = ...;
String jdbcURL = dbType.getJdbcUrl();

  要获取URLQ必预先知道该实用Ҏ在哪里?


可变参数(Vararg)
  正确C用可变参数确实可以清理一些垃圾代码。典型的例子是一个带有可变的String参数个数的logҎQ?

    Log.log(String code)
    Log.log(String code,  String arg)
    Log.log(String code,  String arg1, String arg2)
    Log.log(String code,  String[] args)

  当讨论可变参数时Q比较有的是,如果用新的可变参数替换前四个例子Q将是兼容的Q?
Log.log(String code, String... args)
  所有的可变参数都是源兼容的——那是_如果重新~译log()Ҏ的所有调用程序,可以直接替换全部的四个方法。然而,如果需要向后的二进制兼Ҏ,那么需要舍d三个Ҏ。只有最后那个带一个字W串数组参数的方法等效于可变参数版本Q因此可以被可变参数版本替换?

cd强制转换

  如果希望调用E序了解应该使用哪种cd的参敎ͼ那么应该避免用可变参数进行类型强制{换。看下面q个例子Q第一希望是StringQ第二项希望是ExceptionQ?

    Log.log(Object...  objects) {
    String message = (String)objects[0];
    if (objects.length > 1) {
    Exception e = (Exception)objects[1];
    // Do something with the exception
    }
    }

  Ҏ{֐应该如下所C,相应的可变参数分别用String和Exception声明Q?

Log.log(String message, Exception e, Object... objects) {...}

  不要使用可变参数破坏cdpȝ。需要强cd化时才可以用它。对于这个规则,PrintStream.printf()是一个有的例外Q它提供cd信息作ؓ自己的第一个参敎ͼ以便E后可以接受那些cd?

协变q回

  协变q回的基本用法是用于在已知一个实现的q回cd比API更具体的时候避免进行类型强制{换。在下面q个例子中,有一个返回Animal对象的Zoo接口。我们的实现q回一个AnimalImpl对象Q但是在JDK 1.5之前Q要q回一个Animal对象必d明?

    public interface Zoo  {
    public Animal getAnimal();
    }
  public class ZooImpl  implements Zoo {
  public Animal getAnimal(){
  return new AnimalImpl();
  }
  }

  协变q回的用替换了三个反模式:

 

  • 直接字段讉K。ؓ了规避API限制Q一些实现把子类直接暴露为字D:

ZooImpl._animal

  • 另一UŞ式是Q在知道实现的实际上是特定的子类的情况下Q在调用E序中执行向下{换:

((AnimalImpl)ZooImpl.getAnimal()).implMethod();

  • 我看到的最后一UŞ式是一个具体的ҎQ该Ҏ用来避免׃个完全不同的{֐所引发的问题:

ZooImpl._getAnimal();

  q三U模式都有它们的问题和局限性。要么是不够整洁Q要么就是暴露了不必要的实现l节?

协变

  协变q回模式比较整z、安全ƈ且易于维护,它也不需要类型强制{换或特定的方法或字段Q?
public AnimalImpl getAnimal(){
return new AnimalImpl();
}
  使用l果Q?
ZooImpl.getAnimal().implMethod();

使用泛型
  
我们从两个角度来了解泛型:使用泛型和构造泛型。我们不讨论List、Set和Map的显而易见的用法。知道泛型集合是强大的ƈ且应该经怋用就_了?
  我们讨论泛型方法的使用以及~译器推断类型的Ҏ。通常q些都不会出问题Q但是当出问题时Q错误信息会非常令h费解Q所以需要了解如何修复这些问题?

泛型Ҏ
  
除了泛型cdQJava 5q引入了泛型Ҏ。在q个来自java.util.Collections的例子中Q构造了一个单元素列表。新的List的元素类型是Ҏ传入Ҏ的对象的cd来推断的Q?

static  List Collections.singletonList(T o)
CZ用法Q?
public List getListOfOne() {
    return Collections.singletonList(1);
}

  在示例用法中Q我们传入了一个int。所以方法的q回cd是List。编译器把T推断为Integer。这和泛型类型是不同的,因ؓ您通常不需要显式地指定cd参数?
q也昄了自动装和泛型的相互作用。类型参数必L引用cdQ这是Z么我们得到的是List而不是List?

不带参数的泛型方?br />  emptyList()Ҏ与泛型一起引入,作ؓjava.util.Collections中EMPTY_LIST字段的类型安全置换:

static  List Collections.emptyList()
CZ用法Q?
public List getNoIntegers() {
    return Collections.emptyList();
}

  与先前的例子不同Q这个方法没有参敎ͼ那么~译器如何推断T的类型呢Q基本上Q它尝试用一ơ参数。如果没有v作用Q它再次试使用q回或赋值类型。在本例中,q回的是ListQ所以T被推断ؓInteger?
  如果在返回语句或赋D句之外的位置调用泛型Ҏ会怎么样呢Q那么编译器无法执行类型推断的W二ơ传送。在下面q个例子中,emptyList()是从条gq算W内部调用的Q?

public List getNoIntegers() {
    return x ? Collections.emptyList() : null;
}

  因ؓ~译器看不到q回上下文,也不能推断TQ所以它攑ּq用Object。您看C个错误消息,比如Q?#8220;无法List< Object >转换为List?#8221;
Z修复q个错误Q应昑ּ地向Ҏ调用传递类型参数。这P~译器就不会试图推断cd参数Q就可以获得正确的结果:

return x ? Collections.emptyList() : null;

  q种情况l常发生的另一个地Ҏ在方法调用中。如果一个方法带一个List参数Qƈ且需要ؓ那个参数调用q个传递的emptyList()Q那么也需要用这个语法?

集合之外
  q里有三个泛型类型的例子Q它们不是集合,而是以一U新颖的方式使用泛型。这三个例子都来自标准的Java库:

  • Class
    Class在类的类型上被参数化了。这׃无需cd强制转换而构造一个newInstance成ؓ可能?
  • Comparable
    Comparable被实际的比较cd参数化。这在compareTo()调用时提供了更强的类型化。例如,String实现Comparable。对除String之外的Q何东西调用compareTo()Q都会在~译时失败?
  • Enum>
    Enum被枚丄型参数化。一个名为Color的枚丄型将扩展Enum。getDeclaringClass()Ҏq回枚Dcd的类对象Q在q个例子中就是一个Color对象。它与getClass()不同Q后者可能返回一个无名类?

通配W?br />  泛型最复杂的部分是寚w配W的理解。我们将讨论三种cd的通配W以及它们的用途?
  首先让我们了解一下数l是如何工作的。可以从一个Integer[]Z个Number[]赋倹{如果尝试把一个Float写到Number[]中,那么可以~译Q但在运行时会失败,出现一个ArrayStoreExceptionQ?

Integer[] ia = new Integer[5];
Number[] na = ia;
na[0] = 0.5; // compiles, but fails at runtime
如果试图把该例直接{换成泛型Q那么会在编译时p|Q因值是不被允许的:
List iList = new ArrayList();
List nList = iList; // not allowed
nList.add(0.5);

  如果使用泛型Q只要代码在~译时没有出现警告,׃会遇到运行时ClassCastException?

上限通配W?/strong>
  我们惌的是一个确切元素类型未知的列表Q这一点与数组是不同的?
List是一个列表,其元素类型是具体cdNumber?
List<!--xtends Numb-->是一个确切元素类型未知的列表。它是Number或其子类型?

上限
  
如果我们更新初始的例子,q赋值给List<!--xtends Numb-->Q那么现在赋值就会成功了Q?

List iList = new ArrayList();
List<!--xtends Numb--> nList = iList;
Number n = nList.get(0);
nList.add(0.5); // Not allowed

  我们可以从列表中得到NumberQ因为无论列表的切元素cd是什么(Float、Integer或NumberQ,我们都可以把它赋值给Number?
  我们仍然不能把Q点类型插入列表中。这会在~译时失败,因ؓ我们不能证明q是安全的。如果我们想要向列表中添加Q点类型,它将破坏iList的初始类型安全——它只存储Integer?
  通配W给了我们比数组更多的表达能力?

Z么用通配W?br />  在下面这个例子中Q通配W用于向API的用户隐藏类型信息。在内部QSet被存储ؓCustomerImpl。而API的用户只知道他们正在获取一个SetQ从中可以读取Customer?
此处通配W是必需的,因ؓ无法从Set向Set赋|

public class CustomerFactory {
    private Set _customers;
    public Set<!--xtends Custom--> getCustomers() {
        return _customers;
    }
}

通配W和协变q回
  通配W的另一U常见用法是和协变返回一起用。与赋值相同的规则可以应用到协变返回上。如果希望在重写的方法中q回一个更具体的泛型类型,声明的方法必M用通配W:

public interface NumberGenerator {
    public List<!--xtends Numb--> generate();
}
public class FibonacciGenerator extends NumberGenerator {
    public List generate() {
        ...
    }
}

  如果要用数l,接口可以q回Number[]Q而实现可以返回Integer[]?

下限
  我们所谈的主要是关于上限通配W的。还有一个下限通配W。List<!--uper Numb-->是一个确?#8220;元素cd”未知的列表,但是可能是MnumberQ或者Number的超cd。所以它可能是一个List或一个List< Object>?
  下限通配W远没有上限通配W那样常见,但是当需要它们的时候,它们是必需的?

下限与上?br />

List<!--xtends Numb--> readList = new ArrayList();
Number n = readList.get(0);

List<!--uper Numb--> writeList = new ArrayList< Object>();
writeList.add(new Integer(5));

  W一个是可以从中L的列表?
  W二个是可以向其写数的列表?

无界通配W?/strong>
  最后,List列表的内容可以是McdQ而且它与List<!--xtends Obje-->几乎相同。可以随时读取ObjectQ但是不能向列表中写入内宏V?

公共API中的通配W?
  MQ正如前面所_通配W在向调用程序隐藏实现细节方面是非常重要的,但即使下限通配W看h是提供只读访问,׃remove(int position)之类的非泛型ҎQ它们也q如此。如果您惌一个真正不变的集合Q可以用java.util.Collection上的ҎQ比如unmodifiableList()?
  ~写API的时候要记得通配W。通常Q在传递泛型类型时Q应该尝试用通配W。它使更多的调用E序可以讉KAPI?
  通过接收List<!--xtends Numb-->而不是ListQ下面的Ҏ可以p多不同类型的列表调用Q?

void removeNegatives(List<!--xtends Numb--> list);

构造泛型类?/strong>
  现在我们讨论构造自q泛型cd。我们将展示一些例子,其中通过使用泛型可以提高cd安全性,我们q将讨论一些实现泛型类型时的常见问题?/p>

集合风格(Collection-like)的函?/strong>
  W一个泛型类的例子是一个集合风格的例子。Pair有两个类型参敎ͼ而且字段是类型的实例Q?

public final class Pair {
    public final A first;
    public final B second;

    public Pair(A first, B second) {
        this.first = first;
        this.second = second;
    }
}

  q从方法返回两个项而无需为每个两U类型的l合~写专用的类成ؓ可能。另一U方法是q回Object[]Q而这hcd不安全或者不整洁的?
在下面的用法中,我们从方法返回一个File和一个Boolean。方法的客户端可以直接用字D而无需cd强制转换Q?

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;

集合之外
  在下面这个例子中Q泛型被用于附加的编译时安全性。通过把DBFactorycd数化为所创徏的PeercdQ您实际上是在强制Factory子类q回一个Peer的特定子cdQ?

public abstract class DBFactory {
    protected abstract T createEmptyPeer();
    public List get(String constraint) {
        List peers = new ArrayList();
        // database magic
        return peers;
    }
}
通过实现DBFactoryQCustomerFactory必须从createEmptyPeer()q回一个CustomerQ?
public class CustomerFactory extends DBFactory{

    public Customer createEmptyPeer() {
        return new Customer();
    }
}

泛型Ҏ
  不管惌对参C间还是参Cq回cd之间的泛型类型施加约束,都可以用泛型方法:
  例如Q如果编写的反{函数是在位置上反转,那么可能不需要泛型方法。然而,如果希望反{q回一个新的ListQ那么可能会希望新List的元素类型与传入的List的类型相同。在q种情况下,需要一个泛型方法:


List reverse(List list)

具体?br />  当实C个泛型类Ӟ您可能想要构造一个数lT[]。因为泛型是通过擦除(erasure)实现的,所以这是不允许的?
  您可以尝试把Object[]强制转换为T[]。但q是不安全的?

具体化解x?br />  按照泛型教程的惯例,解决Ҏ使用的是“cd令牌”Q通过向构造函数添加一个Class参数Q可以强制客L为类的类型参数提供正的cd象:

public class ArrayExample {
    private Class clazz;

    public ArrayExample(Class clazz) {
        this.clazz = clazz;
    }

    public T[] getArray(int size) {
        return (T[])Array.newInstance(clazz, size);
    }
}

  Z构造ArrayExampleQ客L必须把String.class传递给构造函敎ͼ因ؓString.class的类型是Class?
拥有cd象构造一个具有正元素类型的数组成ؓ可能?

l束?/strong>
  总而言之,新的语言Ҏ有助于从根本上改变Java。通过了解在什么场景下使用以及如何使用q些新特性,您将会编写出更好的代码?/p>

补充阅读

 

原文出处:Experiences with the New Java 5 Language Features http://dev2dev.bea.com/pub/a/2005/09/java_5_features.html <!--文章其他信息-->

 作者简?/span>
  Jess Garms 是BEA Systems中Javelin~译器团队的领导者。在此之前,Jess致力于BEA?Java IDEQWebLogic Workshop。此外,他在密码学方面也h丰富的经验。他q与他h合著?#8220;Professional Java Security”Q由Wrox出版Cև版?/td>
  Tim Hanson 是BEA Systems中Javelin~译器的架构师。Tim对BEA的Java~译器做了很多开发工作,该编译器是最早兼?.5的实C一。他曄~写q许多其他的~译器,包括他在IBM时编写的CORBA/IDL~译器,以及XQuery~译器?/td>


]]>
java Collection 学习W记http://www.tkk7.com/balajinima/articles/144901.html李云?/dc:creator>李云?/author>Thu, 13 Sep 2007 08:29:00 GMThttp://www.tkk7.com/balajinima/articles/144901.htmlhttp://www.tkk7.com/balajinima/comments/144901.htmlhttp://www.tkk7.com/balajinima/articles/144901.html#Feedback0http://www.tkk7.com/balajinima/comments/commentRss/144901.htmlhttp://www.tkk7.com/balajinima/services/trackbacks/144901.html
支持c集的接口如下:
Collection
List
Set
SortedSet
Comparator 定义两个对象如何比较
Iterator 枚Dc集中的对象
ListIterator枚Dc集中的对象
Collection接口Q省略常用的ҎQ?br />Boolean add(Object obj) d一个Object元素
boolean addAll(Collection c)
boolean contains(Object obj)  判断obj是否是调用类集的一个元素(属于Q?br />boolean containsAll(Collection c)  判断c是否是调用类集的子集Q包含)
boolean equals(Collection c) 判断c是否与调用类集相{?br />int hashCode() q回调用c集的hash?br />Iterator iterator() q回调用c集的P代程?br />boolean removeAll(Collection c) 从调用类集中L所有c中包含的元素Q差集)
boolean retainAll(Collection c) 从调用类集中L包含在c中以外的元素Q补集)
Object[] toArray() q回c集的元素组成的数组
 
Void clear()
boolean isEmpty()
int size()

c集包含一个add(Object obj)ҎQ因此可以包含Q意Object数据Q但是不能直接存储:intQchar,Double{数据。可以用下面的Ҏ实现Q?br />ArrayList a=new ArrayList();
a.add(new Integer(1));
a.add(new Integer(2));
…?/p>

当类集不能被修改Ӟ可能引发 UnsupportedOperationException异常。企囑ְ一个不兼容的对象加入到一个类集中时可能引发ClassCastException异常?/p>

List接口Q从Collectionl承而来Q用基?的下标)
void add(int index,Object obj) 插入点以后的元素后U?br />boolean addAll(int index,Collection c) 如果调用列表改变了,q回true,否则q回false
Object get(int index)
int indexOf(Object obj) q回obj对象在列表中的烦引,不存在返?1
int lastIndexOf(Object obj) q回obj在列表中的最后一个实例的下标Q不存在q回-1
ListIterator listIterator()
ListIterator listIterator(int index) q回index开始的q代E序
Object set(int index,Object obj) 对列表index处的D行修?br />List subList(int start,int end) 从start到end-1
 

Set接口Q从CollectionzQ没有定义新的方法)
Set不允许有重复的元素?br />对Set调用addQObject objQ方法,如果obj已经存在集合中,返回false?/p>

SortedSet接口
Comparator comparator() q回调用排序集合的比较函敎ͼ如果攚w合用自焉序,则返回null
Object first() q回被排序集合的W一个元?br />SortedSet headSet(Object end) q回一个包含小于end元素的SortedSet
Object last() q回调用排序集合的最后一个元?br />SortedSet subSet(Object start,Object end) 包括从start到end-1
SortedSet tailSet(Object start) q回包含大于{于start的元?br /> 

ArrayList扩展AstractListc,q执行List接口。ArrayList支持动态长度的数组?br />LinkList扩展了AbstractSequentialListQ执行List接口。提供连接列表?br />HashSet扩展AbstractSet实现Set接口Q元素没有顺序。对于大集合提供帔RU基本操作?br />TreeSet使用树来存储的SetQ对象按升序存储。访问和索非常快?/p>

iterator实现Iterator接口或者ListIterator接口?br />Iterator接口
boolean hasNext()
Object next() 如果没有下一个元素则引发NoSuchElementException异常?br />void remove() 删除当前元素Q如果试囑֜调用next()Ҏ后调用remove()Ҏ则引发IllegalStateException异常?br /> 
 

ListIterator接口
void add(Object obj) 一个元素插入到当前元素之前Q调用next()Ҏ返回该元素?br />boolean hasNext()
boolean hasPrevious()
Object next() 如果不存在引发NoSuchElementException
int nextIndex() 如果不存在返回列表的大小
void remove()
void set(Object obj) 修改当前元素

public void test1() {
  ArrayList al = new ArrayList();
  for (int i = 1; i < 10; i++) {
  al.add("ArrayList Element:" + i);
  }
  Iterator itr = al.listIterator();
  while (itr.hasNext()) {
  Object obj = itr.next();
  System.out.println(obj);
  }
  }

public void test2() {
  HashSet hs = new HashSet();
  System.out.println("HashSet");
  for (int i = 1; i < 10; i++) {
  hs.add("HashSet Element:" + i);
  }
  Iterator itr = hs.iterator();
  while (itr.hasNext()) {
  Object obj = itr.next();
  System.out.println(obj);
  }
  }

  public void test3() {
  TreeSet ts = new TreeSet();
  System.out.println("TreeSet");
  for (int i = 1; i < 10; i++) {
  ts.add("TreeSet Element:" + i);
  }
  Iterator itr = ts.iterator();
  while (itr.hasNext()) {
  Object obj = itr.next();
  System.out.println(obj);
  }
  }

  public void test4()
  {
  HashMap hm=new HashMap();
  for ( int i=0;i<10;i++)
  {
  hm.put("item"+i,"value"+i);
  }

  Set set=hm.entrySet();
  Iterator itr=set.iterator();
  while (itr.hasNext())
  {
  Map.Entry me=(Map.Entry)itr.next();
  System.out.println(me.getKey()+";"+me.getValue());
  }

  hm.put("item5","modifyed value");
  System.out.println(hm.get("item5") );

  set=hm.entrySet();
  itr=set.iterator();
  while (itr.hasNext())
  {
  Map.Entry me=(Map.Entry)itr.next();
  System.out.println(me.getKey()+";"+me.getValue());
  }

  }

 

 



]]>
Java反射机制http://www.tkk7.com/balajinima/articles/144748.html李云?/dc:creator>李云?/author>Thu, 13 Sep 2007 02:38:00 GMThttp://www.tkk7.com/balajinima/articles/144748.htmlhttp://www.tkk7.com/balajinima/comments/144748.htmlhttp://www.tkk7.com/balajinima/articles/144748.html#Feedback0http://www.tkk7.com/balajinima/comments/commentRss/144748.htmlhttp://www.tkk7.com/balajinima/services/trackbacks/144748.html阅读全文

]]>
抽象cM接口的区?/title><link>http://www.tkk7.com/balajinima/articles/144688.html</link><dc:creator>李云?/dc:creator><author>李云?/author><pubDate>Thu, 13 Sep 2007 01:03:00 GMT</pubDate><guid>http://www.tkk7.com/balajinima/articles/144688.html</guid><wfw:comment>http://www.tkk7.com/balajinima/comments/144688.html</wfw:comment><comments>http://www.tkk7.com/balajinima/articles/144688.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.tkk7.com/balajinima/comments/commentRss/144688.html</wfw:commentRss><trackback:ping>http://www.tkk7.com/balajinima/services/trackbacks/144688.html</trackback:ping><description><![CDATA[ <p>abstract class和interface是Java语言中对于抽象类定义q行支持的两U机Ӟ正是׃q两U机制的存在Q才赋予了Java强大的面向对象能力。abstract class和interface之间在对于抽象类定义的支持方面具有很大的怼性,甚至可以怺替换Q因此很多开发者在q行抽象cd义时对于abstract class和interface的选择昑־比较随意。其实,两者之间还是有很大的区别的Q对于它们的选择甚至反映出对于问题领域本质的理解、对于设计意囄理解是否正确、合理。本文将对它们之间的区别q行一番剖析,试图l开发者提供一个在二者之间进行选择的依据?<br /> <br />理解抽象c?<br /> <br />abstract class和interface在Java语言中都是用来进行抽象类Q本文中的抽象类q从abstract class译而来Q它表示的是一个抽象体Q而abstract class为Java语言中用于定义抽象类的一U方法,误者注意区分)定义的,那么什么是抽象c,使用抽象c能为我们带来什么好处呢Q?<br /> <br />在面向对象的概念中,我们知道所有的对象都是通过cL描绘的,但是反过来却不是q样。ƈ不是所有的c都是用来描l对象的Q如果一个类中没有包含够的信息来描l一个具体的对象Q这Lcd是抽象类。抽象类往往用来表征我们在对问题领域q行分析、设计中得出的抽象概念,是对一pd看上M同,但是本质上相同的具体概念的抽象。比如:如果我们q行一个图形编辑Y件的开发,׃发现问题领域存在着圆、三角Şq样一些具体概念,它们是不同的Q但是它们又都属于Ş状这样一个概念,形状q个概念在问题领域是不存在的Q它是一个抽象概c正是因为抽象的概念在问题领域没有对应的具体概念Q所以用以表征抽象概늚抽象cL不能够实例化的?<br /> <br />在面向对象领域,抽象cM要用来进行类型隐藏。我们可以构造出一个固定的一l行为的抽象描述Q但是这l行为却能够有Q意个可能的具体实现方式。这个抽象描q就是抽象类Q而这一lQ意个可能的具体实现则表现为所有可能的zcR模块可以操作一个抽象体。由于模块依赖于一个固定的抽象体,因此它可以是不允怿改的Q同Ӟ通过从这个抽象体zQ也可扩展此模块的行为功能。熟悉OCP的读者一定知道,Z能够实现面向对象设计的一个最核心的原则OCP(Open-ClosedPrinciple)Q抽象类是其中的关键所在?<br /> <br />从语法定义层面看abstract class和interface <br /> <br />在语法层面,Java语言对于abstract class和interfacel出了不同的定义方式Q下面以定义一个名为Demo的抽象类Z来说明这U不同?<br /> <br />使用abstract class的方式定义Demo抽象cȝ方式如下Q?<br /> <br />abstract class Demo?<br /> <br />abstract void method1(); <br /> <br />abstract void method2(); <br /> <br />?<br /> <br />?<br /> <br />使用interface的方式定义Demo抽象cȝ方式如下Q?<br /> <br />interface Demo{ <br /> <br />void method1(); <br /> <br />void method2(); <br /> <br />?<br /> <br />} <br /> <br />在abstract class方式中,Demo可以有自q数据成员Q也可以有非abstarct的成员方法,而在interface方式的实CQDemo只能够有静态的不能被修改的数据成员Q也是必须是static final的,不过在interface中一般不定义数据成员Q,所有的成员Ҏ都是abstract的。从某种意义上说Qinterface是一U特DŞ式的abstract class?<br /> <br />从编E的角度来看Qabstract class和interface都可以用来实?design by contract"的思想。但是在具体的用上面还是有一些区别的?<br /> <br />首先Qabstract class在Java语言中表C的是一U承关p,一个类只能使用一ơ承关pR但是,一个类却可以实现多个interface。也许,q是Java语言的设计者在考虑Java对于多重l承的支持方面的一U折中考虑吧?<br /> <br />其次Q在abstract class的定义中Q我们可以赋予方法的默认行ؓ。但是在interface的定义中Q方法却不能拥有默认行ؓQؓ了绕q这个限Ӟ必须使用委托Q但是这会增加一些复杂性,有时会造成很大的麻烦?<br /> <br />在抽象类中不能定义默认行存在另一个比较严重的问题Q那是可能会造成l护上的ȝ。因为如果后来想修改cȝ界面Q一般通过abstract class或者interface来表C)以适应新的情况Q比如,d新的Ҏ或者给已用的方法中d新的参数Q时Q就会非常的ȝQ可能要p很多的时_对于zcd多的情况Q尤为如此)。但是如果界面是通过abstract class来实现的Q那么可能就只需要修改定义在abstract class中的默认行ؓ可以了?<br /> <br />同样Q如果不能在抽象cM定义默认行ؓQ就会导致同LҎ实现出现在该抽象cȝ每一个派生类中,q反?one ruleQone place"原则Q造成代码重复Q同样不利于以后的维护。因此,在abstract class和interface间进行选择时要非常的小心?<br /> <br />从设计理念层面看abstract class和interface <br /> <br />上面主要从语法定义和~程的角度论qCabstract class和interface的区别,q些层面的区别是比较低层ơ的、非本质的。本节从另一个层面:abstract class和interface所反映出的设计理念Q来分析一下二者的区别。作者认为,从这个层面进行分析才能理解二者概늚本质所在?<br /> <br />前面已经提到q,abstarct class在Java语言中体C一U承关p,要想使得l承关系合理Q父cdzcM间必d?isa"关系Q即父类和派生类在概忉|质上应该是相同的Q参考文献?〕中有关?isa"关系的大幅深入的论qͼ有兴的读者可以参考)。对于interface来说则不Ӟq不要求interface的实现者和interface定义在概忉|质上是一致的Q仅仅是实现了interface定义的契U而已。ؓ了便于理解Q下面将通过一个简单的实例q行说明?<br /> <br />考虑q样一个例子,假设在我们的问题领域中有一个关于Door的抽象概念,该Doorh执行两个动作open和closeQ此时我们可以通过abstract  class或者interface来定义一个表C抽象概念的类型,定义方式分别如下所C: <br /> <br />使用abstract class方式定义DoorQ?<br /> <br />abstract class Door{ <br /> <br />abstract void open(); <br /> <br />abstract void close()Q?<br /> <br />} <br /> <br />使用interface方式定义DoorQ?<br /> <br />interface Door{ <br /> <br />void open(); <br /> <br />void close(); <br /> <br />} <br /> <br />其他具体的Doorcd可以extends使用abstract  class方式定义的Door或者implements使用interface方式定义的Door。看h好像使用abstract  class和interface没有大的区别?/p> <p> </p> <p>如果现在要求Doorq要h报警的功能。我们该如何设计针对该例子的cȝ构呢Q在本例中,主要是ؓ了展Cabstract   class和interface反映在设计理念上的区别,其他斚w无关的问题都做了化或者忽略)Q下面将|列出可能的解决ҎQƈ从设计理念层面对q些不同的方案进行分析?<br /> <br />解决Ҏ一Q?<br /> <br />单的在Door的定义中增加一个alarmҎQ如下: <br /> <br />abstract class Door{ <br /> <br />abstract void open(); <br /> <br />abstract void close()Q?<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 />那么h报警功能的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 />q种Ҏq反了面向对象设计中的一个核心原则ISPQInterfaceSegregationPricipleQ,在Door的定义中把Door概念本n固有的行为方法和另外一个概?报警?的行为方法؜在了一赗这样引L一个问题是那些仅仅依赖于Doorq个概念的模块会因ؓ"报警?q个概念的改变(比如Q修改alarmҎ的参敎ͼ而改变,反之依然?<br /> <br />解决Ҏ二: <br /> <br />既然open、close和alarm属于两个不同的概念,ҎISP原则应该把它们分别定义在代表q两个概늚抽象cM。定义方式有Q这两个概念都用abstract  class方式定义Q两个概念都使用interface方式定义Q一个概念用abstract  class方式定义Q另一个概念用interface方式定义?<br /> <br />昄Q由于Java语言不支持多重承,所以两个概念都使用abstract  class方式定义是不可行的。后面两U方式都是可行的Q但是对于它们的选择却反映出对于问题领域中的概念本质的理解、对于设计意囄反映是否正确、合理。我们一一来分析、说明?<br /> <br />如果两个概念都用interface方式来定义,那么反映出两个问题Q?、我们可能没有理解清楚问题领域,AlarmDoor在概忉|质上到底是Doorq是报警器?2、如果我们对于问题领域的理解没有问题Q比如:我们通过对于问题领域的分析发现AlarmDoor在概忉|质上和Door是一致的Q那么我们在实现时就没有能够正确的揭C我们的设计意图Q因为在q两个概늚定义上(均用interface方式定义Q反映不Zq含义?<br /> <br />如果我们对于问题领域的理解是QAlarmDoor在概忉|质上是DoorQ同时它有具有报警的功能。我们该如何来设计、实现来明确的反映出我们的意思呢Q前面已l说q,abstract class在Java语言中表CZU承关p,而承关pd本质上是"isa"关系。所以对于Doorq个概念Q我们应该用abstarct class方式来定义。另外,AlarmDoor又具有报警功能,说明它又能够完成报警概念中定义的行ؓQ所以报警概念可以通过interface方式定义。如下所C: <br /> <br />abstract  class  Door{ <br /> <br />abstract  void  open(); <br /> <br />abstract  void  close()Q?<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 />q种实现方式基本上能够明的反映出我们对于问题领域的理解Q正的揭示我们的设计意图。其实abstract  class表示的是"isa"关系Qinterface表示的是"likea"关系Q大家在选择时可以作Z个依据,当然q是建立在对问题领域的理解上的,比如Q如果我们认为AlarmDoor在概忉|质上是报警器Q同时又hDoor的功能,那么上述的定义方式就要反q来了?/p> <p> </p> <p> </p> <img src ="http://www.tkk7.com/balajinima/aggbug/144688.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.tkk7.com/balajinima/" target="_blank">李云?/a> 2007-09-13 09:03 <a href="http://www.tkk7.com/balajinima/articles/144688.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java dtxt文本文g(转发)http://www.tkk7.com/balajinima/articles/140810.html李云?/dc:creator>李云?/author>Wed, 29 Aug 2007 03:01:00 GMThttp://www.tkk7.com/balajinima/articles/140810.htmlhttp://www.tkk7.com/balajinima/comments/140810.htmlhttp://www.tkk7.com/balajinima/articles/140810.html#Feedback0http://www.tkk7.com/balajinima/comments/commentRss/140810.htmlhttp://www.tkk7.com/balajinima/services/trackbacks/140810.html
d所有的文g数据
<%@ page contentType="text/html;charset=gb2312"%>
<%@ page import="java.io.*,java.lang.*"%>
<html>
<head>
<title>d所有的文g数据</title>
</head>
<body>
<%
String path=request.getRealPath(".");
FileReader fr=new FileReader(path + "file://ReadData.txt/");
//关键在于dq程中,要判断所d的字W是否已l到了文件的末尾Qƈ且这个字W是不是文g中的断行W,卛_断该字符值是否ؓ13?br />int c=fr.read();//从文件中d一个字W?br />//判断是否已读到文件结?br />while(c!=-1){
 out.print((char)c);//输出d的数?br /> c=fr.read();//从文件中l箋d数据
 if(c==13){//判断是否为断行字W?br />  out.print("<br>");//输出分行标签
  fr.skip(1);//略过一个字W?br />  //c=fr.read();//d一个字W?br /> }
}
fr.close();
%>
</body>
</html>

一行一行读取数?br /><%@ page contentType="text/html;charset=gb2312"%>
<%@ page import="java.io.*"%>
<html>
<head>
<title>文gd</title>
</head>
<body>
<%
 String path=request.getRealPath("");//取得当前目录的\?br /> FileReader fr=new FileReader(path + "file://file//inc//t.txt%22);//建立FileReader对象Qƈ实例化ؓfr
 BufferedReader br=new BufferedReader(fr);//建立BufferedReader对象Qƈ实例化ؓbr
 String Line=br.readLine();//从文件读取一行字W串
 //判断d到的字符串是否不为空
 while(Line!=null){
  out.println(Line + "<br>");//输出从文件中d的数?br />  Line=br.readLine();//从文件中l箋d一行数?br /> }
 br.close();//关闭BufferedReader对象
 fr.close();//关闭文g
%>
</body>
</html>

略过文g中的字符不读?br /><%@ page contentType="text/html;charset=gb2312"%>
<%@ page import="java.io.*"%>
<html>
<head>
<title>略过字节不读?lt;/title>
</head>
<body>
<%
String path=request.getRealPath(".");
FileReader fr=new FileReader(path + "file://ReadData.txt/");
fr.skip(2);//跌2个字?br />int c=fr.read();//d一个字?br />while(c!=-1){
 out.print((char)c);
 c=fr.read();
}
fr.close();
%>
</body>
</html>

数据写入文?br /><%@ page contentType="text/html;charset=gb2312"%>
<%@ page import="java.io.*"%>
<html>
<head>
<title>数据写入文?lt;/title>
</head>
<body>
<%
String path=request.getRealPath(".");
FileWriter fw=new FileWriter(path + "file://WriteData.txt%22);//建立FileWriter对象Qƈ实例化fw
//字W串写入文g
fw.write("大家好!");
fw.write("本书是《JSP~程技巧?);
fw.write("请多多指教!");
fw.write("email:stride@sina.com");
fw.close();
FileReader fr=new FileReader(path + "file://WriteData.txt/");
BufferedReader br=new BufferedReader(fr);//建立BufferedReader对象Qƈ实例化ؓbr
String Line=br.readLine();
//d一行数?br />out.println(Line + "<br>");
br.close();//关闭BufferedReader对象
fr.close();
%>
</body>
</html>

写入文件的数据分行
<%@ page contentType="text/html;charset=gb2312"%>
<%@ page import="java.io.*"%>
<html>
<head>
<title>写入文件的数据分行</title>
</head>
<body>
<%
String path=request.getRealPath(".");
FileWriter fw=new FileWriter(path + "file://WriteData.txt/");
BufferedWriter bw=new BufferedWriter(fw);
bw.write("大家好!");
bw.write("本书是《JSP~程技巧》?);
bw.newLine();//断行
bw.write("请多多指教!");
bw.newLine();//断行
bw.write("email: stride@sina.com");
bw.flush();//数据更新至文g
fw.close();//关闭文g?br />out.println("写入文g内容为:<br>");
FileReader fr=new FileReader(path + "file://WriteData.txt/");
BufferedReader br=new BufferedReader(fr);
String Line=br.readLine();//d一行数?br />while(Line!=null){
 out.println(Line + "<br>");
 Line=br.readLine();
}
fr.close();
%>
</body>
</html>

如何数据追加写入到文g
<%@ page contentType="text/html;charset=gb2312"%>
<%@ page import="java.io.*"%>
<html>
<head>
<title>写入文件的数据分行</title>
</head>
<body>
<%
String path=request.getRealPath(".");
RandomAccessFile rf=new RandomAccessFile(path + "file://WriteData.txt%22,%22rw%22);//定义一个类RandomAccessFile的对象,q实例化
rf.seek(rf.length());//指针移动到文g末尾
rf.writeBytes("\nAppend a line to the file!");
rf.close();//关闭文g?br />out.println("写入文g内容为:<br>");
FileReader fr=new FileReader(path + "file://WriteData.txt/");
BufferedReader br=new BufferedReader(fr);//d文g的BufferedRead对象
String Line=br.readLine();
while(Line!=null){
 out.println(Line + "<br>");
 Line=br.readLine();
}
fr.close();//关闭文g
%>
</body>
</html>
 
import java.util.*;
import java.io.*;
public class ReadIni
{
  public static void main(String[] args)
    throws Exception
  {
    Properties proDB = new Properties();
    FileInputStream in = new FileInputStream("DBConfig.ini");
    proDB.load(in);
    String jdbc = proDB.getProperty("jdbc");
    String dburl = proDB.getProperty("dburl");
    String userid = proDB.getProperty("userid");
    String password = proDB.getProperty("password");

    System.out.println(jdbc);
    System.out.println(dburl);
    System.out.println(userid);
    System.out.println(password);
  }
}

DBConfig.ini:

dburl=jdbcracle:thin:@202.16.147.104:1521ub
userid=user
password=password
jdbc=oracle.jdbc.driver.OracleDriver

 



]]>
վ֩ģ壺 ĻmvѸӰ| ޹˾þһþ| һƷ| ɫwwwվ| þһ߹ۿ2020| һƵ| ۺۺ| Ʒһ| ѹۿƬëƬ| Ѷ| þֻƷ99re| С˵ ͼƬ | ޹va| 99߹ۿƷ99| ŷ͵ҹɫ| ŷ| Ƭ߹ۿ| ޾Ʒ鶹ר| 99þѹƷ| ޾ƷƷþ99| ˵վ| þó˹Ʒ| Av뾫Ʒɫҹ| ˿wwwƵ| ޹VA߹ۿ| ޾Ʒ޲߲| ŮѹۿˬˬˬƵ| һ24޹˾| þþѹ۳ӰԺ| AV֮պƷ| ˾Ʒþ޸岻| һƵ߹ۿİ| 777޾Ʒþþþþ| ĻƵ| պVAĻ| Ʒרţţ| ѹۿͰŮƵ| vavavaӰĻ | avƬ߹ۿ | Ƶ| Ļպ|