﻿<?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-java-随笔分类-Java</title><link>http://www.blogjava.net/zhaozhenlin1224/category/43791.html</link><description /><language>zh-cn</language><lastBuildDate>Thu, 30 Jun 2011 21:21:03 GMT</lastBuildDate><pubDate>Thu, 30 Jun 2011 21:21:03 GMT</pubDate><ttl>60</ttl><item><title>深入研究java.lang.ThreadLocal类</title><link>http://www.blogjava.net/zhaozhenlin1224/archive/2011/06/30/353457.html</link><dc:creator>java/j2ee</dc:creator><author>java/j2ee</author><pubDate>Thu, 30 Jun 2011 10:46:00 GMT</pubDate><guid>http://www.blogjava.net/zhaozhenlin1224/archive/2011/06/30/353457.html</guid><wfw:comment>http://www.blogjava.net/zhaozhenlin1224/comments/353457.html</wfw:comment><comments>http://www.blogjava.net/zhaozhenlin1224/archive/2011/06/30/353457.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/zhaozhenlin1224/comments/commentRss/353457.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zhaozhenlin1224/services/trackbacks/353457.html</trackback:ping><description><![CDATA[<div><div><strong>一、概述</strong></div> <div><strong></strong>&nbsp;</div> <div>ThreadLocal是什么呢？其实ThreadLocal并非是一个线程的本地实现版本，它并不是一个Thread，而是 threadlocalvariable(线程局部变量)。也许把它命名为ThreadLocalVar更加合适。线程局部变量 (ThreadLocal)其实的功用非常简单，就是为每一个使用该变量的线程都提供一个变量值的副本，是Java中一种较为特殊的线程绑定机制，是每一 个线程都可以独立地改变自己的副本，而不会和其它线程的副本冲突。</div> <div>&nbsp;</div> <div>从线程的角度看，每个线程都保持一个对其线程局部变量副本的隐式引用，只要线程是活动的并且 ThreadLocal 实例是可访问的；在线程消失之后，其线程局部实例的所有副本都会被垃圾回收（除非存在对这些副本的其他引用）。</div> <div>&nbsp;</div> <div>通过ThreadLocal存取的数据，总是与当前线程相关，也就是说，JVM 为每个运行的线程，绑定了私有的本地实例存取空间，从而为多线程环境常出现的并发访问问题提供了一种隔离机制。</div> <div>&nbsp;</div> <div>ThreadLocal是如何做到为每一个线程维护变量的副本的呢？其实实现的思路很简单，在ThreadLocal类中有一个Map，用于存储每一个线程的变量的副本。</div> <div>&nbsp;</div> <div>概括起来说，对于多线程资源共享的问题，同步机制采用了&#8220;以时间换空间&#8221;的方式，而ThreadLocal采用了&#8220;以空间换时间&#8221;的方式。前者仅提供一份变量，让不同的线程排队访问，而后者为每一个线程都提供了一份变量，因此可以同时访问而互不影响。</div> <div>&nbsp;</div> <div><strong>二、API说明</strong></div> <div>&nbsp;</div> <div>ThreadLocal() </div> <div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 创建一个线程本地变量。</div> <div>&nbsp;</div> <div>T get() </div> <div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 返回此线程局部变量的当前线程副本中的值，如果这是线程第一次调用该方法，则创建并初始化此副本。 </div> <div>&nbsp;</div> <div>protected&nbsp; T initialValue() </div> <div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 返回此线程局部变量的当前线程的初始值。最多在每次访问线程来获得每个线程局部变量时调用此方法一次，即线程第一次使用  get() 方法访问变量的时候。如果线程先于 get 方法调用 set(T) 方法，则不会在线程中再调用 initialValue 方法。 </div> <div>&nbsp;</div> <div>&nbsp;&nbsp; 若该实现只返回 null；如果程序员希望将线程局部变量初始化为 null 以外的某个值，则必须为 ThreadLocal  创建子类，并重写此方法。通常，将使用匿名内部类。initialValue 的典型实现将调用一个适当的构造方法，并返回新构造的对象。</div> <div>&nbsp;</div> <div>void remove() </div> <div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 移除此线程局部变量的值。这可能有助于减少线程局部变量的存储需求。如果再次访问此线程局部变量，那么在默认情况下它将拥有其 initialValue。 </div> <div>&nbsp;</div> <div>void set(T value) </div> <div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 将此线程局部变量的当前线程副本中的值设置为指定值。许多应用程序不需要这项功能，它们只依赖于 initialValue() 方法来设置线程局部变量的值。 </div> <div>&nbsp;</div> <div>在程序中一般都重写initialValue方法，以给定一个特定的初始值。</div> <div>&nbsp;</div> <div>&nbsp;</div> <div><strong>三、典型实例</strong></div> <div>&nbsp;</div> <div>1、Hiberante的Session 工具类HibernateUtil</div> <div>这个类是Hibernate官方文档中HibernateUtil类，用于session管理。</div> <div>&nbsp;</div> <div> <div> <div style="border: 1px solid #aaaaaa; padding: 5px; background-color: #f5f5f5;"> <div>public class HibernateUtil {</div> <div>&nbsp;&nbsp;&nbsp; private static Log log = LogFactory.getLog(HibernateUtil.class);</div> <div>&nbsp;&nbsp;&nbsp; private static final SessionFactory sessionFactory;&nbsp;&nbsp;&nbsp;&nbsp; //定义SessionFactory</div> <div>&nbsp;</div> <div>&nbsp;&nbsp;&nbsp; static {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 通过默认配置文件hibernate.cfg.xml创建SessionFactory<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sessionFactory = new Configuration().configure().buildSessionFactory();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (Throwable ex) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; log.error("初始化SessionFactory失败！", ex);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw new ExceptionInInitializerError(ex);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp; }</div> <div><br />&nbsp;&nbsp;&nbsp; //创建线程局部变量session，用来保存Hibernate的Session<br />&nbsp;&nbsp;&nbsp; public static final ThreadLocal session = new ThreadLocal();</div> <div>&nbsp;</div> <div>&nbsp;&nbsp;&nbsp; /**<br />&nbsp;&nbsp;&nbsp;&nbsp; * 获取当前线程中的Session<br />&nbsp;&nbsp;&nbsp;&nbsp; * @return Session<br />&nbsp;&nbsp;&nbsp;&nbsp; * @throws HibernateException<br />&nbsp;&nbsp;&nbsp;&nbsp; */<br />&nbsp;&nbsp;&nbsp; public static Session currentSession() throws HibernateException {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Session s = (Session) session.get();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 如果Session还没有打开，则新开一个Session<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (s == null) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; s = sessionFactory.openSession();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; session.set(s);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //将新开的Session保存到线程局部变量中<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return s;<br />&nbsp;&nbsp;&nbsp; }</div> <div>&nbsp;</div> <div>&nbsp;&nbsp;&nbsp; public static void closeSession() throws HibernateException {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //获取线程局部变量，并强制转换为Session类型<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Session s = (Session) session.get();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; session.set(null);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (s != null)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; s.close();<br />&nbsp;&nbsp;&nbsp; }<br />}</div></div></div></div> <div>&nbsp;</div> <div>在这个类中，由于没有重写ThreadLocal的initialValue()方法，则首次创建线程局部变量session其初始值为 null，第一次调用currentSession()的时候，线程局部变量的get()方法也为null。因此，对session做了判断，如果为 null，则新开一个Session，并保存到线程局部变量session中，这一步非常的关键，这也是&#8220;public static final  ThreadLocal session = new ThreadLocal()&#8221;所创建对象session能强制转换为Hibernate  Session对象的原因。</div> <div>&nbsp;</div> <div>2、另外一个实例</div> <div>创建一个Bean，通过不同的线程对象设置Bean属性，保证各个线程Bean对象的独立性。</div> <div>&nbsp;</div> <div> <div> <div> <div> <div> <div> <div> <div style="border: 1px solid #aaaaaa; padding: 5px; background-color: #f5f5f5;"> <div>/**<br />&nbsp;* Created by IntelliJ IDEA.<br />&nbsp;* User: leizhimin<br />&nbsp;* Date: 2007-11-23<br />&nbsp;* Time: 10:45:02<br />&nbsp;* 学生<br />&nbsp;*/<br />public class Student {<br />&nbsp;&nbsp;&nbsp; private int age = 0;&nbsp;&nbsp; //年龄</div> <div>&nbsp;</div> <div>&nbsp;&nbsp;&nbsp; public int getAge() {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return this.age;<br />&nbsp;&nbsp;&nbsp; }</div> <div>&nbsp;</div> <div>&nbsp;&nbsp;&nbsp; public void setAge(int age) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.age = age;<br />&nbsp;&nbsp;&nbsp; }<br />}</div></div></div></div></div></div></div></div></div> <div>&nbsp;</div> <div> <div> <div> <div style="border: 1px solid #aaaaaa; padding: 5px; background-color: #f5f5f5;"> <div>/**<br />&nbsp;* Created by IntelliJ IDEA.<br />&nbsp;* User: leizhimin<br />&nbsp;* Date: 2007-11-23<br />&nbsp;* Time: 10:53:33<br />&nbsp;* 多线程下测试程序<br />&nbsp;*/<br />public class ThreadLocalDemo implements Runnable {<br />&nbsp;&nbsp;&nbsp; //创建线程局部变量studentLocal，在后面你会发现用来保存Student对象<br />&nbsp;&nbsp;&nbsp; private final static ThreadLocal studentLocal = new ThreadLocal();</div> <div>&nbsp;</div> <div>&nbsp;&nbsp;&nbsp; public static void main(String[] agrs) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ThreadLocalDemo td = new ThreadLocalDemo();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Thread t1 = new Thread(td, "a");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Thread t2 = new Thread(td, "b");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; t1.start();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; t2.start();<br />&nbsp;&nbsp;&nbsp; }</div> <div>&nbsp;</div> <div>&nbsp;&nbsp;&nbsp; public void run() {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; accessStudent();<br />&nbsp;&nbsp;&nbsp; }</div> <div>&nbsp;</div> <div>&nbsp;&nbsp;&nbsp; /**<br />&nbsp;&nbsp;&nbsp;&nbsp; * 示例业务方法，用来测试<br />&nbsp;&nbsp;&nbsp;&nbsp; */<br />&nbsp;&nbsp;&nbsp; public void accessStudent() {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //获取当前线程的名字<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String currentThreadName = Thread.currentThread().getName();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(currentThreadName + " is running!");</div> <div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //产生一个随机数并打印<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Random random = new Random();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int age = random.nextInt(100);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("thread " + currentThreadName + " set age to:" + age);</div> <div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //获取一个Student对象，并将随机数年龄插入到对象属性中<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Student student = getStudent();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; student.setAge(age);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("thread " + currentThreadName + " first read age is:" + student.getAge());<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Thread.sleep(500);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; catch (InterruptedException ex) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ex.printStackTrace();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("thread " + currentThreadName + " second read age is:" + student.getAge());<br />&nbsp;&nbsp;&nbsp; }</div> <div>&nbsp;</div> <div>&nbsp;&nbsp;&nbsp; protected Student getStudent() {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //获取本地线程变量并强制转换为Student类型<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Student student = (Student) studentLocal.get();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //线程首次执行此方法的时候，studentLocal.get()肯定为null<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (student == null) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //创建一个Student对象，并保存到本地线程变量studentLocal中<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; student = new Student();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; studentLocal.set(student);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return student;<br />&nbsp;&nbsp;&nbsp; }<br />}</div></div></div></div></div> <div>&nbsp;</div> <div>运行结果：</div> <div> <div> <div style="border: 1px solid #cccccc; padding: 4px; font-size: 10pt; width: 98%; color: #000000; line-height: 16px; font-family: verdana,宋体; background-color: #eeeeee;">a is running! <br />thread a set age to:76 <br />b is running! <br />thread b set age to:27 <br />thread a first read age is:76 <br />thread b first read age is:27 <br />thread a second read age is:76 <br />thread b second read age is:27</div></div></div> <div>&nbsp;</div> <div>可以看到a、b两个线程age在不同时刻打印的值是完全相同的。这个程序通过妙用ThreadLocal，既实现多线程并发，游兼顾数据的安全性。</div> <div>&nbsp;</div> <div><strong>四、总结</strong></div> <div><strong></strong>&nbsp;</div> <div>ThreadLocal使用场合主要解决多线程中数据数据因并发产生不一致问题。ThreadLocal为每个线程的中并发访问的数据提供一个副本，通过访问副本来运行业务，这样的结果是耗费了内存，单大大减少了线程同步所带来性能消耗，也减少了线程并发控制的复杂度。</div> <div>&nbsp;</div> <div>ThreadLocal不能使用原子类型，只能使用Object类型。ThreadLocal的使用比synchronized要简单得多。 </div> <div>&nbsp;</div> <div>ThreadLocal和Synchonized都用于解决多线程并发访问。但是ThreadLocal与synchronized有本质的区 别。synchronized是利用锁的机制，使变量或代码块在某一时该只能被一个线程访问。而ThreadLocal为每一个线程都提供了变量的副本， 使得每个线程在某一时间访问到的并不是同一个对象，这样就隔离了多个线程对数据的数据共享。而Synchronized却正好相反，它用于在多个线程间通 信时能够获得数据共享。 </div> <div>&nbsp;</div> <div>Synchronized用于线程间的数据共享，而ThreadLocal则用于线程间的数据隔离。 </div> <div>&nbsp;</div> <div>当然ThreadLocal并不能替代synchronized,它们处理不同的问题域。Synchronized用于实现同步机制，比ThreadLocal更加复杂。 </div> <div>&nbsp;</div> <div>&nbsp;</div> <div><strong>五、ThreadLocal使用的一般步骤</strong></div> <div>&nbsp;</div> <div>1、在多线程的类（如ThreadDemo类）中，创建一个ThreadLocal对象threadXxx，用来保存线程间需要隔离处理的对象xxx。</div> <div>2、在ThreadDemo类中，创建一个获取要隔离访问的数据的方法getXxx()，在方法中判断，若ThreadLocal对象为null时候，应该new()一个隔离访问类型的对象，并强制转换为要应用的类型。</div> <div>3、在ThreadDemo类的run()方法中，通过getXxx()方法获取要操作的数据，这样可以保证每个线程对应一个数据对象，在任何时刻都操作的是这个对象。</div> <div>&nbsp;</div> <div>&nbsp;</div> <div>参考文档：</div> <div>JDK 官方文档</div> <div><a href="http://www.java3z.com/cwbwebhome/article/article2a/271.html?id=319">[url]http://www.java3z.com/cwbwebhome/article/article2a/271.html?id=319[/url]</a></div> <div><a href="http://www.java3z.com/cwbwebhome/article/article2/2952.html?id=1648[/url]">[url]http://www.java3z.com/cwbwebhome/article/article2/2952.html?id=1648[/url]</a></div> <div>&nbsp;</div></div><img src ="http://www.blogjava.net/zhaozhenlin1224/aggbug/353457.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zhaozhenlin1224/" target="_blank">java/j2ee</a> 2011-06-30 18:46 <a href="http://www.blogjava.net/zhaozhenlin1224/archive/2011/06/30/353457.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java.util.concurrent</title><link>http://www.blogjava.net/zhaozhenlin1224/archive/2011/06/26/353025.html</link><dc:creator>java/j2ee</dc:creator><author>java/j2ee</author><pubDate>Sun, 26 Jun 2011 05:49:00 GMT</pubDate><guid>http://www.blogjava.net/zhaozhenlin1224/archive/2011/06/26/353025.html</guid><wfw:comment>http://www.blogjava.net/zhaozhenlin1224/comments/353025.html</wfw:comment><comments>http://www.blogjava.net/zhaozhenlin1224/archive/2011/06/26/353025.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/zhaozhenlin1224/comments/commentRss/353025.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zhaozhenlin1224/services/trackbacks/353025.html</trackback:ping><description><![CDATA[<div>private static ExecutorService exs = Executors.newCachedThreadPool();// 线程池</div>exs.submit(Callable or Runable)返回Future对象<br /><div><a href="http://images.cnblogs.com/cnblogs_com/mshijie/WindowsLiveWriter/javaExecutor_974/c5653557-d5d5-3cca-b2d8-36b11dadd621_2.jpg">Future&lt;V&gt; 代表一个异步执行的操作，通过get()方法可以获得操作的结果，如果异步操作还没有完成，则，get()会使当前线程阻塞。 FutureTask&lt;V&gt;实现了Future&lt;V&gt;和Runable&lt;V&gt;。Callable代表一个有返回值得 操作。</a><br />Runnable通过 public void run方法处理业务逻辑，执行线程逻辑单元。<br />Callable通过public object call()实现业务逻辑，执行线程逻辑单元，不同的是callable有返回值。是不是可以认为callable可以代替runnable呢？<br />不同之处在于，把runnable交给thread执行，把callable交给ExecutorService执行。<br />&nbsp;futuretask实现了Future和runnable接口,构造函数参数允许callable对象。注意Future是一个接口,不能实例化。<br />是不是exs.submit(futuretask)来代替thread.start()呢?(futuretask通过 构造参数里的callable执行业务逻辑),这样做的好处还可以通过get方法获取返回结果.</div>单线程。<div>ExecutorService提交线程执行的的方法<br /><div>&nbsp;&nbsp;&nbsp; void execute(Runnable command);</div></div><div>&nbsp;&nbsp;&nbsp; &lt;T&gt; Future&lt;T&gt; submit(Callable&lt;T&gt; task);<br />&nbsp;&nbsp; 成功执行后，通过get方法获取到指定的result值<br />&nbsp;&nbsp;&nbsp; &lt;T&gt; Future&lt;T&gt; submit(Runnable task, T result);<br />&nbsp;&nbsp; 线程执行结束后，通过 get方法获取到null<br />&nbsp;&nbsp;&nbsp; Future&lt;?&gt; submit(Runnable task);</div><span style="color: red;">注意三大接口 runnable callable future和RunnableFuture,FutureTask实现了RunnableFuture接口</span><br /><div><p align="left"><span style="background-color: silver; background-image: none; background-repeat: repeat; background-attachment: scroll; background-position: 0% 0%; -moz-background-size: auto auto; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; font-size: 10pt;">Callable</span><span style="font-size: 10pt;">&lt;Integer&gt; func = </span><strong><span style="font-size: 10pt;">new</span></strong><span style="font-size: 10pt;"> <span style="background-color: silver; background-image: none; background-repeat: repeat; background-attachment: scroll; background-position: 0% 0%; -moz-background-size: auto auto; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">Callable</span>&lt;Integer&gt;(){</span></p> <p align="left"><span style="font-size: 10pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><strong><span style="font-size: 10pt;">public</span></strong><span style="font-size: 10pt;"> Integer call() </span><strong><span style="font-size: 10pt;">throws</span></strong><span style="font-size: 10pt;"> Exception {</span></p> <p align="left"><span style="font-size: 10pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.</span><em><span style="font-size: 10pt;">out</span></em><span style="font-size: 10pt;">.println(</span><span style="font-size: 10pt;">"inside callable"</span><span style="font-size: 10pt;">);</span></p> <p align="left"><span style="font-size: 10pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Thread.<em>sleep</em>(1000);</span></p> <p align="left"><span style="font-size: 10pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><strong><span style="font-size: 10pt;">return</span></strong> <strong><span style="font-size: 10pt;">new</span></strong><span style="font-size: 10pt;"> Integer(8);</span></p> <p align="left"><span style="font-size: 10pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></p> <p align="left"><span style="font-size: 10pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; };&nbsp;&nbsp;&nbsp;&nbsp; </span></p> <p align="left"><span style="font-size: 10pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FutureTask&lt;Integer&gt; futureTask&nbsp;= </span><strong><span style="font-size: 10pt;">new</span></strong><span style="font-size: 10pt;"> FutureTask&lt;Integer&gt;(func);</span></p> <p align="left"><span style="font-size: 10pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Thread newThread = </span><strong><span style="font-size: 10pt;">new</span></strong><span style="font-size: 10pt;"> Thread(futureTask);</span></p> <p align="left"><span style="font-size: 10pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; newThread.start();</span><span><br /></span></p><p align="left"><span>&nbsp;&nbsp;&nbsp;&nbsp; try&nbsp;{&nbsp;&nbsp;</span><br /></p><p align="left">&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(<span>"blocking&nbsp;here");&nbsp;&nbsp;</span><br /></p><p align="left">&nbsp;&nbsp;&nbsp; Integer&nbsp;result&nbsp;=&nbsp;futureTask.get();&nbsp;&nbsp;<br /></p><p align="left">&nbsp;&nbsp;&nbsp; System.out.println(result); <br /></p><p align="left">&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp;<span>catch&nbsp;(InterruptedException&nbsp;ignored)&nbsp;{&nbsp; </span><br /></p><p align="left">}&nbsp;<span>catch&nbsp;(ExecutionException&nbsp;ignored)&nbsp;{&nbsp; </span><br /></p><p align="left">}&nbsp; <br /></p></div><br /><br />关于FutureTask<br /><div><ol start="1"><li>&nbsp;&nbsp;&nbsp;<span>class&nbsp;SumCalculator&nbsp;implements&nbsp;Callable&lt;Long&gt;&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>private&nbsp;int[]&nbsp;numbers;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>private&nbsp;int&nbsp;start;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>private&nbsp;int&nbsp;end;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>public&nbsp;SumCalculator(final&nbsp;int[]&nbsp;numbers,&nbsp;int&nbsp;start,&nbsp;int&nbsp;end)&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>this.numbers&nbsp;=&nbsp;numbers;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>this.start&nbsp;=&nbsp;start;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>this.end&nbsp;=&nbsp;end;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>public&nbsp;Long&nbsp;call()&nbsp;throws&nbsp;Exception&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Long&nbsp;sum&nbsp;=&nbsp;0l;&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>for&nbsp;(int&nbsp;i&nbsp;=&nbsp;start;&nbsp;i&nbsp;&lt;&nbsp;end;&nbsp;i++)&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sum&nbsp;+=&nbsp;numbers[i];&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>return&nbsp;sum;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp; <br /></li></ol></div><br /><div><ol start="1"><li><br /></li><div><ol start="1"><li>SumCalculator&nbsp;subCalc&nbsp;=&nbsp;<span>new&nbsp;SumCalculator(numbers,&nbsp;start,&nbsp;end);&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FutureTask&lt;Long&gt;&nbsp;task&nbsp;=&nbsp;<span>new&nbsp;FutureTask&lt;Long&gt;(subCalc);&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tasks.add(task);&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>if&nbsp;(!exec.isShutdown())&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exec.submit(task);&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp; <br /></li></ol></div><li><br /></li><li><br /></li></ol></div><div><ol start="1"><li>&nbsp;<span>public&nbsp;Long&nbsp;getResult()&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Long&nbsp;result&nbsp;=&nbsp;0l;&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>for&nbsp;(Future&lt;Long&gt;&nbsp;task&nbsp;:&nbsp;tasks)&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>try&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>//&nbsp;如果计算未完成则阻塞&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Long&nbsp;subSum&nbsp;=&nbsp;task.get();&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result&nbsp;+=&nbsp;subSum;&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span>catch&nbsp;(InterruptedException&nbsp;e)&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace();&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span>catch&nbsp;(ExecutionException&nbsp;e)&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace();&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>return&nbsp;result;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp; <br /></li></ol></div><img src ="http://www.blogjava.net/zhaozhenlin1224/aggbug/353025.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zhaozhenlin1224/" target="_blank">java/j2ee</a> 2011-06-26 13:49 <a href="http://www.blogjava.net/zhaozhenlin1224/archive/2011/06/26/353025.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>正则表达式</title><link>http://www.blogjava.net/zhaozhenlin1224/archive/2011/01/09/342630.html</link><dc:creator>java/j2ee</dc:creator><author>java/j2ee</author><pubDate>Sun, 09 Jan 2011 10:40:00 GMT</pubDate><guid>http://www.blogjava.net/zhaozhenlin1224/archive/2011/01/09/342630.html</guid><wfw:comment>http://www.blogjava.net/zhaozhenlin1224/comments/342630.html</wfw:comment><comments>http://www.blogjava.net/zhaozhenlin1224/archive/2011/01/09/342630.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/zhaozhenlin1224/comments/commentRss/342630.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zhaozhenlin1224/services/trackbacks/342630.html</trackback:ping><description><![CDATA[<ol class="dp-j" start="1">
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;regex&nbsp;=&nbsp;<span class="string">"&lt;a&gt;(.*?)&lt;/a&gt;"</span><span>;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;非贪婪模式</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String&nbsp;regex&nbsp;=&nbsp;"&lt;a&gt;(.*)&lt;/a&gt;";&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;贪婪模式</span><span>&nbsp; <br />
    </span></span></li>
</ol>
&nbsp; appendReplacement(StringBuffer&nbsp;sb,&nbsp;String&nbsp;replacement)&nbsp;将当前匹配子串替换为指<br />
定字符串，并且将替换后的子串以及其之前到上次匹配子串之后的字符串段添加到一个<br />
StringBuffer对象里，而appendTail(StringBuffer&nbsp;sb)&nbsp;方法则将最后一次匹配工作后<br />
剩余的字符串添加到一个StringBuffer对象里<br />
<br />
&nbsp; "abc".matches("...");<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; "a8729a".replaceAll("\\d", "-");两个反斜杠代表正则表达式，一个反斜杠代表反义<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;Pattern p = Pattern.compile("[a-z]{3}");a到z的三个字符<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;Matcher m = p.matcher("fgh");<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; boolean b = m.matches());<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; b = "fgha".matches("[a-z]{3}");<br />
<br />
&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; //初步认识. * + ?<br />
.代表一个字符，*代表0个或者多个，+代表一个或者多个，？代表0个或者1个<br />
[0-9]代表代表数字0到9.\\d{1,3}数字出现1到3次<br />
&amp;&amp;代表交集 |代表或者<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; /*<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; p("a".matches("."));<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; p("aa".matches("aa"));<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; p("aaaa".matches("a*"));<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; p("aaaa".matches("a+"));<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; p("".matches("a*"));<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; p("aaaa".matches("a?"));<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; p("".matches("a?"));<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; p("a".matches("a?"));<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; p("214523145234532".matches("\\d{3,100}"));<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; p("192.168.0.aaa".matches("\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}"));<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; p("192".matches("[0-2][0-9][0-9]"));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; //范围<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; /*<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; p("a".matches("[abc]"));[abc]代表从abc之中任意一个<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; p("a".matches("[^abc]"));[^abc]abc之外的字符<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; p("A".matches("[a-zA-Z]"));a到z或者A到Z<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; p("A".matches("[a-z]|[A-Z]"));同上<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; p("A".matches("[a-z[A-Z]]"));同上<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; p("R".matches("[A-Z&amp;&amp;[RFG]]"));A到Z并且是RFG中的任意字符<br />
\t 间隔 ('\u0009')<br />
\n 换行 ('\u000A')<br />
\r 回车 ('\u000D')<br />
\d 数字 等价于[0-9]<br />
\D 非数字 等价于[^0-9]<br />
\s 空白符号 [\t\n\x0B\f\r]<br />
\S 非空白符号 [^\t\n\x0B\f\r]<br />
\w 单独字符 [a-zA-Z_0-9]<br />
\W 非单独字符 [^a-zA-Z_0-9]<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; p(" \n\r\t".matches("\\s{4}"));<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; p(" ".matches("\\S"));<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; p("a_8".matches("\\w{3}"));<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; p("abc888&amp;^%".matches("[a-z]{1,3}\\d+[&amp;^#%]+"));<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; p("\\".matches("\\\\"));<br />
<br />
&nbsp;\\b单词边界<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $为限制结尾<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ^放在[]外面的意思代表开头<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; p("hello sir".matches("^h.*"));<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; p("hello sir".matches(".*ir$"));<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; p("hello sir".matches("^h[a-z]{1,3}o\\b.*"));<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; p("hellosir".matches("^h[a-z]{1,3}o\\b.*"));<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; //whilte lines<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; p(" \n".matches("^[\\s&amp;&amp;[^\\n]]*\\n$"));<br />
<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; //email<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; //p("asdfasdfsafsf@dsdfsdf.com".matches("[\\w[.-]]+@[\\w[.-]]+\\.[\\w]+"));<br />
<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; //matches find lookingAt<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; /match匹配整串，find寻找子串，lookingAt从头找<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; Pattern p = Pattern.compile("\\d{3,5}");<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; String s = "123-34345-234-00";<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; Matcher m = p.matcher(s);<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; p(m.matches());<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; m.reset();<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; p(m.find());<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; p(m.start() + "-" + m.end());<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; p(m.find());<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; p(m.start() + "-" + m.end());<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; p(m.find());<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; p(m.start() + "-" + m.end());<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; p(m.find());<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; //p(m.start() + "-" + m.end());<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; p(m.lookingAt());<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; p(m.lookingAt());<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; p(m.lookingAt());<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; p(m.lookingAt());<br />
<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; //replacement<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; /*<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; Pattern p = Pattern.compile("java", Pattern.CASE_INSENSITIVE);<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; Matcher m = p.matcher("java Java JAVa JaVa IloveJAVA you hateJava afasdfasdf");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //String str&nbsp; = m.replaceAll("JAVA");<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; StringBuffer buf = new StringBuffer();<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; int i=0;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; while(m.find()) {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; i++;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if(i%2 == 0) {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; m.appendReplacement(buf, "java");<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; } else {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; m.appendReplacement(buf, "JAVA");<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; m.appendTail(buf);<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; p(buf);<br />
<br />
<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; //group<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 有几个()就有几组<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; Pattern p = Pattern.compile("(\\d{3,5})([a-z]{2})");<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; String s = "123aa-34345bb-234cc-00";<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; Matcher m = p.matcher(s);<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; while(m.find()) {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; p(m.group(1));<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
<br />
<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; //qulifiers<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; +<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; Pattern p = Pattern.compile(".{3,10}+[0-9]");<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; String s = "aaaa5bbbb68";<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; Matcher m = p.matcher(s);<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if(m.find())<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; p(m.start() + "-" + m.end());<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; else <br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; p("not match!");<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; */<br />
<img src ="http://www.blogjava.net/zhaozhenlin1224/aggbug/342630.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zhaozhenlin1224/" target="_blank">java/j2ee</a> 2011-01-09 18:40 <a href="http://www.blogjava.net/zhaozhenlin1224/archive/2011/01/09/342630.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java中如何正确使用字体编码</title><link>http://www.blogjava.net/zhaozhenlin1224/archive/2010/09/26/332919.html</link><dc:creator>java/j2ee</dc:creator><author>java/j2ee</author><pubDate>Sun, 26 Sep 2010 03:07:00 GMT</pubDate><guid>http://www.blogjava.net/zhaozhenlin1224/archive/2010/09/26/332919.html</guid><wfw:comment>http://www.blogjava.net/zhaozhenlin1224/comments/332919.html</wfw:comment><comments>http://www.blogjava.net/zhaozhenlin1224/archive/2010/09/26/332919.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/zhaozhenlin1224/comments/commentRss/332919.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zhaozhenlin1224/services/trackbacks/332919.html</trackback:ping><description><![CDATA[在Java编程中，中文字体编码难倒了不少程序员，如果抓住了影响Java中文显示的几个关键因素，问题将迎刃而解。 <br />
<br />
Java是目前最流行的面向对象的编程语言之一，Java支持UTF-8、ISO-8 <br />
859-1、GBK等各种字体编码，可笔者发现Java中字体编码的问题仍难倒了不少程序员，网上虽然也有不少关于在Java中如何正确显示中文的文章，但都不够全面，笔者特意总结如下。 <br />
<br />
影响Java中字体编码正确显示的有几个因素: 1)数据库的连接方式; 2)网页中使用的字体编码; 3)数据库里存放数据的字体编码; 4)Java的缺省字体编码。如果在编程中遇到不能正确显示中文时，要先弄清楚以上几项所使用的字体编码，再分析找出原因，即可解决问题。 <br />
<br />
众所周知，JSP是Java的一种，和网页有关，而网页也有自己的中文编码系统，所以JSP处理中文要比纯Java的类文件更为麻烦。本文的测试数据库是MySQL3.2，数据库连接驱动是用org.gjt.mm.mysql.Driver，这里主要讨论UTF-8和GBK的显示( GB2312是GBK的一个子集，Java中可以使用GBK来代替GB系列)。我们先来研究JSP中字体编码问题， 下面第一到第六点是针对JSP的(因为从数据库里读出中文数据与写入中文数据有所区别，咱们分别说明，前三点是从读取数据库到显示在网页，后三点是从网页输入数据到存入数据库)，第七到第九点针对纯Java的类文件。 以下rs表示ResultSet的一个实例，是执行Select语句之后产生的数据集。 <br />
<br />
一、数据库连接方式使用UTF-8 <br />
<br />
在连接数据库的驱动后面加上这句参数useUnicode=true&amp;characterEncoding= <br />
<br />
UTF-8，例如jdbc:mysql://localhost/DBVF?autoReconnect=true&amp;useUnicode= <br />
<br />
true&amp;characterEncoding=UTF-8，从数据库里读出中文显示在使用GBK的JSP的网页里，如果数据库里存放的字体编码是UTF-8，在JSP中使用 str=new String(rs.getBytes(1),"UTF-8")或者str=rs.getString(1)，可以正确显示中文。如果数据库里存放的是GBK数据，那么JSP中也要使用str=new String(rs.getBytes(1),"GBK")来显示正确的中文。值得注意的是如果页面使用UTF-8，数据库里存放的是UTF-8，也可以用str=new String(rs.getBytes(1),"GBK")正确显示中文。如果网页是UTF-8，而数据库里存放的是GBK，无法直接显示中文，需要2步转换, str=new String(rs.getBytes(1),"GBK"); 再str=new String(str.getBytes("UTF-8"),"GBK")，才可以正确显示中文。 <br />
<br />
二、数据库连接方式使用GBK <br />
<br />
在连接数据库的驱动后面加上这句参数useUnicode=true&amp;characterEncoding= <br />
<br />
GBK,例如jdbc:mysql://localhost/DBVF?autoReconnect=true&amp;UseUnicode=true&amp; <br />
<br />
characterEncoding=GBK，从数据库里读出中文，显示在使用GBK的JSP的网页里，如果数据库里存放的字体编码是UTF-8，在JSP中一定要使用 str=new String(rs.getBytes(1),"UTF-8")，才正确显示中文。如果数据库里存放的是GBK数据，那么JSP中也要使用str=new String(rs.getBytes(1),"GBK") 或者直接使用str=rs.getString(1)，即可显示正确的中文。 如果网页是UTF-8，而数据库里存放的是GBK，只能用str=new String(rs.getString(1).getBytes("UTF-8"),"GBK")的方法来显示中文; 如果网页是UTF-8，而数据库里存放的是UTF-8，可用str=new String(rs.getBytes(1),"GBK") 或者rs.getString(1)方法来显示中文。 <br />
<br />
三、使用缺省数据库连接方式 <br />
<br />
连接数据库的驱动后面没有这句参数useUnicode=&amp;characterEncoding=，例如jdbc:mysql://localhost/DBVF?autoReconnect=true，没有参数useUnicode=true&amp;characterEncoding，表示使用默认的ISO-8895-1编码。 <br />
<br />
1. 从数据库里读出中文，显示在GBK的网页里。如果数据库里存放的字体编码是UTF-8，在JSP网页中一定要使用语句 str=new String(rs.getBytes(1),"UTF-8") 或者str= new String(rs.getString(1).getBytes("ISO-8859-1"),"UTF-8")，才可正确显示中文。如果数据库里存放的是GBK数据，那么JSP中也要使用str=new String(rs.getBytes(1),"GBK")或str=new String(rs.getString(1).getBytes("ISO-8859-1"),"GBK") 显示正确的中文。 <br />
<br />
2. 如果网页是UTF-8,不能直接正确显示GBK，需要2步转换，str=new String(rs.getBytes(1),"GBK")，再str=new String(str.getBytes("UTF-8"),"GBK") 才可以正确显示中文。如果数据库里存的是UTF-8，直接用str=new String(rs.getBytes(1),"GBK")或者str=new String(rs.getString(1).getBytes("ISO-8859-1"),"GBK")就可以显示中文了。 <br />
<br />
以上是读取数据库里中文正确显示在网页上，下面三点是如何正确存入数据库。 <br />
<br />
四、数据库连接方式使用UTF-8编码 <br />
<br />
JSP中要把网页输入的中文存入数据库，通常有一个提交(Submit)的过程，是用str=request.getParameter("username")，然后执行update或者insert语句来存入数据库。如何赋值给str很重要，而且这里中文输入与网页所使用的字体编码有关。 <br />
<br />
1、 网页使用UTF-8，使用str= new String(request.getParameter("username").getBytes("ISO-8859-1"),"UTF-8")或者str= new String(request.getParameter("username").getBytes(),"UTF-8")，都可以使得存到数据库里的数据是UTF-8编码。 <br />
<br />
2. 网页使用GBK，使用str= new String(request.getParameter("username").getBytes(),"GBK")，那么存入数据库的是UTF-8编码。 <br />
<br />
3. 值得注意的是使用UTF-8的数据库连接方式不能存得GBK。 <br />
<br />
五、数据库连接方式使用GBK编码 <br />
<br />
1. 输入使用GBK网页，存到数据库里是GBK的方法: str= new String(request.getParameter("username").getBytes("ISO-8859-1"),"GBK") 或者str= new String(request.getParameter("username").getBytes(),"GBK")。 <br />
<br />
2. 网页使用GBK，想存入UTF-8到数据库里，要分2步: 先str=new String(request.getParameter("username").getBytes(),"GBK")，再str=new String(str.getBytes("UTF-8"),"GBK")即可。 <br />
<br />
3. 网页使用UTF-8，而且使用str= new String(request.getParameter("username").getBytes("ISO-8859-1"),"GBK") 或者str= new String(request.getParameter("username").getBytes(),"UTF-8")，那么存到数据库里的数据是UTF-8编码。 <br />
<br />
4. 网页使用UTF-8，而且使用str= new String(request.getParameter("username").getBytes("ISO-8859-1"),"UTF-8")，那么存到数据库里的数据是GBK编码。 <br />
<br />
六、数据库连接方式使用缺省，即不使用参数useUnicode和characterEncoding <br />
<br />
1. 网页使用GBK，如果使用str= request.getParameter("username")或者str= new String(request.getParameter("username").getBytes())，那么在数据库里的数据是GBK码。网页使用UTF-8 和使用str= request.getParameter("username")，则存入数据库是UTF-8编码。 <br />
<br />
2. 如果使用str= new String(request.getParameter("username").getBytes("ISO-8859-1"))，那么根据网页提供的字体编码而存到数据库里，比如是UTF-8的网页，那么存到数据库中就是UTF-8编码，如果使用GBK网页，那么存到数据库里的字就是GBK编码。 <br />
<br />
3. 如果使用str= new String(request.getParameter("username").getBytes("UTF-8"),"UTF-8")这一种组合能存到正确的数据外，其他存到数据库里的数据则都是乱码或者错误码。在这个UTF-8组合的特例中，网页使用的是GBK，则存放到数据库里就是GBK，网页使用UTF-8，那么存到数据库里的就是UTF-8。 <br />
<br />
4. 网页是GBK的要存得UTF-8，一定需要2步: company=new String(request.getParameter("company").getBytes(),"GBK")和company=new String(company.getBytes("UTF-8"))。 <br />
<br />
5. 网页是UTF-8的，不能存得GBK在数据库里，一句话，改变数据库连接方式不能存得GBK码。 <br />
<br />
以上所有的都是基于JSP网页和数据库交换数据，下面讨论一下纯JAVA编程下的字体编码转换。 <br />
<br />
七、数据库连接方式使用UTF-8编码 <br />
<br />
1. 数据库里的中文是UTF-8，可以转换为GBK,但不能把GBK存入数据库。 <br />
<br />
2. 数据库是GBK，如果转换为UTF-8，使用content=new String(rs.getBytes(2),"GBK")直接将content存入数据库就可为UTF-8。 <br />
<br />
八、数据库连接方式使用GBK编码 <br />
<br />
1. 数据库里的中文是UTF-8，如果转换为GBK，使用content= new String(rs.getString(2).getBytes(),"UTF-8"),再直接使用update或者insert语句插入到数据库，即存得GBK。如果使用content= new String(rs.getString(2).getBytes(),"GBK")或者content= new String(rs.getString(2).getBytes())，再存入数据库即存得还是UTF-8编码。 <br />
<br />
2. 数据库里的中文是GBK，如果转换为UTF-8，使用content= new String(rs.getString(2).getBytes("UTF-8"))或者content= new String(rs.getString(2).getBytes("UTF-8"),"GBK")，再直接使用update或者insert语句插入到数据库,即存得UTF-8。 <br />
<br />
3. 如果某个String是GBK，要转换为UTF-8，也是使用content= new String(GBKstr.getBytes("UTF-8"))或者content= new String(GBKstr.getBytes("UTF-8"),"GBK"); 如果某个String是UTF-8，要转换为GBK，应该使用new String(UTFstr.getBytes("GBK"),"UTF-8")。 <br />
<br />
九、数据库连接方式使用缺省,即不跟参数 <br />
<br />
1. str2=new String(GBKstr.getBytes("UTF-8"),"ISO-8859-1")，可以将数据库里的GBK编码转换为UTF-8。 <br />
<br />
2. 读取UTF-8然后存入UTF-8，则用str1=new String(UTFstr.getBytes(),"ISO-8859-1")或者str1=new String(UTFstr.getBytes("GBK"),"ISO-8859-1")。 <br />
<br />
3. 不能实现数据库里的UTF-8转换为GBK。 <br />
<br />
如果采用UTF-8的数据库连接方式或者缺省数据连接方式，那么无法将UTF-8转为GBK；而GBK的数据库连接方式可以实现UTF-8和GBK的相互转换。建议大家采用GBK的数据连接方式。 <br />
<img src ="http://www.blogjava.net/zhaozhenlin1224/aggbug/332919.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zhaozhenlin1224/" target="_blank">java/j2ee</a> 2010-09-26 11:07 <a href="http://www.blogjava.net/zhaozhenlin1224/archive/2010/09/26/332919.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Comparable和Comparator</title><link>http://www.blogjava.net/zhaozhenlin1224/archive/2010/02/21/313510.html</link><dc:creator>java/j2ee</dc:creator><author>java/j2ee</author><pubDate>Sun, 21 Feb 2010 04:04:00 GMT</pubDate><guid>http://www.blogjava.net/zhaozhenlin1224/archive/2010/02/21/313510.html</guid><wfw:comment>http://www.blogjava.net/zhaozhenlin1224/comments/313510.html</wfw:comment><comments>http://www.blogjava.net/zhaozhenlin1224/archive/2010/02/21/313510.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/zhaozhenlin1224/comments/commentRss/313510.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zhaozhenlin1224/services/trackbacks/313510.html</trackback:ping><description><![CDATA[<div class="blog_content">Comparable &amp; Comparator 都是用来实现集合中的排序的，只是 Comparable 是在集合内部定义的方法实现的排序，Comparator 是在集合外部实现的排序，所以，如想实现排序，就需要在集合外定义 Comparator 接口的方法或在集合内实现 Comparable 接口的方法。 <br />
Comparable 是一个对象本身就已经支持自比较所需要实现的接口（如 String、Integer 自己就可以完成比较大小操作） <br />
<br />
　　而 Comparator 是一个专用的比较器，当这个对象不支持自比较或者自比较函数不能满足你的要求时，你可以写一个比较器来完成两个对象之间大小的比较。 <br />
<br />
　　可以说一个是自已完成比较，一个是外部程序实现比较的差别而已。 <br />
<br />
　　用 Comparator 是策略模式（strategy design pattern），就是不改变对象自身，而用一个策略对象（strategy object）来改变它的行为。 <br />
<br />
如果对java比较熟悉的会知道java.util.Comparator 接口。要实现里面的函数 <br />
int compare(Object o1, Object o2) 返回一个基本类型的整型，返回负数表示o1 小于o2，返回0 表示o1和o2相等，返回正数表示o1大于o2。 <br />
<br />
1.下面是一个简单的例子，Person类有name和age连个属性，排序规则是先按姓名排，如果姓名一样则按年龄排： <br />
<br />
Person类： <br />
<br />
public class Person { <br />
<br />
&nbsp;&nbsp;&nbsp; private String name; <br />
&nbsp;&nbsp;&nbsp; private Integer age; <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; public Person(String name, Integer age) <br />
&nbsp;&nbsp;&nbsp; { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.name = name; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.age = age; <br />
&nbsp;&nbsp;&nbsp; } <br />
<br />
&nbsp;&nbsp;&nbsp; public String getName() { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return name; <br />
&nbsp;&nbsp;&nbsp; } <br />
<br />
&nbsp;&nbsp;&nbsp; public Integer getAge() { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return age; <br />
&nbsp;&nbsp;&nbsp; } <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; public String toString() <br />
&nbsp;&nbsp;&nbsp; { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return name + " " + age; <br />
&nbsp;&nbsp;&nbsp; } <br />
} <br />
<br />
PersonComparator类（里面有测试的代码） <br />
<br />
public class PersonComparator implements Comparator&lt;Person&gt; { <br />
<br />
&nbsp;&nbsp;&nbsp; public int compare(Person arg0, Person arg1) { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String name1 = arg0.getName(); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String name2 = arg1.getName(); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Integer age1 = arg0.getAge(); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Integer age2 = arg1.getAge(); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return (name1.compareTo(name2) == 0) ? (age1.compareTo(age2)) : name1.compareTo(name2); <br />
&nbsp;&nbsp;&nbsp; } <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; public static void main(String[] args) { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; List&lt;Person&gt; persons = new ArrayList&lt;Person&gt;(); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; persons.add(new Person("name1", new Integer(23))); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; persons.add(new Person("name1", new Integer(13))); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; persons.add(new Person("name2", new Integer(23))); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; persons.add(new Person("name", new Integer(13))); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Collections.sort(persons, new PersonComparator()); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(int i = 0; i &lt; persons.size(); i++) { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(persons.get(i).toString()); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; } <br />
<br />
} <br />
<br />
2.Comparable例子 <br />
<br />
public class ComparableTest implements Comparable { <br />
<br />
&nbsp;&nbsp;&nbsp; private String str; <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; public String getStr() { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return str; <br />
&nbsp;&nbsp;&nbsp; } <br />
<br />
&nbsp;&nbsp;&nbsp; public void setStr(String str) { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.str = str; <br />
&nbsp;&nbsp;&nbsp; } <br />
<br />
&nbsp;&nbsp;&nbsp; public int compareTo(Object arg0) { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ComparableTest t = (ComparableTest)arg0; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return str.compareTo(t.getStr()); <br />
&nbsp;&nbsp;&nbsp; } <br />
<br />
&nbsp;&nbsp;&nbsp; public static void main(String[] args) { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String[] strs = {"a", "f","s","d","e","t","i","l","y","z"}; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; List cts = new ArrayList(strs.length); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(int i = 0; i &lt; strs.length; i++) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ComparableTest t = new ComparableTest(); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; t.setStr(strs[i]); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cts.add(t); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Collections.sort(cts); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(int i = 0; i &lt; cts.size(); i++) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ComparableTest t = (ComparableTest)cts.get(i); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(t.getStr()); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <br />
<br />
&nbsp;&nbsp;&nbsp; } <br />
} <br />
</div>
<img src ="http://www.blogjava.net/zhaozhenlin1224/aggbug/313510.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zhaozhenlin1224/" target="_blank">java/j2ee</a> 2010-02-21 12:04 <a href="http://www.blogjava.net/zhaozhenlin1224/archive/2010/02/21/313510.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java学习笔记一</title><link>http://www.blogjava.net/zhaozhenlin1224/archive/2010/02/10/312505.html</link><dc:creator>java/j2ee</dc:creator><author>java/j2ee</author><pubDate>Wed, 10 Feb 2010 06:09:00 GMT</pubDate><guid>http://www.blogjava.net/zhaozhenlin1224/archive/2010/02/10/312505.html</guid><wfw:comment>http://www.blogjava.net/zhaozhenlin1224/comments/312505.html</wfw:comment><comments>http://www.blogjava.net/zhaozhenlin1224/archive/2010/02/10/312505.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/zhaozhenlin1224/comments/commentRss/312505.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zhaozhenlin1224/services/trackbacks/312505.html</trackback:ping><description><![CDATA[1.序列化。需要序列化的对象需要实现Serializable接口.<br />
&nbsp;
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: small;"><span style="font-family: 宋体;">FileOutputStream fos = new FileOutputStream(args[0]);</span></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: small;"><span style="font-family: 宋体;">ObjectOutputStream oos = new ObjectOutputStream(fos);</span></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: small;"><span style="font-family: 宋体;">Person p = new Person("gaoyanbing", "haiger");<br />
<span style="font-size: small;"><span style="font-family: 宋体;"><span lang="EN-US">oos.writeObject(p);</span></span></span></span></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: small;"><span style="font-family: 宋体;">FileInputStream fis = new FileInputStream(args[0]);</span></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: small;"><span style="font-family: 宋体;">ObjectInputStream ois = new ObjectInputStream(fis);</span></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: small;"><span style="font-family: 宋体;">Object o = ois.readObject();<br />
2.克隆。分为深度克隆和浅克隆。java object自身的克隆是浅克隆。<br />
3.List转换成数组<br />
<font style="background-color: #c0c0c0;">List&lt;PrizeStatistic&gt; pList = cwlGameDAO.getLatestPrizeStatistic(gameId);<br />
&nbsp;&nbsp;prizeStatistic = pList.toArray(new PrizeStatistic[pList.size()]);<br />
<br />
4.<font style="background-color: #c0c0c0;">math.floor(i) 小于等于i的最大整数<br />
&nbsp; math.ceil(i) 大于等于i的最小整数&nbsp;&nbsp;&nbsp;<br />
&nbsp; Math.round(x)：四舍五入。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp; Math.round(x)返回long型，其余的返回double型。<br />
<font style="background-color: #c0c0c0;">&nbsp;int pageCount = (int) Math.ceil((double)historyAmount/pageSize)<br />
<br />
</font></font>5.double,float 等浮点数是不准确的，想使用准确的，可以用BigDecimal 或者直接用 int/long 这类整数.<br />
&nbsp; DecimalFormat format <span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000ff;">new</span><span style="color: #000000;"> DecimalFormat(</span><span style="color: #000000;">"</span><span style="color: #000000;">0.0</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: #0000ff;">double</span><span style="color: #000000;"> a </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #000000;">1.9</span><span style="color: #000000;">;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: #0000ff;">double</span><span style="color: #000000;"> b </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #000000;">0.3</span><span style="color: #000000;">;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: #0000ff;">double</span><span style="color: #000000;"> d </span><span style="color: #000000;">=</span><span style="color: #000000;"> Double.valueOf(format.format(a </span><span style="color: #000000;">+</span><span style="color: #000000;"> b));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(a</span><span style="color: #000000;">+</span><span style="color: #000000;">"</span><span style="color: #000000;">+</span><span style="color: #000000;">"</span><span style="color: #000000;">+</span><span style="color: #000000;">b</span><span style="color: #000000;">+</span><span style="color: #000000;">"</span><span style="color: #000000;">=</span><span style="color: #000000;">"</span><span style="color: #000000;">+</span><span style="color: #000000;">d);</span><span style="color: #008000;">//</span><span style="color: #008000;">这样就是2.2了</span><span style="color: #008000;"><br />
</span></font></span></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: small;"><span style="font-family: 宋体;"><font style="background-color: #c0c0c0;">6&nbsp;&nbsp;&nbsp;取a和b之间的随即数 int m=(int)Math.rint(Math.random()*(b-a)+a);</font></span></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="color: red;">7</span><br />
</p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">作用域&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 当前类 &nbsp; &nbsp; &nbsp; &nbsp;    同一package&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   子孙类&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;     其他package <br />
</p>
<pre id="recommend-answer-content">public          &#8730;                    &#8730;              &#8730;                  &#8730; <br />protected       &#8730;                   &#8730;               &#8730;&#215;                &#215; <br />friendly        &#8730;                   &#8730;               &#215;                  &#215; <br />private         &#8730;                   &#215;               &#215;                  &#215;<br />protected:不同包的子类就规规矩矩的在自己的代码里用父类的属性就行了（继承了父类的属性）。其它的使用都是不允许的（例如实例化父类，然后调用protected属性或者方法）。<br />protected只有本包和子类可以访问。freindly只有本包可以访问。当然当前类都可以访问。<br /><span style="color: red;">8 java数据类型转换</span><br />在混合运算中，容器小的类型自动提升为为容器大的类型，数据类型容器大小顺序如下:<br /><div><pre id="recommend-answer-content"><pre id="recommend-answer-content">byte short char-&gt;int-&gt;long-&gt;float-&gt;double<br />byte short char之前不会相互转换，他们运算时先提升为int<br /></pre></pre></div>容器大的转换为容器小的需要加上强制转换符，可能造成数据溢出或者精度降低<br />在存在多种数据类型计算时，先把数据类型转换为容量最大的类型进行计算。<br />实数常量如（1.2）默认为double,整数常量(123)默认为int<br />byte1个字节，8位(-2/7----2/7-1)。 short 2个字节，16位(-2/16----2/16-1)。 int 4个字节，32位(-2/32----2/32-1)。char 8位 无符号<br />double双精度,8个字节。flot单精度4个字节。float没有double的精确度高。如果对精确度要求特别高，可以使用BigDecimal.<br />整数除0，抛异常。浮点数除0，得到无穷大，得到正无穷大positive_infinity或者福无穷大negative_infinity。NAN意思是not a number,NAN有可能不等于NAN.<br />赋值变量类型转换的规则<br /><div><pre id="recommend-answer-content"><pre id="recommend-answer-content"><pre id="recommend-answer-content">byte short char-&gt;int-&gt;long-&gt;float-&gt;double</pre></pre></pre></div><div><pre id="recommend-answer-content"><div><pre id="recommend-answer-content">byte-&gt;short-&gt;int    char-&gt;int</pre></div></pre></div><span style="color: red;">9 java集合 </span><br />iterator.remove()删除左边的元素 collection接口的子类都有默认的构造函数（例如 ArrayList l = new ArrayList(l1)）;<br />Collection 有retainAll、addAll、toArray方法<br /><span style="color: red;">10 io</span><br />InputStream OutputStream 字节流，Reader Writer字符流<br />常见子类FileInputStream FileOutputStream FileReader FileWriter<br />每一个抽象流都有一个缓冲流 BufferedInputStream BufferedOutputStream BufferedReader BufferedWriter<br />BufferedReader有readLine读取一行字符，BufferedWriter有newLine（）创建新的一行.readLine是同步的阻塞的。<br />转换流 OutputStreamWriter 将流转换为writer，可以写字符。InputStreamReader可以将流转换为Reader，可以读取字符。外面还可以套Buffered<br />DataOutputStream DataInputStream属于处理流，可以修饰所有的OutputStream和InputStream子类（包括Buffer流），用于读写java的原始数据类型数据.DataOutputStream写的都是二进制文件，需要用DataInputStream打开。<br />打印流 PrintWriter PrintStream分别对用于字符和字节,可以套接FileOutput流。不会抛异常，具有自动flush功能。<br />一般套接情况，file流外套buffer流，将支持buffer功能，然后套格式化流（比如DataOutputSream和PrinterWirter等），就支持了格式化输入输出。<br />对象流 <br /><span style="color: red;">
1</span><span style="color: red;">1 父类子类的构造函数</span><br />
如果父类没有声明无参构造函数，那么子类也不能使用无参构造函数，只能使用跟父类一样参数的构造函数。<br />
如果父类声明了无参构造函数，那么子类也可以使用无参构造函数还可以使用其他参数类型的构造函数（有人叫它重载构造函数）<br />
<span style="color: red;">12 内部类。</span><br />  内部类分为静态内部类和非静态内部类。<br /> 非静态内部类,不能有静态方法/属性/静态块,不能访问外部类的静态方法和属性。private修饰的内部类只能在外部类内使用。<br /> 非静态内部类维护着对外部类的对象的引用。可以访问外部类的private属性。属性如果同名，类名.this.属性名这种方式访问。<br /> 外部类不能访问内部类的成员属性和方法，只能通过创建对象来访问。<br />------------------------------------------------------------------------------------------------------------------------------------------<br /> 静态内部类，只能访问外部类的静态属性和静态方法。因为静态内部类维护的是外部类的类引用而不是对象引用。<br /> 外部类不能访问静态内部类的成员，但可以通过内部类的类名做为调用者来调用静态属性。<br /> 也可以构建子类的对象来访问子类的方法。<br /><span style="color: red;">13 线程和多线程</span> <br />  sleep suspend resume join属于Thread的方法，wait notify notifyall属于object的方法。wait notify notifyall必须放在同步方法或者同步块里，否则报异常。<br />  一般情况下会使用notifyall而不是notify.sleep睡眠一段时间后会执行,sleep被阻塞了但是不放弃锁。wait会放弃锁。<div><span style="font-family: 宋体;">  用suspend</span>()<span style="font-family: 宋体;">暂停了线程的执行。除非线程收到</span>resume()<span style="font-family: 宋体;">消息，否则不会返回可运行状态；</span></div><div>  阻塞指的是暂停一个线程的执行以等待某个条件发生（如某资源就绪），学过操作系统的同学对它一定已经很熟悉了。Java 提供了大量方法来支持阻塞，下面让我们逐一分析。 <br /><br />&nbsp;&nbsp;&nbsp;  1. sleep() 方法：sleep() 允许 <br />指定以毫秒为单位的一段时间作为参数，它使得线程在指定的时间内进入阻塞状态，不能得到CPU 时间，指定的时间一过，线程重新进入可执行状态。<br />典型地，sleep() 被用在等待某个资源就绪的情形：测试发现条件不满足后，让线程阻塞一段时间后重新测试，直到条件满足为止。 <br /><br />&nbsp;&nbsp;&nbsp;  2. suspend() 和 resume() <br />方法：两个方法配套使用，suspend()使得线程进入阻塞状态，并且不会自动恢复，必须其对应的resume() 被调用，才能使得线程重新进入可执行状态。<br />典型地，suspend() 和 resume() 被用在等待另一个线程产生的结果的情形：测试发现结果还没有产生后，让线程阻塞，另一个线程产生了结果后，调用 resume() 使其恢复。 <br /><br />    3. yield() 方法：<br />yield() 使得线程放弃当前分得的 CPU 时间，但是不使线程阻塞，即线程仍处于可执行状态，随时可能再次分得 CPU 时间。<br />调用 yield() 的效果等价于调度程序认为该线程已执行了足够的时间从而转到另一个线程。 <br /><br />&nbsp;&nbsp;&nbsp;  4. wait() 和 notify() 方法：两个方法配套使用，wait() 使得线程进入阻塞状态，它有两种形式，一种允许 <br />指定以毫秒为单位的一段时间作为参数，另一种没有参数，前者当对应的 notify() 被调用或者超出指定时间时线程重新进入可执行状态，后者则必须对应的 notify() 被调用。 <br /> 初看起来它们与 suspend() 和 resume() 方法对没有什么分别，但是事实上它们是截然不同的。区别的核心在于，前面叙述的所有方法，阻塞时都不会释放占用的锁（如果占用了的话），而这一对方法则相反。 <br />Thread类的方法基本上都不会放弃锁，object同步方法会放弃锁.</div>    volatile变量只能保证可预见性，加锁可以保证原子性和可见性。volatile是若同步，不会加锁，可以读取到变量的最新值。   在当前的Java内存模型下，线程可以把变量保存在本地内存（比如机器的寄存器）中，而不是直接在主存中进行读写。这就可能造成一个线程在主存中修改了一<br /><div>个变量的值，而另外一个线程还继续使用它在寄存器中的变量值的拷贝，造成数据的不一致。要解决这个问题，只需要像在本程序中的这样，把该变量声明为<br />volatile（不稳定的）即可，这就指示JVM，这个变量是不稳定的，每次使用它都到主存中进行读取。一般说来，多任务环境下各任务间共享的标志都应<br />该加volatile修饰。Volatile修饰的成员变量在每次被线程访问时，都强迫从共享内存中重读该成员变量的值。而且，当成员变量发生变化时，强迫线程将变化值回写到共享内存。这样在任何时刻，两个不同的线程总是看到某个成员变量的同一个值。</div> <br /> ReenTrantLock显示锁可以替代synchronized，提供了更高级的应用。ReentTranloack典型用法如下：<br />  <div><p>ReentrantLock lock = new ReentrantLock(); // not a fair lock</p><p>lock.lock();<br />try {<br />&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> //<br />synchronized do something<br />} finally {<br /><wbr><wbr><wbr><br />lock.unlock();<br />}</p><p>ReentTranLock提供了更高级的用法trylock方法.</p><p><div>if (fromAcct.lock.tryLock()) {do somthing} //lock是formAcct类的一个属性。<br />定时方法如下：<br /><div>import static java.util.concurrent.TimeUnit.NANOSECONDS;</div><div>    private Lock lock = new ReentrantLock();<br />    public boolean trySendOnSharedLine(String message,long timeout, TimeUnit unit)throws InterruptedException {<br />        long nanosToLock = unit.toNanos(timeout)- estimatedNanosToSend(message);<br />        if (!lock.tryLock(nanosToLock, NANOSECONDS))<br />            return false;<br />        try {<br />            return sendOnSharedLine(message);<br />        } finally {<br />            lock.unlock();<br />        }<br />    }</div></div><br /></p></div><br />
  </pre>
<font style="background-color: #c0c0c0;"></font><img src ="http://www.blogjava.net/zhaozhenlin1224/aggbug/312505.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zhaozhenlin1224/" target="_blank">java/j2ee</a> 2010-02-10 14:09 <a href="http://www.blogjava.net/zhaozhenlin1224/archive/2010/02/10/312505.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>junit 简明实用</title><link>http://www.blogjava.net/zhaozhenlin1224/archive/2010/01/30/311304.html</link><dc:creator>java/j2ee</dc:creator><author>java/j2ee</author><pubDate>Sat, 30 Jan 2010 01:51:00 GMT</pubDate><guid>http://www.blogjava.net/zhaozhenlin1224/archive/2010/01/30/311304.html</guid><wfw:comment>http://www.blogjava.net/zhaozhenlin1224/comments/311304.html</wfw:comment><comments>http://www.blogjava.net/zhaozhenlin1224/archive/2010/01/30/311304.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/zhaozhenlin1224/comments/commentRss/311304.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zhaozhenlin1224/services/trackbacks/311304.html</trackback:ping><description><![CDATA[<div>用XP进行开发的过程，unit test是必不可少的环节。作为unit test，junit是首选的工具。本文从使用目的、如何使用、以及使用中需要考虑的问题，简略描述了junit的基本用法。<br />
<br />
使用目的<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;junit是java中书写unit test的framework，目前一些流行的unit test工具大都都是在junit上扩展而来的。目前它的版本是junit3.8.1，可以从www.junit.org上下载。<br />
<br />
用法<br />
1. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;基本使用步骤，Junit的使用非常简单，它的基本使用步骤：<br />
<br />
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;创建，从junit.framework.TestCase派生unit test需要的test case<br />
<br />
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;书写测试方法，提供类似于如下函数签名的测试方法：<br />
<br />
public void testXXXXX();<br />
<br />
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;编译，书写完test case后，编译所写的test case类<br />
<br />
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;运行，启动junit test runner，来运行这个test case。<br />
<br />
Junit提供了2个基本的test runner：字符界面和图形界面。启动命令分别如下：<br />
<br />
a 图形界面：<br />
<br />
java junit.swingui.TestRunner XXXXX<br />
<br />
b 字符界面：<br />
<br />
java junit.textui.TestRunner XXXXX<br />
<br />
2. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;使用例子：<br />
<br />
import junit.frmework.TestCase;<br />
<br />
public class TestSample extends TestCaset{<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public void testMethod1(){<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assertTrue( true);<br />
<br />
}<br />
<br />
}<br />
<br />
3. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setUp与tearDown，这两个函数是junit framework中提供初始化和反初始化每个测试方法的。setUp在每个测试方法调用前被调用，负责初始化测试方法所需要的测试环境；tearDown在每个测试方法被调用之后被调用，负责撤销测试环境。它们与测试方法的关系可以描述如下：<br />
<br />
<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;测试开始 -&gt; setUp -&gt; testXXXX -&gt; tearDown -&gt;测试结束<br />
<br />
<br />
<br />
<br />
4. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;使用例子：<br />
<br />
import junit.frmework.TestCase;<br />
<br />
public class TestSample extends TestCaset{<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;protected void setUp(){<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//初始化&#8230;&#8230;<br />
<br />
}<br />
<br />
<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public void testMethod1(){<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assertTrue( true);<br />
<br />
}<br />
<br />
<br />
<br />
potected void tearDown(){<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//撤销初始化&#8230;&#8230;<br />
<br />
}<br />
<br />
}<br />
<br />
5. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;区分fail、exception。<br />
<br />
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fail，期望出现的错误。产生原因：assert函数出错（如assertFalse(true)）；fail函数产生（如fail(&#8230;&#8230;)）。<br />
<br />
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exception，不期望出现的错误，属于unit test程序运行时抛出的异常。它和普通代码运行过程中抛出的runtime异常属于一种类型。<br />
<br />
对于assert、fail等函数请参见junit的javadoc。<br />
<br />
6. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;使用例子：<br />
<br />
import junit.frmework.TestCase;<br />
<br />
public class TestSample extends TestCaset{<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;protected void setUp(){<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//初始化&#8230;&#8230;<br />
<br />
}<br />
<br />
<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public void testMethod1(){<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#8230;&#8230;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try{<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;boolean b= &#8230;&#8230;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assertTrue( b);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw new Exception( &#8220;This is a test.&#8221;);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fail( &#8220;Unable point.&#8221;); &nbsp;&nbsp;&nbsp;&nbsp;//不可能到达<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}catch(Exception e){<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fail( &#8220;Yes, I catch u&#8221;); //应该到达点<br />
<br />
}<br />
<br />
&#8230;&#8230;<br />
<br />
}<br />
<br />
<br />
<br />
potected void tearDown(){<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//撤销初始化&#8230;&#8230;<br />
<br />
}<br />
<br />
}<br />
<br />
7. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;组装TestSuite，运行更多的test。在junit中，Test、TestCase和TestSuite三者组成了composiste pattern。通过组装自己的TestSuite，可以完成对添加到这个TestSuite中的所有的TestCase的调用。而且这些定义的TestSuite还可以组装成更大的TestSuite，这样同时也方便了对于不断增加的TestCase的管理和维护。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;它的另一个好处就是，可以从这个TestCase树的任意一个节点（TestSuite或TestCase）开始调用，来完成这个节点以下的所有TestCase的调用。提高了unit test的灵活性。<br />
<br />
8. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;使用例子：<br />
<br />
import junit.framework.Test;<br />
<br />
import junit.framework.TestSuite;<br />
<br />
public class TestAll{<br />
<br />
public class TestAll{<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//定义一个suite，对于junit的作用可以视为类似于java应用程序的main。<br />
<br />
&nbsp;&nbsp;&nbsp;public static Test suite(){<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TestSuite suite = new TestSuite("Running all tests.");<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;suite.addTestSuite( TestCase1.class);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;suite.addTestSuite( TestCase2.class);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return suite;<br />
<br />
&nbsp;&nbsp;&nbsp;}<br />
<br />
}<br />
<br />
运行同运行单独的一个TestCase是一样的，参见step 1 &#8220;运行&#8221;。<br />
<br />
9. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;使用Ant junit task。我们除了使用java来直接运行junit之外，我们还可以使用junit提供的junit task与ant结合来运行。涉及的几个主要的ant task如下：<br />
<br />
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;junit&gt;，定义一个junit task<br />
<br />
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;batchtest&gt;，位于&lt;junit&gt;中，运行多个TestCase<br />
<br />
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;test&gt;，位于&lt;junit&gt;中，运行单个TestCase<br />
<br />
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;formatter&gt;，位于&lt;junit&gt;中，定义一个测试结果输出格式<br />
<br />
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;junitreport&gt;，定义一个junitreport task<br />
<br />
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;report&gt;，位于&lt;junitreport&gt;中，输出一个junit report<br />
<br />
具体的语法请参见相关文档。<br />
<br />
10. &nbsp;&nbsp;使用例子：<br />
<br />
&lt;junit printsummary="yes" haltonfailure="no"&gt;<br />
<br />
&nbsp;&nbsp;&nbsp;&lt;classpath&gt;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;path refid="classpath"/&gt;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;pathelement location="${dist.junit}"/&gt;<br />
<br />
&nbsp;&nbsp;&nbsp;&lt;/classpath&gt;<br />
<br />
&nbsp;&nbsp;&nbsp;<br />
<br />
&nbsp;&nbsp;&nbsp;&lt;formatter type="brief" usefile="false"/&gt;<br />
<br />
&nbsp;&nbsp;&nbsp;&lt;formatter type="xml"/&gt;<br />
<br />
<br />
<br />
&nbsp;&nbsp;&nbsp;&lt;batchtest todir="${doc.junitReport}"&gt;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;fileset dir="${dist.junit}" includes="**/*Test.class" /&gt;<br />
<br />
&nbsp;&nbsp;&nbsp;&lt;/batchtest&gt;<br />
<br />
&lt;/junit&gt;<br />
<br />
<br />
<br />
&lt;junitreport todir="${doc.junitReport}"&gt;<br />
<br />
&nbsp;&nbsp;&nbsp;&lt;fileset dir="${doc.junitReport}"&gt;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;include name="TEST*-*.xml"/&gt;<br />
<br />
&nbsp;&nbsp;&nbsp;&lt;/fileset&gt;<br />
<br />
&nbsp;&nbsp;&nbsp;&lt;report format="frames" styledir="${junit.styleDir}" todir="${doc.junitReport}"/&gt;<br />
<br />
&lt;/junitreport&gt;<br />
<br />
检查表<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;junit的使用并不很难，然而要书写一个好的TestCase却并非易事。一个不好的TestCase往往是既浪费了时间，也起不了实际的作用。相反，一个好的TestCase，不仅可以很好的指出代码中存在的问题，而且也可以作为代码更准确的文档，同时还在持续集成的过程中起非常重要的作用。在此给出书写TestCase时需要注意的几点：<br />
<br />
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;测试的独立性：一次只测试一个对象，方便定位出错的位置。这有2层意思：一个TestCase，只测试一个对象；一个TestMethod，只测试这个对象中的一个方法。<br />
<br />
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;给测试方法一个合适的名字。<br />
<br />
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在assert函数中给出失败的原因，如：assertTrue( &#8220;&#8230; should be true&#8221;, &nbsp;&#8230;&#8230;)，方便查错。在这个例子中，如果无法通过assertTrue，那么给出的消息将被显示。在junit中每个assert函数都有第一个参数是出错时显示消息的函数原型。<br />
<br />
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;测试所有可能引起失败的地方，如：一个类中频繁改动的函数。对于那些仅仅只含有getter/setter的类，如果是由IDE（如Eclipse）产生的，则可不测；如果是人工写，那么最好测试一下。<br />
<br />
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在setUp和tearDown中的代码不应该是与测试方法相关的，而应该是全局相关的。如针对与测试方法A和B，在setUp和tearDown中的代码应该是A和B都需要的代码。<br />
<br />
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;测试代码的组织：相同的包，不同的目录。这样，测试代码可以访问被测试类的protected变量/方法，方便测试代码的编写。放在不同的目录，则方便了测试代码的管理以及代码的打包和发布。一个例子如下：<br />
<br />
src &nbsp;&nbsp;&lt;=源代码根目录<br />
<br />
<img style="vertical-align: middle" height="19" src="mhtml:file://D:\book\java－junit简明使用方法 — Windows Live.mht!http://www.uml.org.cn/j2ee/images/016.gif" width="19" border="0"  alt="" />-com<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;<img style="vertical-align: middle" height="19" src="mhtml:file://D:\book\java－junit简明使用方法 — Windows Live.mht!http://www.uml.org.cn/j2ee/images/016.gif" width="19" border="0"  alt="" />-mod1<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img style="vertical-align: middle" height="19" src="mhtml:file://D:\book\java－junit简明使用方法 — Windows Live.mht!http://www.uml.org.cn/j2ee/images/016.gif" width="19" border="0"  alt="" />-class1<br />
<br />
junit &nbsp;&nbsp;&lt;=测试代码根目录<br />
<br />
<img style="vertical-align: middle" height="19" src="mhtml:file://D:\book\java－junit简明使用方法 — Windows Live.mht!http://www.uml.org.cn/j2ee/images/016.gif" width="19" border="0"  alt="" />-com<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;<img style="vertical-align: middle" height="19" src="mhtml:file://D:\book\java－junit简明使用方法 — Windows Live.mht!http://www.uml.org.cn/j2ee/images/016.gif" width="19" border="0"  alt="" />-mod1<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img style="vertical-align: middle" height="19" src="mhtml:file://D:\book\java－junit简明使用方法 — Windows Live.mht!http://www.uml.org.cn/j2ee/images/016.gif" width="19" border="0"  alt="" />-class1 <br />
</div>
<img src ="http://www.blogjava.net/zhaozhenlin1224/aggbug/311304.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zhaozhenlin1224/" target="_blank">java/j2ee</a> 2010-01-30 09:51 <a href="http://www.blogjava.net/zhaozhenlin1224/archive/2010/01/30/311304.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java 类与类之间的关系</title><link>http://www.blogjava.net/zhaozhenlin1224/archive/2010/01/30/311299.html</link><dc:creator>java/j2ee</dc:creator><author>java/j2ee</author><pubDate>Sat, 30 Jan 2010 01:48:00 GMT</pubDate><guid>http://www.blogjava.net/zhaozhenlin1224/archive/2010/01/30/311299.html</guid><wfw:comment>http://www.blogjava.net/zhaozhenlin1224/comments/311299.html</wfw:comment><comments>http://www.blogjava.net/zhaozhenlin1224/archive/2010/01/30/311299.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/zhaozhenlin1224/comments/commentRss/311299.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zhaozhenlin1224/services/trackbacks/311299.html</trackback:ping><description><![CDATA[<p class="MsoNormal" style="margin: 0cm 0cm 0pt"><span><font size="3">类与类之间存在以下关系：</font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 18pt; text-indent: -18pt"><strong><span lang="EN-US"><span><font size="+0"><font size="3">1、</font><span> </span></font></span></span></strong><strong><font size="3"><span>泛化</span><span lang="EN-US"><font size="+0">(Generalization)&lt;o:p&gt;&lt;/o:p&gt;</font></span></font></strong></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 18pt"><span><font size="3">很简单，就是我们常说的继承。是说子类获得父类的功能的同时，还可以扩展自己的功能。</font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 18pt"><font size="3"><span>如图</span><span lang="EN-US"><font size="+0">:</font></span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 18pt"><font size="3"><span lang="EN-US"><img alt="" src="mhtml:file://D:\book\Java中类与类的关系 - 平平 - JavaEye技术网站.mht!http://p.blog.csdn.net/images/p_blog_csdn_net/fantian830211/265334/o_Generalization.jpg" /></span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 18pt"><font size="3"><span lang="EN-US"><font size="+0">Java</font></span><span>代码中表现为：</span><span lang="EN-US"><font size="+0">extends </font></span><span>和</span><span lang="EN-US"><font size="+0"> implements</font></span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 18pt; text-indent: -18pt"><strong><span lang="EN-US"><span><font size="+0"><font size="3">2、</font><span> </span></font></span></span></strong><strong><font size="3"><span>依赖</span><span lang="EN-US"><font size="+0">(Dependency)&lt;o:p&gt;&lt;/o:p&gt;</font></span></font></strong></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 18pt"><font size="3"><span>两个相对独立的咚咚</span><span lang="EN-US"><font size="+0">(A</font></span><span>和</span><span lang="EN-US"><font size="+0">B)</font></span><span>，当</span><span lang="EN-US"><font size="+0">A</font></span><span>负责构造</span><span lang="EN-US"><font size="+0">B</font></span><span>时，</span><span lang="EN-US"><font size="+0">A</font></span><span>与</span><span lang="EN-US"><font size="+0">B</font></span><span>形成依赖关系，即</span><span lang="EN-US"><font size="+0">A</font></span><span>使用</span><span lang="EN-US"><font size="+0">B</font></span><span>。</span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 18pt"><span><font size="3">如图：</font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 18pt"><span><img alt="" src="mhtml:file://D:\book\Java中类与类的关系 - 平平 - JavaEye技术网站.mht!http://p.blog.csdn.net/images/p_blog_csdn_net/fantian830211/265334/o_Dependency.jpg" /></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 18pt; text-align: center" align="center"><span lang="EN-US">&lt;v:shape id="_x0000_i1026" style="WIDTH: 378pt; HEIGHT: 81.75pt" type="#_x0000_t75"&gt;&lt;v:imagedata o:title="Dependency" src="file:///D:\DOCUME~1\Yaogao\LOCALS~1\Temp\msohtml1\01\clip_image003.wmz"&gt;<font size="3">&lt;/v:imagedata&gt;&lt;/v:shape&gt;</span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 18pt"><font size="3"><span lang="EN-US"><font size="+0">Java</font></span><span>代码中的表现为局部变量，方法的参数，以及对静态方法的调用</span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 18pt; text-indent: -18pt"><strong><span lang="EN-US"><span><font size="+0"><font size="3">3、</font><span> </span></font></span></span></strong><strong><font size="3"><span>关联</span><span lang="EN-US"><font size="+0">(Association)&lt;o:p&gt;&lt;/o:p&gt;</font></span></font></strong></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt"><font size="3"><strong><span lang="EN-US"><span><font size="+0">&nbsp;&nbsp; </font></span></span></strong><span>两个相对独立的咚咚</span><span lang="EN-US"><font size="+0">(A</font></span><span>和</span><span lang="EN-US"><font size="+0">B)</font></span><span>，当</span><span lang="EN-US"><font size="+0">A</font></span><span>对象持有</span><span lang="EN-US"><font size="+0">B</font></span><span>对象的时候，形成<strong>关联</strong>关系。</span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 18pt"><font size="3"><span>关于分为有两种特殊的形式，<strong>聚合（</strong></span><strong><span lang="EN-US"><font size="+0">Aggregation</font></span></strong><strong><span>）</span></strong><span>和<strong>组合（</strong></span><strong><span lang="EN-US"><font size="+0">Composition</font></span></strong><strong><span>）</span></strong><span>，聚合和组合只有概念上的区别，在</span><span lang="EN-US"><font size="+0">Java</font></span><span>中的代码实现上没有区别。</span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 18pt"><span><font size="3">聚合：指的是整体与部分的关系，如图：</font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 18pt"><font size="3"><span><img alt="" src="mhtml:file://D:\book\Java中类与类的关系 - 平平 - JavaEye技术网站.mht!http://p.blog.csdn.net/images/p_blog_csdn_net/fantian830211/265334/o_Aggregation.jpg" /></span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 18pt"><font size="3"><span>组合：表示类之间整体和部分的关系，但是组合关系中部分和整体具有统一的生存期</span><span lang="EN-US"><font size="+0">,</font></span><span>即整体对象不存在，部分对象也将不存在，如图：</span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 18pt"><font size="3"><span lang="EN-US"><font size="+0"><img alt="" src="mhtml:file://D:\book\Java中类与类的关系 - 平平 - JavaEye技术网站.mht!http://p.blog.csdn.net/images/p_blog_csdn_net/fantian830211/265334/o_Composition.jpg" /></font></span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 18pt"><font size="3"><span lang="EN-US"><font size="+0">Java</font></span><span>代码中，表现为成员变量。</span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 18pt; text-indent: -18pt"><strong><span lang="EN-US"><span><font size="+0"><font size="3">4、</font><span> </span></font></span></span></strong><strong><font size="3"><span>总结</span><span lang="EN-US">&lt;o:p&gt;&lt;/o:p&gt;</span></font></strong></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt"><font size="3"><span>在</span><span lang="EN-US"><font size="+0">Java</font></span><span>中，应该尽量优先使用<strong>组合</strong>，而不是<strong>继承</strong>，因为<strong>继承</strong>会使得类关系过于复杂化，破坏了封装性，使用<strong>组合</strong>一样可以获得已有类的功能，而且会使新类更加稳固。</span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt"><font size="3"><span>实际上，从<strong>依赖</strong></span><strong><span lang="EN-US"><font size="+0"> -----</font></span></strong><strong><span>〉聚合</span><span lang="EN-US"><font size="+0">--------</font></span></strong><strong><span>〉组合，</span></strong><span>类与类之间的关系更加紧密，互相之间的影响越来越大，其实我们平常比较少去区分这些关系，而且事实上这东西的定义不太好理解，所以肯定会导致认识上的偏差，所以我们使用这些东西的时候，尽量靠近大家都认同的做法，这样容易让别人理解。</span></font></font></p>
<img src ="http://www.blogjava.net/zhaozhenlin1224/aggbug/311299.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zhaozhenlin1224/" target="_blank">java/j2ee</a> 2010-01-30 09:48 <a href="http://www.blogjava.net/zhaozhenlin1224/archive/2010/01/30/311299.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JAVA反射机制 </title><link>http://www.blogjava.net/zhaozhenlin1224/archive/2010/01/30/311300.html</link><dc:creator>java/j2ee</dc:creator><author>java/j2ee</author><pubDate>Sat, 30 Jan 2010 01:48:00 GMT</pubDate><guid>http://www.blogjava.net/zhaozhenlin1224/archive/2010/01/30/311300.html</guid><wfw:comment>http://www.blogjava.net/zhaozhenlin1224/comments/311300.html</wfw:comment><comments>http://www.blogjava.net/zhaozhenlin1224/archive/2010/01/30/311300.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/zhaozhenlin1224/comments/commentRss/311300.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zhaozhenlin1224/services/trackbacks/311300.html</trackback:ping><description><![CDATA[JAVA反射机制 <br />
<br />
　　JAVA反射机制是在运行状态中，对于任意一个类，都能够知道这个类的所有属性和方法；对于任意一个对象，都能够调用它的任意一个方法；这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。 <br />
<br />
　　Java反射机制主要提供了以下功能： 在运行时判断任意一个对象所属的类；在运行时构造任意一个类的对象；在运行时判断任意一个类所具有的成员变量和方法；在运行时调用任意一个对象的方法；生成动态代理。 <br />
<br />
　　1. 得到某个对象的属性 <br />
<br />
　　1 public Object getProperty(Object owner, String fieldName) throws Exception { <br />
<br />
　　2 Class ownerClass = owner.getClass(); <br />
<br />
　　3 <br />
<br />
　　4 Field field = ownerClass.getField(fieldName); <br />
<br />
　　5 <br />
<br />
　　6 Object property = field.get(owner); <br />
<br />
　　7 <br />
<br />
　　8 return property; <br />
<br />
　　9 } <br />
<br />
　　Class ownerClass = owner.getClass()：得到该对象的Class。 <br />
<br />
　　Field field = ownerClass.getField(fieldName)：通过Class得到类声明的属性。 <br />
<br />
　　Object property = field.get(owner)：通过对象得到该属性的实例，如果这个属性是非公有的，这里会报IllegalAccessException。 <br />
<br />
　　2. 得到某个类的静态属性 <br />
<br />
　　1 public Object getStaticProperty(String className, String fieldName) <br />
<br />
　　2 throws Exception { <br />
<br />
　　3 Class ownerClass = Class.forName(className); <br />
<br />
　　4 <br />
<br />
　　5 Field field = ownerClass.getField(fieldName); <br />
<br />
　　6 <br />
<br />
　　7 Object property = field.get(ownerClass); <br />
<br />
　　8 <br />
<br />
　　9 return property; <br />
<br />
　　10 } <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 />
　　3. 执行某对象的方法 <br />
<br />
　　1 public Object invokeMethod(Object owner, String methodName, Object[] args) throws Exception { <br />
<br />
　　2 <br />
<br />
　　3 Class ownerClass = owner.getClass(); <br />
<br />
　　4 <br />
<br />
　　5 Class[] argsClass = new Class[args.length]; <br />
<br />
　　6 <br />
<br />
　　7 for (int i = 0, j = args.length; i &lt; j; i++) { <br />
<br />
　　8 argsClass[i] = args[i].getClass(); <br />
<br />
　　9 } <br />
<br />
　　10 <br />
<br />
　　11 Method method = ownerClass.getMethod(methodName, argsClass); <br />
<br />
　　12 <br />
<br />
　　13 return method.invoke(owner, args); <br />
<br />
　　14 } <br />
<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 />
　　4. 执行某个类的静态方法 <br />
<br />
　　1 public Object invokeStaticMethod(String className, String methodName, <br />
<br />
　　2 Object[] args) throws Exception { <br />
<br />
　　3 Class ownerClass = Class.forName(className); <br />
<br />
　　4 <br />
<br />
　　5 Class[] argsClass = new Class[args.length]; <br />
<br />
　　6 <br />
<br />
　　7 for (int i = 0, j = args.length; i &lt; j; i++) { <br />
<br />
　　8 argsClass[i] = args[i].getClass(); <br />
<br />
　　9 } <br />
<br />
　　10 <br />
<br />
　　11 Method method = ownerClass.getMethod(methodName, argsClass); <br />
<br />
　　12 <br />
<br />
　　13 return method.invoke(null, args); <br />
<br />
　　14 } <br />
<br />
　　基本的原理和实例3相同，不同点是最后一行，invoke的一个参数是null，因为这是静态方法，不需要借助实例运行。 <br />
<br />
　　5. 新建实例 <br />
<br />
　　1 <br />
<br />
　　2 public Object newInstance(String className, Object[] args) throws Exception { <br />
<br />
　　3 Class newoneClass = Class.forName(className); <br />
<br />
　　4 <br />
<br />
　　5 Class[] argsClass = new Class[args.length]; <br />
<br />
　　6 <br />
<br />
　　7 for (int i = 0, j = args.length; i &lt; j; i++) { <br />
<br />
　　8 argsClass[i] = args[i].getClass(); <br />
<br />
　　9 } <br />
<br />
　　10 <br />
<br />
　　11 Constructor cons = newoneClass.getConstructor(argsClass); <br />
<br />
　　12 <br />
<br />
　　13 return cons.newInstance(args); <br />
<br />
　　14 <br />
<br />
　　15 } <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 />
　　6. 判断是否为某个类的实例 <br />
<br />
　　1 public boolean isInstance(Object obj, Class cls) { <br />
<br />
　　2 return cls.isInstance(obj); <br />
<br />
　　3 } <br />
<br />
　　7. 得到数组中的某个元素 <br />
<br />
　　1 public Object getByArray(Object array, int index) { <br />
<br />
　　2 return Array.get(array,index); <br />
<br />
<img src ="http://www.blogjava.net/zhaozhenlin1224/aggbug/311300.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zhaozhenlin1224/" target="_blank">java/j2ee</a> 2010-01-30 09:48 <a href="http://www.blogjava.net/zhaozhenlin1224/archive/2010/01/30/311300.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java socket</title><link>http://www.blogjava.net/zhaozhenlin1224/archive/2010/01/30/311296.html</link><dc:creator>java/j2ee</dc:creator><author>java/j2ee</author><pubDate>Sat, 30 Jan 2010 01:44:00 GMT</pubDate><guid>http://www.blogjava.net/zhaozhenlin1224/archive/2010/01/30/311296.html</guid><wfw:comment>http://www.blogjava.net/zhaozhenlin1224/comments/311296.html</wfw:comment><comments>http://www.blogjava.net/zhaozhenlin1224/archive/2010/01/30/311296.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/zhaozhenlin1224/comments/commentRss/311296.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zhaozhenlin1224/services/trackbacks/311296.html</trackback:ping><description><![CDATA[事实上网络编程简单的理解就是两台计算机相互通讯数据而已。对于程序员而言，去掌握一种编程接口并使用一种编程模型相对就会显得简单的多了。<strong><a title="更多Java文章" href="http://dev.yesky.com/devjava" target="_blank"><font color="#204890">Java</font></a> SDK</strong>提供一些相对简单的Api来完成这些工作，Socket就是其中之一。
<p>　　对于Java而言。这些Api存在与Java.net这个包里面。因此只要导入这个包就可以准备网络编程了。网络编程的基本模型就是客户机到服务器模型。简单的说就是两个进程之间相互通讯，然后其中一个必须提供一个固定的位置，而另一个则只需要知道这个固定的位置，并去建立两者之间的联系。然后完成数据的通讯就可以了。这里提供固定位置的通常称为服务器，而建立联系的通常叫做客户端。基于这个简单的模型，就可以进入网络编程。</p>
<p>　　Java对这个模型的支持有很多种Api.而这里我只想介绍有关Socket的编程接口。对于Java而言已经简化了Socket的编程接口。首先我们来讨论有关提供固定位置的服务方是如何建立的。Java提供了ServerSocket来对其进行支持。事实上当你创建该类的一个实力对象并提供一个端口资源你就建立了一个固定位置可以让其他计算机来访问你。</p>
<p>
<table class="FCK__ShowTableBorders" style="border-right: #cccccc 1px dotted; table-layout: fixed; border-top: #cccccc 1px dotted; border-left: #cccccc 1px dotted; border-bottom: #cccccc 1px dotted" cellspacing="0" cellpadding="6" width="95%" align="center" border="0">
    <tbody>
        <tr>
            <td style="word-wrap: break-word" bgcolor="#f3f3f3"><font style="font-weight: bold; color: #990000">以下是引用片段：</font><br />
            　　ServerSocket server=new ServerSocket(6789);</td>
        </tr>
    </tbody>
</table>
</p>
<p>　　这里稍微要注意的是端口的分配必须是唯一的。因为端口是为了唯一标识每台计算机唯一服务的。另外端口号是从0~65535之间的，前1024个端口已经被Tcp/Ip 作为保留端口，因此你所分配的端口只能是1024个之后的。</p>
<p>　　好了。我们有了固定位置。现在所需要的就是一根连接线了。该连接线由客户方首先提出要求。因此Java同样提供了一个Socket对象来对其进行支持。只要客户方创建一个Socket的实例对象进行支持就可以了。</p>
<p>
<table class="FCK__ShowTableBorders" style="border-right: #cccccc 1px dotted; table-layout: fixed; border-top: #cccccc 1px dotted; border-left: #cccccc 1px dotted; border-bottom: #cccccc 1px dotted" cellspacing="0" cellpadding="6" width="95%" align="center" border="0">
    <tbody>
        <tr>
            <td style="word-wrap: break-word" bgcolor="#f3f3f3"><font style="font-weight: bold; color: #990000">以下是引用片段：</font><br />
            　　Socket client=new Socket(InetAddress.getLocalHost()，5678);</td>
        </tr>
    </tbody>
</table>
</p>
<p>　　客户机必须知道有关服务器的IP地址。对于着一点Java也提供了一个相关的类InetAddress 该对象的实例必须通过它的静态方法来提供。它的静态方法主要提供了得到本机IP 和通过名字或IP直接得到InetAddress的方法。</p>
<p>　　好了，上面的方法基本可以建立一条连线让两台计算机相互交流了。可是数据是如何传输的呢?事实上I/O操作总是和网络编程息息相关的。因为底层的网络是继续数据的。除非远程调用，处理问题的核心在执行上。</p>
<p>　　否则数据的交互还是依赖于IO操作的。所以你也必须导入Java.io这个包。Java的IO操作也不复杂。它提供了针对于字节流和Unicode的读者和写者，然后也提供了一个缓冲用于数据的读写。</p>
<p>
<table class="FCK__ShowTableBorders" style="border-right: #cccccc 1px dotted; table-layout: fixed; border-top: #cccccc 1px dotted; border-left: #cccccc 1px dotted; border-bottom: #cccccc 1px dotted" cellspacing="0" cellpadding="6" width="95%" align="center" border="0">
    <tbody>
        <tr>
            <td style="word-wrap: break-word" bgcolor="#f3f3f3"><font style="font-weight: bold; color: #990000">以下是引用片段：</font><br />
            　　BufferedReader in=new BufferedReader(new InputStreamReader(server.getInputStream())); <br />
            　　PrintWriter out=new PrintWriter(server.getOutputStream());</td>
        </tr>
    </tbody>
</table>
</p>
<p>　　上面两句就是建立缓冲并把原始的字节流转变为Unicode可以操作。而原始的字节流来源于Socket的两个方法，getInputStream()和getOutputStream()方，分别用来得到输入和输出。那么现在有了基本的模型和基本的操作工具，我们可以做一个简单的Socket例程了服务方：</p>
<p>
<table class="FCK__ShowTableBorders" style="border-right: #cccccc 1px dotted; table-layout: fixed; border-top: #cccccc 1px dotted; border-left: #cccccc 1px dotted; border-bottom: #cccccc 1px dotted" cellspacing="0" cellpadding="6" width="95%" align="center" border="0">
    <tbody>
        <tr>
            <td style="word-wrap: break-word" bgcolor="#f3f3f3">
            <p><font style="font-weight: bold; color: #990000">以下是引用片段：</font><br />
            　　import java.io.BufferedReader;<br />
            import java.io.IOException;<br />
            import java.io.InputStreamReader;<br />
            import java.io.PrintWriter;<br />
            import java.net.*;</p>
            <p>public class MyServer{<br />
            public static void main (String[] args) throws IOException <br />
            {<br />
            &nbsp;&nbsp; ServerSocket server=new ServerSocket(5678); <br />
            &nbsp;&nbsp; Socket client = server.accept(); <br />
            &nbsp;&nbsp; BufferedReader in=new BufferedReader(new InputStreamReader (client.getInputStream())); <br />
            &nbsp;&nbsp; PrintWriter out=new PrintWriter(client.getOutputStream()); <br />
            &nbsp;&nbsp; while(true) <br />
            &nbsp;&nbsp; { <br />
            &nbsp;&nbsp;&nbsp; String str=in.readLine(); <br />
            &nbsp;&nbsp;&nbsp; System.out.println(str); <br />
            &nbsp;&nbsp;&nbsp; out.println(str+"has receive..."); <br />
            &nbsp;&nbsp;&nbsp; out.flush(); <br />
            &nbsp;&nbsp;&nbsp; if(str.equals("end")) <br />
            &nbsp;&nbsp;&nbsp; break; <br />
            &nbsp;&nbsp; } <br />
            &nbsp;&nbsp; client.close();<br />
            } <br />
            }</p>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p>　　这个程序的主要目的在于服务器不断接收客户机所写入的信息只到。客户机发送"End"字符串就退出程序。并且服务器也会做出"Receive"为回应。告知客户机已接收到消息。客户机代码：</p>
<p>
<table class="FCK__ShowTableBorders" style="border-right: #cccccc 1px dotted; table-layout: fixed; border-top: #cccccc 1px dotted; border-left: #cccccc 1px dotted; border-bottom: #cccccc 1px dotted" cellspacing="0" cellpadding="6" width="95%" align="center" border="0">
    <tbody>
        <tr>
            <td style="word-wrap: break-word" bgcolor="#f3f3f3"><font style="font-weight: bold; color: #990000">以下是引用片段：</font><br />
            　import java.net.*; <br />
            import java.io.*; <br />
            public class Client{ <br />
            static Socket server; <br />
            public static void main(String[] args) throws Exception <br />
            { <br />
            &nbsp;&nbsp; server = new Socket(InetAddress.getLocalHost(),5678); <br />
            &nbsp;&nbsp; BufferedReader in=new BufferedReader(new InputStreamReader(server.getInputStream())); <br />
            &nbsp;&nbsp; PrintWriter out=new PrintWriter(server.getOutputStream()); <br />
            &nbsp;&nbsp; BufferedReader wt=new BufferedReader(new InputStreamReader(System.in)); <br />
            &nbsp;&nbsp; while(true) <br />
            &nbsp;&nbsp; { <br />
            &nbsp;&nbsp;&nbsp; String str=wt.readLine(); <br />
            &nbsp;&nbsp;&nbsp; out.println(InetAddress.getLocalHost()+"--"+str); <br />
            &nbsp;&nbsp;&nbsp; out.flush(); <br />
            &nbsp;&nbsp;&nbsp; if(str.equals("end")) <br />
            &nbsp;&nbsp;&nbsp; { <br />
            &nbsp;&nbsp;&nbsp;&nbsp; break; <br />
            &nbsp;&nbsp;&nbsp; } <br />
            &nbsp;&nbsp;&nbsp; System.out.println(in.readLine()); <br />
            &nbsp;&nbsp; } <br />
            &nbsp;&nbsp; server.close(); <br />
            } <br />
            }</td>
        </tr>
    </tbody>
</table>
</p>
<img src ="http://www.blogjava.net/zhaozhenlin1224/aggbug/311296.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zhaozhenlin1224/" target="_blank">java/j2ee</a> 2010-01-30 09:44 <a href="http://www.blogjava.net/zhaozhenlin1224/archive/2010/01/30/311296.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JDK中正则表达式</title><link>http://www.blogjava.net/zhaozhenlin1224/archive/2010/01/29/311268.html</link><dc:creator>java/j2ee</dc:creator><author>java/j2ee</author><pubDate>Fri, 29 Jan 2010 14:27:00 GMT</pubDate><guid>http://www.blogjava.net/zhaozhenlin1224/archive/2010/01/29/311268.html</guid><wfw:comment>http://www.blogjava.net/zhaozhenlin1224/comments/311268.html</wfw:comment><comments>http://www.blogjava.net/zhaozhenlin1224/archive/2010/01/29/311268.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/zhaozhenlin1224/comments/commentRss/311268.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zhaozhenlin1224/services/trackbacks/311268.html</trackback:ping><description><![CDATA[<p><br />
一、正则表达式的编译形式<br />
1）指定为字符串的正则表达式必须首先被编译为此类的实例。compile<br />
2）将得到的模式用于创建Matcher对象。matcher<br />
3）依照正则表达式，该对象可以于任意字符序列匹配。matches<br />
例：<br />
Pattern p=Pattern.compile("a*b");<br />
Matcher m=P.matcher("aaaaab");<br />
boolean b=m.matches();<br />
二、规则<br />
1）字符类<br />
.&nbsp;&nbsp; 表示任何字符<br />
[abc]&nbsp;&nbsp; 包含a、b、c的任何字符&nbsp; （和a|b|c相同）<br />
[^abc]&nbsp;&nbsp; 除a、b、c之外的任何字符 （否定）<br />
[a-zA-Z]&nbsp; 任何从a到z或从A到Z的字符 （范围）<br />
[abc[hij]]&nbsp; 任意a、b、c、h、i、j字符 （与a|b|c|h|i|j相同）（合并）<br />
[a-z&amp;&amp;[hij]]&nbsp; 任意h、i、j字符&nbsp; （交）<br />
\s&nbsp;&nbsp; whitespace符&nbsp;&nbsp; （空格、tab、换行、换页、回车）<br />
\S&nbsp;&nbsp; 非whitespace符&nbsp; （[^\s]）<br />
\d&nbsp;&nbsp; 数字[0-9]<br />
\D&nbsp;&nbsp; 非数字[^0-9]<br />
\w&nbsp;&nbsp; word character&nbsp; （[a-zA-Z_[0-9]）<br />
\W&nbsp;&nbsp; 非word character&nbsp; （^\w）<br />
2）在Java中，&#8220;\\&#8221;意味着正在插入一个正则表达式的反斜杠，随后的字符具有特殊意义。<br />
XY&nbsp; XY<br />
X|Y&nbsp; X或Y<br />
(X)&nbsp; Capturing group<br />
3）边界匹配<br />
^ 一行的开始<br />
$ 一行的结束<br />
\b 词界<br />
\B 非词界<br />
\G 上一级的结尾<br />
4）量词<br />
？&nbsp; 0或1个<br />
*&nbsp; 0或多个<br />
+&nbsp; 1或多个<br />
X{n}&nbsp; X，恰好n次<br />
X{n,}&nbsp; X，至少n次<br />
X{n,m}&nbsp; X，至少n次，至多m次<br />
三、字符序列<br />
CharSequence接口，从String到StringBuffer类中抽象出。<br />
interface CharSequence{<br />
&nbsp;charAt(int i);&nbsp; //返回指定索引处的char值<br />
&nbsp;length();&nbsp;&nbsp; //返回长度<br />
&nbsp;subSequence(int start,int end); //返回从索引start开始，end结束的子序列<br />
&nbsp;toString();&nbsp;&nbsp; //返回字符串<br />
&nbsp;}<br />
四、在Java中，正则表达式是通过java.util.regex包里面的Pattern和Matcher类来实现的。<br />
1）Matcher.find()用于发现应用于CharSequence的多重模式匹配。<br />
2）find(int start) 重置此匹配器，然后尝试查找匹配该模式、从指定索引开始的输入序列的下一个子序列。<br />
例：<br />
package myfile;<br />
import java.util.regex.*;<br />
import java.util.*;<br />
public class FindDemo {<br />
&nbsp;private static String str="boolean contains(CharSequence s)&nbsp; new Test()";<br />
&nbsp;public static void main(String[] args) {&nbsp; <br />
&nbsp; Matcher m=Pattern.compile("\\w+").matcher("Evening is full of the linnet's wings");<br />
&nbsp; while(m.find())<br />
&nbsp;&nbsp; System.out.println(m.group());<br />
&nbsp; int i=0;<br />
&nbsp; while(m.find(i)){<br />
&nbsp;&nbsp; i++;<br />
&nbsp;&nbsp; System.out.print(m.group()+" ");<br />
&nbsp; }<br />
&nbsp; System.out.println("\n"+"i="+i);<br />
&nbsp;}<br />
}<br />
</p>
<p>一、组group<br />
1、组是由圆括号分开的正则表达式，随后可以根据它们的组号进行调用。<br />
第0组匹配整个表达式，第1组匹配第1个圆括号扩起来的组，......依次类推。<br />
如：A(B(C))D<br />
有3个组：<br />
第0组：ABCD<br />
第1组：BC<br />
第2组：C</p>
<p>例子：<br />
package myfile;<br />
import java.util.regex.*;<br />
public class GroupR2 {<br />
&nbsp;public static void main(String[] args) {<br />
&nbsp; String[] input=new String[]{<br />
&nbsp;&nbsp;&nbsp; "Java has regular expressions in 1.4",<br />
&nbsp;&nbsp;&nbsp; "regular expressions now expressing in Java",<br />
&nbsp;&nbsp;&nbsp; "Java represses oracular expressions"<br />
&nbsp; };<br />
&nbsp; Pattern<br />
&nbsp; p1=Pattern.compile("re\\w*"),<br />
&nbsp; p2=Pattern.compile("Java.*");<br />
&nbsp; for(int i=0;i&lt;input.length;i++){<br />
&nbsp;&nbsp; System.out.println("input "+i+":"+input[i]);<br />
&nbsp;&nbsp; Matcher<br />
&nbsp;&nbsp; m1=p1.matcher(input[i]),<br />
&nbsp;&nbsp; m2=p2.matcher(input[i]);<br />
&nbsp;&nbsp; while(m1.find())<br />
&nbsp;&nbsp;&nbsp; System.out.println("m1.find() '"+m1.group()+"' start= "+m1.start()+" end= "+m1.end());<br />
&nbsp;&nbsp; while(m2.find())<br />
&nbsp;&nbsp;&nbsp; System.out.println("m2.find() '"+m2.group()+"' start= "+m2.start()+" end= "+m2.end());<br />
&nbsp;&nbsp; if(m1.lookingAt())<br />
&nbsp;&nbsp;&nbsp; System.out.println("m1.lookingAt() start = "+m1.start()+" end= "+m1.end());<br />
&nbsp;&nbsp; if(m2.lookingAt())<br />
&nbsp;&nbsp;&nbsp; System.out.println("m2.lookingAt() start = "+m2.start()+" end= "+m2.end());<br />
&nbsp;&nbsp; if(m1.matches())<br />
&nbsp;&nbsp;&nbsp; System.out.println("m1.matches() start= "+m1.start()+" end= "+m1.end());<br />
&nbsp;&nbsp; if(m2.matches())<br />
&nbsp;&nbsp;&nbsp; System.out.println("m2.matches() start= "+m2.start()+" end= "+m2.end());<br />
&nbsp;&nbsp; <br />
&nbsp; }<br />
&nbsp;}<br />
&nbsp;/**<br />
&nbsp;* 输u20986 结u26524 ：<br />
&nbsp;input 0:Java has regular expressions in 1.4<br />
&nbsp;m1.find() 'regular' start= 9 end= 16<br />
&nbsp;m1.find() 'ressions' start= 20 end= 28<br />
&nbsp;m2.find() 'Java has regular expressions in 1.4' start= 0 end= 35<br />
&nbsp;m2.lookingAt() start = 0 end= 35<br />
&nbsp;m2.matches() start= 0 end= 35<br />
&nbsp;input 1:regular expressions now expressing in Java<br />
&nbsp;m1.find() 'regular' start= 0 end= 7<br />
&nbsp;m1.find() 'ressions' start= 11 end= 19<br />
&nbsp;m1.find() 'ressing' start= 27 end= 34<br />
&nbsp;m2.find() 'Java' start= 38 end= 42<br />
&nbsp;m1.lookingAt() start = 0 end= 7<br />
&nbsp;input 2:Java represses oracular expressions<br />
&nbsp;m1.find() 'represses' start= 5 end= 14<br />
&nbsp;m1.find() 'ressions' start= 27 end= 35<br />
&nbsp;m2.find() 'Java represses oracular expressions' start= 0 end= 35<br />
&nbsp;m2.lookingAt() start = 0 end= 35<br />
&nbsp;m2.matches() start= 0 end= 35<br />
&nbsp;*/<br />
} </p>
<p>2、Matcher对象的方法：<br />
int groupCount()&nbsp;&nbsp;&nbsp; 分组的数目（不含0组）<br />
String group()&nbsp;&nbsp;&nbsp; 返回前一次的匹配操作<br />
String group(int i)&nbsp;&nbsp;&nbsp; 返回前一次匹配操作期间指定的组<br />
int start(int group)&nbsp;&nbsp;&nbsp; 返回前一次匹配操作寻找到的组的起始下标<br />
int end(int group)&nbsp;&nbsp;&nbsp; 返回前一次匹配操作寻找到的组的最后一个字符下标加一的值<br />
二、模式标记<br />
Pattern Pattern.compile(String regex, int flag)<br />
flag有多个值：<br />
（1）Pattern.CANON_EQ&nbsp;&nbsp; 两个字符当且仅当它们的完全规范分解相匹配时，就认为匹配。缺省时，不考虑。<br />
（2）Pattern.CASE_INSENSITIVE&nbsp;&nbsp; 缺省时，仅在ASCII字符集中进行。<br />
（3）Pattern.COMMENTS&nbsp;&nbsp; 忽略空格符，且以#号开始到行末的注释也忽略<br />
（4）Pattern.DOTALL&nbsp;&nbsp;&nbsp;&nbsp; 表达式'.'匹配所有字符，包括行终结符。缺省时，'.'不匹配行终结符。<br />
（5）Pattern.MULTILINE&nbsp; 在多行模式下，表达式&#8216;^'和'$'分别匹配一行的开始和结束。缺省时，它们仅匹配输入的完整字符串的开始和结束。<br />
见例子：</p>
<p>package myfile;<br />
import java.util.regex.*;<br />
public class ReFlags {<br />
&nbsp;public static void main(String[] args) {<br />
&nbsp; String str="java has regex\nJava has regex\n" +<br />
&nbsp;&nbsp;&nbsp; "JaVa has pretty good regular expressions\n"+<br />
&nbsp;&nbsp;&nbsp; "Regular expressions are in JAva";<br />
&nbsp; Pattern p=Pattern.compile("^java", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);<br />
&nbsp; Matcher m=p.matcher(str);<br />
&nbsp; while(m.find()) //find()尝u-29739 查u25214 与u-29723 模u24335 匹u-28339 的u-28781 入u24207 列u30340 下u19968 个u23376 序u21015 。<br />
&nbsp;&nbsp; System.out.println(m.group()); //group()返u22238 由u20197 前u21305 配u25805 作u25152 匹u-28339 的u-28781 入u23376 序u21015 。<br />
&nbsp;}<br />
}<br />
&nbsp;<br />
三、split()<br />
它将输入字符串断开成字符串对象数组，断开边界由正则表达式确定。<br />
String split(CharSequence charseq);<br />
String split(CharSequence charseq, int limit);<br />
第2种limit限制了分裂的数目。</p>
<p>例子：</p>
<p>package myfile;<br />
import java.util.regex.*;<br />
import java.util.*;<br />
public class SplitDemo {<br />
&nbsp;static String input="This!!unusual use!!of exclamation!!points";<br />
&nbsp;public static void main(String[] args) {<br />
&nbsp; System.out.println(Arrays.asList(Pattern.compile("!!").split(input)));<br />
&nbsp; //Arrays.asList() 返回一个受指定数组支持的固定大小的列表。<br />
&nbsp; System.out.println(Arrays.asList(Pattern.compile("!!").split(input,3)));<br />
&nbsp; System.out.println(Arrays.asList("Aha! String has a split() built in!".split(" ")));<br />
&nbsp;}<br />
}</p>
<p>四、替换操作<br />
1）replaceFirst(String replacement)<br />
用replacement替换输入字符串中最先匹配的那部分。<br />
2）replaceAll(String replacement)<br />
用replacement替换输入字符串中所有的匹配部分。<br />
3）appendReplacement(StringBuffer sbuf, String replacement)<br />
逐步地在sbuf中执行替换<br />
4）appendTail(StringBuffer sbuf,String replacement)<br />
在一个或多个appendReplacement()调用之后被调用，以便复制输入字符串的剩余部分。</p>
<p>例子：</p>
<p>package myfile;<br />
import java.util.regex.*;<br />
import java.io.*;<br />
/*!Here's a block of text to use as input to<br />
&nbsp;* the regular expression matcher. Note that we'll<br />
&nbsp;* first extract the block of text by looking for<br />
&nbsp;* the special delimiters, then process the<br />
&nbsp;* extracted block.!<br />
&nbsp;*/<br />
public class TheReplacements {<br />
&nbsp;public static void main(String[] args) throws Exception{<br />
&nbsp; String s="/*!Here's a block of text to use as input to\n"+<br />
&nbsp; " the regular expression matcher. Note that we'll\n"+<br />
&nbsp; "first extract the block of text by looking for\n"+<br />
&nbsp; "the special delimiters, then process the\n"+<br />
&nbsp; "extracted block.!*/";<br />
&nbsp; Pattern p=Pattern.compile("/\\*!(.*)!\\*/", Pattern.DOTALL); //用以匹配在&#8216;/*!&#8217;和&#8216;!*/&#8217;之间的所有文本<br />
&nbsp; Matcher mInput=p.matcher(s);<br />
&nbsp; if(mInput.find())<br />
&nbsp;&nbsp; s=mInput.group(1); //Captured by parentheses<br />
&nbsp; //Replace two or more spaces with a single space:<br />
&nbsp; s=s.replaceAll(" {2,}"," ");<br />
&nbsp; //Replace on or more spaces at the beginning of each line with no spaces.Must enable MULTILINE mode.<br />
&nbsp; s=s.replaceAll("(?m)^+","");<br />
&nbsp; System.out.println(s);<br />
&nbsp; s=s.replaceFirst("[aeiou]","(VOWEL1)");<br />
&nbsp; StringBuffer sbuf=new StringBuffer();<br />
&nbsp; Pattern p1=Pattern.compile("[aeiou]");<br />
&nbsp; Matcher m1=p1.matcher(s);<br />
&nbsp; //Process the find information as you perform the replacements:<br />
&nbsp; while(m1.find())<br />
&nbsp;&nbsp; m1.appendReplacement(sbuf, m1.group().toUpperCase());<br />
&nbsp; //Put in the remainder of the text:<br />
&nbsp; m1.appendTail(sbuf);<br />
&nbsp; System.out.println(sbuf);<br />
&nbsp;}<br />
}</p>
<p>五、reset()方法，可将现有的Matcher对象应用于一个新的字符序列。<br />
例子：</p>
<p>package myfile;<br />
import java.util.regex.*;<br />
import java.io.*;<br />
public class Resetting {</p>
<p>&nbsp;public static void main(String[] args) {<br />
&nbsp; Matcher m=Pattern.compile("[frb][aiu][gx]").matcher("fix the rug with bags");<br />
&nbsp; while(m.find())<br />
&nbsp;&nbsp; System.out.println(m.group());<br />
&nbsp; m.reset("fix the rug with bags");<br />
&nbsp; while(m.find())<br />
&nbsp;&nbsp; System.out.println(m.group());<br />
&nbsp;}</p>
<p>}</p>
<p>六、在JDK1.4之前，将字符串分离成几部份的方法是：<br />
利用StringTokenizer将该字符串&#8220;用标记断开&#8221;。<br />
例子：</p>
<p>package myfile;<br />
import java.util.*;<br />
public class ReplacingStringTokenizer {<br />
&nbsp;public static void main(String[] args) {<br />
&nbsp; // TODO 自动生成方法存根<br />
&nbsp; String input ="But I'm not dead yet! I feel happy!";<br />
&nbsp; StringTokenizer stoke=new StringTokenizer(input);<br />
&nbsp; while(stoke.hasMoreElements())<br />
&nbsp;&nbsp; System.out.println(stoke.nextToken());<br />
&nbsp; System.out.println(Arrays.asList(input.split(" ")));<br />
&nbsp;}</p>
<p>}<br />
&nbsp;</p>
<p>&nbsp;</p>
<p>本文来自CSDN博客，转载请标明出处：http://blog.csdn.net/chszs/archive/2007/03/28/1544367.aspx</p>
<img src ="http://www.blogjava.net/zhaozhenlin1224/aggbug/311268.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zhaozhenlin1224/" target="_blank">java/j2ee</a> 2010-01-29 22:27 <a href="http://www.blogjava.net/zhaozhenlin1224/archive/2010/01/29/311268.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>