??xml version="1.0" encoding="utf-8" standalone="yes"?>亚洲国产精品久久久,亚洲尤物视频网,亚洲精品久久久久http://www.aygfsteel.com/zhuzi1987/category/36118.htmlJAVA+YOU!中国的开发者们加a!!zh-cnSat, 06 Dec 2008 15:38:31 GMTSat, 06 Dec 2008 15:38:31 GMT60【{】垃圑֛收与强引用,软引用,弱引用,qd用的关系(?http://www.aygfsteel.com/zhuzi1987/archive/2008/12/06/244803.html竹子竹子Sat, 06 Dec 2008 13:14:00 GMThttp://www.aygfsteel.com/zhuzi1987/archive/2008/12/06/244803.htmlhttp://www.aygfsteel.com/zhuzi1987/comments/244803.htmlhttp://www.aygfsteel.com/zhuzi1987/archive/2008/12/06/244803.html#Feedback0http://www.aygfsteel.com/zhuzi1987/comments/commentRss/244803.htmlhttp://www.aygfsteel.com/zhuzi1987/services/trackbacks/244803.html import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;


public class Testone {
public static void main(String args[]){
A a=new A();
//a.test();
//SoftReference sr = new SoftReference(a);
ReferenceQueue<A> rq = new ReferenceQueue<A>();
WeakReference<A> wr = new WeakReference<A>(a, rq);
a = null;
System.out.println(wr.get());
System.out.println(rq.poll());
System.gc();
System.runFinalization();
System.out.println(wr.get());
System.out.println(rq.poll());
if (wr != null) {
a = (A)wr.get();
System.out.println("asdasdas");
a.test();
}
else{
a = new A();
System.out.println("123123");
a.test();
a = null;
wr = new WeakReference<A>(a);
}

}
}
class A{
void test(){
System.out.println("A.test()");
}
}


竹子 2008-12-06 21:14 发表评论
]]>
【{】垃圑֛收与强引用,软引用,弱引用,qd用的关系(一)http://www.aygfsteel.com/zhuzi1987/archive/2008/12/06/244802.html竹子竹子Sat, 06 Dec 2008 13:13:00 GMThttp://www.aygfsteel.com/zhuzi1987/archive/2008/12/06/244802.htmlhttp://www.aygfsteel.com/zhuzi1987/comments/244802.htmlhttp://www.aygfsteel.com/zhuzi1987/archive/2008/12/06/244802.html#Feedback0http://www.aygfsteel.com/zhuzi1987/comments/commentRss/244802.htmlhttp://www.aygfsteel.com/zhuzi1987/services/trackbacks/244802.html垃圾回收与强引用QY引用Q弱引用Q引用的关p(一Q?/h1> Java 2 q_引入?nbsp;java.lang.ref 包,其中包括的类可以让?zhn)引用对象Q而不它们留在内存中。这些类q提供了与垃圾收集器Qgarbage collectorQ之间有限的交互。Peter Haggar 在本文中分析?nbsp;SoftReference、WeakReference ?nbsp;PhantomReference cȝ功能和行为,q就q些cȝ使用l出了一些编E风g的徏议?br /> 当在 Java 2 q_中首ơ引?nbsp;java.lang.ref 包(其中包含 SoftReference、WeakReference ?nbsp;PhantomReference c)Ӟ它的实用性显然被q分夸大了。它包含的类可能是有用的Q但q些cd有的某些局限性会(x)使它们显得不是很有吸引力Q而且其应用程序也特别局限于解决一cȝ定的问题?br />
垃圾攉概述
引用cȝ主要功能是能够引用仍可以被垃圾攉器回收的对象。在引入引用cM前,我们只能使用强引用(strong referenceQ。D例来_下面一行代码显C的是强引?nbsp;objQ?br />

Object obj = new Object();




obj q个引用引用堆中存储的一个对象。只?nbsp;obj 引用q存在,垃圾攉器就永远不会(x)释放用来容纳该对象的存储I间?br />
?nbsp;obj 出范围或被昑ּ地指定ؓ(f) null Ӟ垃圾攉器就认ؓ(f)没有对这个对象的其它引用Q也可以收集它了。然而?zhn)q需要注意一个重要的l节Q仅凭对象可以被攉q不意味着垃圾攉器的一ơ指定运行就能够回收它。由于各U垃圾收集算法有所不同Q某些算法会(x)更频J地分析生存期较短的对象Q而不是较老、生存期较长的对象。因此,一个可供收集的对象可能永远也不?x)被回收。如果程序在垃圾攉器释攑֯象之前结束,q种情况可能会(x)出现。因此,概括地说Q?zhn)永远无法保证可供攉的对象L?x)被垃圾攉器收集?br />
q些信息对于(zhn)分析引用类是很重要的。由于垃圾收集有着特定的性质Q所以引用类实际上可能没有?zhn)原来惛_的那么有用,管如此Q它们对于特定问题来说还是很有用的类。Y引用Qsoft referenceQ、弱引用Qweak referenceQ和虚引用(phantom referenceQ对象提供了三种不同的方式来在不妨碍攉的情况下引用堆对象。每U引用对象都有不同的行ؓ(f)Q而且它们与垃圾收集器之间的交互也有所不同。此外,q几个新的引用类都表现出比典型的强引?#8220;更弱”的引用Ş式。而且Q内存中的一个对象可以被多个引用Q可以是强引用、Y引用、弱引用或虚引用Q引用。在q一步往下讨Z前,让我们来看看一些术语:(x)

强可及对象(strongly reachableQ:(x)可以通过强引用访问的对象?br />

软可及对象(softly reachableQ:(x)不是强可及对象,q且能够通过软引用访问的对象?br />

弱可及对象(weakly reachableQ:(x)不是强可及对象也不是软可及对象,q且能够通过弱引用访问的对象?br />

虚可及对象(phantomly reachableQ:(x)不是强可及对象、Y可及对象Q也不是弱可及对象,已经l束的,可以通过虚引用访问的对象?br />

清除Q将引用对象?nbsp;referent 域设|ؓ(f) nullQƈ引用类在堆中引用的对象声明为可l束的?br /> SoftReference c?br /> SoftReference cȝ一个典型用途就是用于内存敏感的高速缓存。SoftReference 的原理是Q在保持对对象的引用时保证在 JVM 报告内存不情况之前清除所有的软引用。关键之处在于,垃圾攉器在q行时可能会(x)Q也可能不会(x)Q释放Y可及对象。对象是否被释放取决于垃圾收集器的算法以及垃圾收集器q行时可用的内存数量?nbsp;

WeakReference c?br /> WeakReference cȝ一个典型用途就是规范化映射Qcanonicalized mappingQ。另外,对于那些生存期相对较长而且重新创徏的开销也不高的对象来说Q弱引用也比较有用。关键之处在于,垃圾攉器运行时如果到了弱可及对象Q将释放 WeakReference 引用的对象。然而,h意,垃圾攉器可能要q行多次才能扑ֈq攑ּ可及对象?br />
PhantomReference c?br /> PhantomReference cd能用于跟t对被引用对象即进行的攉。同P它还能用于执?nbsp;pre-mortem 清除操作。PhantomReference 必须?nbsp;ReferenceQueue cM起用。需?nbsp;ReferenceQueue 是因为它能够充当通知机制。当垃圾攉器确定了某个对象是虚可及对象ӞPhantomReference 对象p攑֜它的 ReferenceQueue 上。将 PhantomReference 对象攑֜ ReferenceQueue 上也是一个通知Q表?nbsp;PhantomReference 对象引用的对象已l结束,可供攉了。这使?zhn)能够刚好在对象占用的内存被回收之前采取行动?nbsp; 

垃圾攉器和引用交互
垃圾攉器每ơ运行时都可以随意地释放不再是强可及的对象占用的内存。如果垃圾收集器发现了Y可及对象Q就?x)出C列情况:(x)

SoftReference 对象?nbsp;referent 域被讄?nbsp;nullQ从而该对象不再引?nbsp;heap 对象?br />

SoftReference 引用q的 heap 对象被声明ؓ(f) finalizable?br />

?nbsp;heap 对象?nbsp;finalize() Ҏ(gu)被运行而且该对象占用的内存被释放,SoftReference 对象pd到它?nbsp;ReferenceQueueQ如果后者存在的话)?br /> 如果垃圾攉器发C弱可及对象,׃(x)出现下列情况Q?br />
WeakReference 对象?nbsp;referent 域被讄?nbsp;nullQ从而该对象不再引?nbsp;heap 对象?br />

WeakReference 引用q的 heap 对象被声明ؓ(f) finalizable?br />

?nbsp;heap 对象?nbsp;finalize() Ҏ(gu)被运行而且该对象占用的内存被释放时QW(xu)eakReference 对象pd到它?nbsp;ReferenceQueueQ如果后者存在的话)?br /> 如果垃圾攉器发C虚可及对象,׃(x)出现下列情况Q?br />
PhantomReference 引用q的 heap 对象被声明ؓ(f) finalizable?br />

与Y引用和弱引用有所不同QPhantomReference 在堆对象被释放之前就被添加到它的 ReferenceQueue。(误住,所有的 PhantomReference 对象都必ȝl过兌?nbsp;ReferenceQueue 来创建。)q(zhn)能够在堆对象被回收之前采取行动?br /> 误虑清单 1 中的代码?br />
清单 1. 使用 WeakReference ?nbsp;ReferenceQueue 的示例代?br /> //Create a strong reference to an object
MyObject obj = new MyObject(); //1

//Create a reference queue
ReferenceQueue rq = new ReferenceQueue(); //2

//Create a weakReference to obj and associate our reference queue
WeakReference wr = new WeakReference(obj, rq); //3



?nbsp;//1 创徏 MyObject 对象Q而行 //2 则创?nbsp;ReferenceQueue 对象。行 //3 创徏引用其引用对?nbsp;MyObject ?nbsp;WeakReference 对象Q还创徏它的 ReferenceQueue。请注意Q每个对象引用(obj、rq ?nbsp;wrQ都是强引用。要利用q些引用c,(zhn)必d消对 MyObject 对象的强引用Q方法是?nbsp;obj 讄?nbsp;null。前面说q,如果不这样做Q对?nbsp;MyObject 永远都不?x)被回收Q引用类的Q何优炚w?x)被削弱?br />
每个引用c都有一?nbsp;get() Ҏ(gu)Q?nbsp;ReferenceQueue cL一?nbsp;poll() Ҏ(gu)。get() Ҏ(gu)q回对被引用对象的引用。在 PhantomReference 上调?nbsp;get() L?x)返?nbsp;null。这是因?nbsp;PhantomReference 只用于跟t收集。poll() Ҏ(gu)q回已被d到队列中的引用对象,如果队列中没有Q何对象,它就q回 null。因此,执行清单 1 之后再调?nbsp;get() ?nbsp;poll() 的结果可能是Q?br />

wr.get(); //returns reference to MyObject
rq.poll(); //returns null




现在我们假定垃圾攉器开始运行。由?nbsp;MyObject 对象没有被释放,所?nbsp;get() ?nbsp;poll() Ҏ(gu)返回同L(fng)|obj 仍然保持对该对象q行强引用。实际上Q对象布局q是没有改变Q和?nbsp;1 所C的差不多。然而,误虑下面的代码:(x)


obj = null;
System.gc(); //run the collector







现在Q调?nbsp;get() ?nbsp;poll() 生与前面不同的结果:(x)


wr.get(); //returns null
rq.poll(); //returns a reference to the WeakReference object




q种情况表明QMyObject 对象Q对它的引用原来是由 WeakReference 对象q行的)不再可用。这意味着垃圾攉器释放了 MyObject 占用的内存,从而 WeakReference 对象可以被放在它?nbsp;ReferenceQueue 上。这P(zhn)就可以知道?nbsp;WeakReference ?nbsp;SoftReference cȝ get() Ҏ(gu)q回 null Ӟ有一个对象被声明?nbsp;finalizableQ而且可能Q不q不一定)被收集。只有当 heap 对象完全l束而且其内存被回收后,W(xu)eakReference ?nbsp;SoftReference 才会(x)被放C其关联的 ReferenceQueue 上。清?nbsp;2 昄了一个完整的可运行程序,它展CZq些原理中的一部分。这D代码本w就颇具说明性,它含有很多注释和打印语句Q可以帮助?zhn)理解?br />
清单 2. 展示引用cd理的完整E序
import java.lang.ref.*;
class MyObject
{
protected void finalize() throws Throwable
{
System.out.println("In finalize method for this object: " +
this);
}
}

class ReferenceUsage
{
public static void main(String args[])
{
hold();
release();
}

public static void hold()
{
System.out.println("Example of incorrectly holding a strong " +
"reference");
//Create an object
MyObject obj = new MyObject();
System.out.println("object is " + obj);

//Create a reference queue
ReferenceQueue rq = new ReferenceQueue();

//Create a weakReference to obj and associate our reference queue
WeakReference wr = new WeakReference(obj, rq);

System.out.println("The weak reference is " + wr);

//Check to see if it´s on the ref queue yet
System.out.println("Polling the reference queue returns " +
rq.poll());
System.out.println("Getting the referent from the " +
"weak reference returns " + wr.get());

System.out.println("Calling GC");
System.gc();
System.out.println("Polling the reference queue returns " +
rq.poll());
System.out.println("Getting the referent from the " +
"weak reference returns " + wr.get());
}

public static void release()
{
System.out.println("");
System.out.println("Example of correctly releasing a strong " +
"reference");
//Create an object
MyObject obj = new MyObject();
System.out.println("object is " + obj);

//Create a reference queue
ReferenceQueue rq = new ReferenceQueue();

//Create a weakReference to obj and associate our reference queue
WeakReference wr = new WeakReference(obj, rq);

System.out.println("The weak reference is " + wr);

//Check to see if it´s on the ref queue yet
System.out.println("Polling the reference queue returns " +
rq.poll());
System.out.println("Getting the referent from the " +
"weak reference returns " + wr.get());

System.out.println("Set the obj reference to null and call GC");
obj = null;
System.gc();
System.out.println("Polling the reference queue returns " +
rq.poll());
System.out.println("Getting the referent from the " +
"weak reference returns " + wr.get());
}
}




用途和风格
q些c背后的原理是避免在应用程序执行期间将对象留在内存中。相反,(zhn)以软引用、弱引用或虚引用的方式引用对象,q样垃圾攉器就能够随意地释攑֯象。当(zhn)希望尽可能减小应用E序在其生命周期中用的堆内存大时Q这U用途就很有好处。?zhn)必须CQ要使用q些c,(zhn)就不能保留对对象的强引用。如果?zhn)q么做了Q那׃(x)费q些cL提供的Q何好处?br />
另外Q?zhn)必须使用正确的编E风g查收集器在用对象之前是否已l回收了它,如果已经回收了,(zhn)首先必重新创对象。这个过E可以用不同的编E风格来完成。选择错误的风g(x)D出问题。请考虑清单 3 中从 WeakReference 索被引用对象的代码风|(x)

清单 3. 索被引用对象的风?br /> obj = wr.get();
if (obj == null)
{
wr = new WeakReference(recreateIt()); //1
obj = wr.get(); //2
}
//code that works with obj




研究了这D代码之后,L(fng)看清?nbsp;4 中从 WeakReference 索被引用对象的另一U代码风|(x)

清单 4. 索被引用对象的另一U风?br /> obj = wr.get();
if (obj == null)
{
obj = recreateIt(); //1
wr = new WeakReference(obj); //2
}
//code that works with obj




h较这两种风格Q看看?zhn)能否定哪种风格一定可行,哪一U不一定可行。清?nbsp;3 中体现出的风g一定在所有情况下都可行,但清?nbsp;4 的风格就可以。清?nbsp;3 中的风格不够好的原因在于Qif 块的Ml束之后 obj 不一定是非空倹{请考虑一下,如果垃圾攉器在清单 3 的行 //1 之后但在?nbsp;//2 执行之前q行?x)怎样。recreateIt() Ҏ(gu)重新创对象Q但它会(x)?nbsp;WeakReference 引用Q而不是强引用。因此,如果攉器在?nbsp;//2 在重新创建的对象上施加一个强引用之前q行Q对象就?x)丢失,wr.get() 则返?nbsp;null?br />
清单 4 不会(x)出现q种问题Q因 //1 重新创徏了对象ƈ为其指定了一个强引用。因此,如果垃圾攉器在该行之后Q但在行 //2 之前Q运行,该对象就不会(x)被回收。然后,?nbsp;//2 创建对 obj ?nbsp;WeakReference。在使用q个 if 块之后的 obj 之后Q?zhn)应该?nbsp;obj 讄?nbsp;nullQ从而让垃圾攉器能够回收这个对象以充分利用弱引用。清?nbsp;5 昄了一个完整的E序Q它?yu)展C刚才我们描q的风格之间的差异。(要运行该E序Q其q行目录中必L一?#8220;temp.fil”文g?br />
清单 5. 展示正确的和不正的~程风格的完整程序?br /> import java.io.*;
import java.lang.ref.*;

class ReferenceIdiom
{
public static void main(String args[]) throws FileNotFoundException
{
broken();
correct();
}

public static FileReader recreateIt() throws FileNotFoundException
{
return new FileReader("temp.fil");
}

public static void broken() throws FileNotFoundException
{
System.out.println("Executing method broken");
FileReader obj = recreateIt();
WeakReference wr = new WeakReference(obj);

System.out.println("wr refers to object " + wr.get());

System.out.println("Now, clear the reference and run GC");
//Clear the strong reference, then run GC to collect obj.
obj = null;
System.gc();

System.out.println("wr refers to object " + wr.get());

//Now see if obj was collected and recreate it if it was.
obj = (FileReader)wr.get();
if (obj == null)
{
System.out.println("Now, recreate the object and wrap it
in a WeakReference");
wr = new WeakReference(recreateIt());
System.gc(); //FileReader object is NOT pinned...there is no
//strong reference to it. Therefore, the next
//line can return null.
obj = (FileReader)wr.get();
}
System.out.println("wr refers to object " + wr.get());
}

public static void correct() throws FileNotFoundException
{
System.out.println("");
System.out.println("Executing method correct");
FileReader obj = recreateIt();
WeakReference wr = new WeakReference(obj);

System.out.println("wr refers to object " + wr.get());

System.out.println("Now, clear the reference and run GC");
//Clear the strong reference, then run GC to collect obj
obj = null;
System.gc();

System.out.println("wr refers to object " + wr.get());

//Now see if obj was collected and recreate it if it was.
obj = (FileReader)wr.get();
if (obj == null)
{
System.out.println("Now, recreate the object and wrap it
in a WeakReference");
obj = recreateIt();
System.gc(); //FileReader is pinned, this will not affect
//anything.
wr = new WeakReference(obj);
}
System.out.println("wr refers to object " + wr.get());
}
}




ȝ
如果使用得当Q引用类q是很有用的。然而,׃它们所依赖的垃圾收集器行ؓ(f)有时候无法预知,所以其实用性就?x)受到媄响。能否有效地使用它们q取决于是否应用了正的~程风格Q关键在于?zhn)要理解这些类是如何实现的以及如何对它们进行编E?br /> =================================================================================

Java 对象的状态有:

    * 已创?created)
    * 强可?strong reachable)
    * 不可?invisible)
    * 不可?unreachable)
    * 已收?collected)
    * l化(finalized)
    * 已回?deallocated) 

Java对象生命周期的状态{? {image:img=objectstatus.jpg|width=400} 引用对象
三种新的引用cd:

    * 软引?soft reference)
    * 弱引?weak reference)
    * qd?phantom reference) 

强可?Strong Reachable)
定义: ~An object is strong reachable if it can be reached by some thread without traversing any reference objects. A newly-created object is strong reachable by the thread that created it.~
处于强可辄态的对象, 在Q何情况下都不?x)被回收? 软可?Softly Reachable)
定义:~An object is softly reachable if it is not strongly reachable but can be reached by traversing a soft reference.~
含义?当对象不处于强可辄? q且可以通过软引用进行访问时, 卛_于Y可达状?
当程序申请内存的时? 垃圾攉器会(x)判断是否开始回收处于Y可达状态的对象, 如果军_回收某个对象, 那么垃圾攉器会(x)清除所有指向该对象的Y引用, 如果M处于其它软可辄态的对象可以通过强引用访问该对象, 那么指向q些对象的Y引用也会(x)被清除掉. 垃圾攉器在军_哪些软可辄态的对象被收集时, 采用"最久未被?原则, 或称"最不常使用"原则. 垃圾攉器也保证在OutOfMemeryError产生以前, 所有的软引用都被清?

    * 产生和用一个Y引用 

// createSoftReference sr = new SoftReference(new SomeObject());// getSomeObject o = (SomeObject) sf.get();// create in a reference queue;ReferenceQueue queue = new ReferenceQueue();SoftReference sr = new SoftReference(new SomeObject(), queue);

弱可?Weakly Reachable)
定义:~An Object is weakly reachable if it is neither strongly nor softly reachable but can be reached by traversing a weak reference.~
垃圾攉器会(x)一ơ清除所有弱引用. qd?Phantomly Reachable)
定义:~An object is phantomly reachable if it is neither strongly, softly, nor weakly reachable, it has been finalized, and some phantom reference refers to it.~
qd用不能直接创? 必须通过向引用队列等U的途径来创?

ReferenceQueue queue = new ReferenceQueue();PhantomReference pr = new PhantomReference (new SomeObject(), queue);

你不可能从引用再次得到对象, pr.get()永远q回null. 另外, 必须调用Reference.clear()手工清除qd? All About ReferenceObjects No InterWiki reference defined in properties for Wiki called '[http'!)]
Reference Objects No InterWiki reference defined in properties for Wiki called '[http'!)]
Reference Objects and Garbage Collection No InterWiki reference defined in properties for Wiki called '[http'!)]
\[Jike Thread\?Soft, Weak, and Phantom References|http://www-124.ibm.com/pipermail/jikesrvm-core/2003-May/000365.html]


Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1492810


竹子 2008-12-06 21:13 发表评论
]]>
Java虚拟机类装蝲Q原理、实C应用http://www.aygfsteel.com/zhuzi1987/archive/2008/08/21/223585.html竹子竹子Thu, 21 Aug 2008 12:45:00 GMThttp://www.aygfsteel.com/zhuzi1987/archive/2008/08/21/223585.htmlhttp://www.aygfsteel.com/zhuzi1987/comments/223585.htmlhttp://www.aygfsteel.com/zhuzi1987/archive/2008/08/21/223585.html#Feedback0http://www.aygfsteel.com/zhuzi1987/comments/commentRss/223585.htmlhttp://www.aygfsteel.com/zhuzi1987/services/trackbacks/223585.html一、引a

  Java虚拟?JVM)的类装蝲是指将包含在类文g中的字节码装载到JVM? q其成为JVM一部分的过E。JVM的类动态装载技术能够在q行时刻动态地加蝲或者替换系l的某些功能模块, 而不影响pȝ其他功能模块的正常运行。本文将分析JVM中的c装载系l,探讨JVM中类装蝲的原理、实C及应用?

  二、Java虚拟机的c装载实C应用

  2.1 装蝲q程?

  所谓装载就是寻找一个类或是一个接口的二进制Ş式ƈ用该二进制Ş式来构造代表这个类或是q个接口的class对象的过E,其中cL接口的名U是l定了的。当然名UC可以通过计算得到Q但是更常见的是通过搜烦源代码经q编译器~译后所得到的二q制形式来构造?

  在Java中,c装载器把一个类装入Java虚拟ZQ要l过三个步骤来完成:(x)装蝲、链接和初始化,其中链接又可以分成校验、准备和解析三步Q除了解析外Q其它步骤是严格按照序完成的,各个步骤的主要工作如下:(x)

  装蝲Q查扑֒导入cL接口的二q制数据Q?
  链接Q执行下面的校验、准备和解析步骤Q其中解析步骤是可以选择的;
  校验Q检查导入类或接口的二进制数据的正确性;
  准备Q给cȝ静态变量分配ƈ初始化存储空_
  解析Q将W号引用转成直接引用Q?
  初始化:(x)Ȁzȝ的静态变量的初始化Java代码和静态Java代码块?

  至于在类装蝲和虚拟机启动的过E中的具体细节和可能?x)抛出的错误Q请参看《Java虚拟范》以及《深入Java虚拟机》,它们在网l上面的资源地址是:(x)
  
http://java.sun.com/docs/books/vmspec/2nd-edition/html/Preface.doc.html
  
http://www.artima.com/insidejvm/ed2/index.html
  ׃本文的讨论重点不在此׃再多叙述?

  2.2 装蝲的实?

  JVM中类的装载是由ClassLoader和它的子cL实现?Java ClassLoader 是一个重要的Javaq行时系l组件。它负责在运行时查找和装入类文g的类?

  在Java中,ClassLoader是一个抽象类Q它在包java.lang?可以q样_只要了解了在ClassLoader中的一些重要的Ҏ(gu)Q再l合上面所介绍的JVM中类装蝲的具体的q程Q对动态装载类q项技术就有了一个比较大概的掌握Q这些重要的Ҏ(gu)包括以下几个:

  ①loadCassҎ(gu) loadClass(String name ,boolean resolve)其中name参数指定了JVM需要的cȝ名称,该名UC包表C法表示,如Java.lang.ObjectQresolve参数告诉Ҏ(gu)是否需要解析类Q在初始化类之前,应考虑c解析,q不是所有的c都需要解析,如果JVM只需要知道该cL否存在或扑և该类的超c?那么׃需要解析。这个方法是ClassLoader 的入口点?

  ②defineClassҎ(gu) q个Ҏ(gu)接受cL件的字节数组q把它{换成Class对象。字节数l可以是从本地文件系l或|络装入的数据。它把字节码分析成运行时数据l构、校验有效性等{?

  ③findSystemClassҎ(gu) findSystemClassҎ(gu)从本地文件系l装入文件。它在本地文件系l中LcL?如果存在,׃用defineClass字节数l{换成Class对象,以将该文件{换成cR当q行Java应用E序?q是JVM 正常装入cȝ~省机制?

  ④resolveClassҎ(gu) resolveClass(Class c)Ҏ(gu)解析装入的类,如果该类已经被解析过那么不做处理。当调用loadClassҎ(gu)?通过它的resolve 参数军_是否要进行解析?

  ⑤findLoadedClassҎ(gu) 当调用loadClassҎ(gu)装入cL,调用findLoadedClass Ҏ(gu)来查看ClassLoader是否已装入这个类,如果已装?那么q回Class对象,否则q回NULL。如果强行装载已存在的类,会(x)抛出链接错误?

  2.3 装蝲的应?

  一般来_我们使用虚拟机的c装载时需要承抽象类java.lang.ClassLoader,其中必须实现的方法是loadClass()Q对于这个方法需要实现如下操?(1) 认cȝ名称;(2) 查请求要装蝲的类是否已经被装?(3) 查请求加载的cL否是pȝc?(4) 试从类装蝲器的存储取所h的类;(5) 在虚拟机中定义所h的类;(6) 解析所h的类;(7) q回所h的类?

  所有的Java 虚拟机都包括一个内|的c装载器Q这个内|的cd装蝲器被UCؓ(f)根装载器(bootstrap ClassLoader)。根装蝲器的Ҏ(gu)之处是它只能够装载在设计时刻已知的类,因此虚拟机假定由根装载器所装蝲的类都是安全的、可信Q?可以不经q安全认证而直接运行。当应用E序需要加载ƈ不是设计时就知道的类?必须使用用户自定义的装蝲?user-defined ClassLoader)。下面我们D例说明它的应用?

  public abstract class MultiClassLoader extends ClassLoader{
  ...
  public synchronized Class loadClass(String s, boolean flag)
  throws ClassNotFoundException
  {
  /* 查类s是否已经在本地内?/
  Class class1 = (Class)classes.get(s);

  /* cs已经在本地内?/
  if(class1 != null) return class1;
  try/*用默认的ClassLoader 装入c?/ {
  class1 = super.findSystemClass(s);
  return class1;
  }
  catch(ClassNotFoundException _ex) {
  System.out.println(">> Not a system class.");
  }

  /* 取得cs的字节数l?/
  byte abyte0[] = loadClassBytes(s);
  if(abyte0 == null) throw new ClassNotFoundException();

  /* 类字节数组转换为类*/
  class1 = defineClass(null, abyte0, 0, abyte0.length);
  if(class1 == null) throw new ClassFormatError();
  if(flag) resolveClass(class1); /*解析c?/

  /* 新加蝲的类攑օ本地内存*/
  classes.put(s, class1);
  System.out.println(">> Returning newly loaded class.");

  /* q回已装载、解析的c?/
  return class1;
  }
  ...
  }
三、Java虚拟机的c装载原?

  前面我们已经知道Q一个Java应用E序使用两种cd的类装蝲器:(x)根装载器(bootstrap)和用户定义的装蝲?user-defined)。根装蝲器是Java虚拟机实现的一部分QD个例子来_如果一个Java虚拟机是在现在已l存在ƈ且正在被使用的操作系l的剙用CE序来实现的Q那么根装蝲器将是那些CE序的一部分。根装蝲器以某种默认的方式将c装入,包括那些Java API的类。在q行期间一个JavaE序能安装用戯己定义的c装载器。根装蝲器是虚拟机固有的一部分Q而用户定义的c装载器则不是,它是用Java语言写的Q被~译成class文g之后然后再被装入到虚拟机Qƈ像其它的M对象一样可以被实例化?Javac装载器的体pȝ构如下所C:(x)
  
  Java的类装蝲模型是一U代?delegation)模型。当JVM 要求c装载器CL(ClassLoader)装蝲一个类?CL首先这个类装蝲h转发l他的父装蝲器。只有当父装载器没有装蝲q无法装载这个类?CL才获得装载这个类的机?x)。这? 所有类装蝲器的代理关系构成了一U树(wi)状的关系。树(wi)的根是类的根装蝲?bootstrap ClassLoader) , 在JVM 中它?null"表示。除根装载器以外的类装蝲器有且仅有一个父装蝲器。在创徏一个装载器? 如果没有昑ּ地给出父装蝲? 那么JVM默认系l装载器为其父装载器。Java的基本类装蝲器代理结构如?所C:(x)
下面针对各种c装载器分别q行详细的说明?
?Bootstrap) 装蝲?该装载器没有父装载器Q它是JVM实现的一部分Q从sun.boot.class.path装蝲q行时库的核心代码?
扩展(Extension) 装蝲?l承的父装蝲器ؓ(f)根装载器Q不像根装蝲器可能与q行时的操作pȝ有关Q这个类装蝲器是用纯Java代码实现的,它从java.ext.dirs (扩展目录)中装载代码?
  pȝ(System or Application) 装蝲?装蝲器ؓ(f)扩展装蝲器,我们都知道在安装JDK的时候要讄环境变量(CLASSPATH )Q这个类装蝲器就是从java.class.path(CLASSPATH 环境变量)中装载代码的Q它也是用纯Java代码实现的,同时q是用户自定义类装蝲器的~省父装载器?

  应用程?Applet) 装蝲? 装蝲器ؓ(f)pȝ装蝲器,它从用户指定的网l上的特定目录装载小应用E序代码?

  在设计一个类装蝲器的时候,应该满以下两个条gQ?

  对于相同的类名,c装载器所q回的对象应该是同一个类对象

  如果c装载器CL1装载类C的请求{l类装蝲器CL2Q那么对于以下的cL接口,CL1和CL2应该q回同一个类对象:a)S为C的直接超c?b)S为C的直接超接口;c)S为C的成员变量的cd;d)S为C的成员方法或构徏器的参数cd;e)S为C的成员方法的q回cd?
  每个已经装蝲到JVM中的c都隐式含有装蝲它的c装载器的信息。类Ҏ(gu)getClassLoader 可以得到装蝲q个cȝc装载器。一个类装蝲器认识的cd括它的父装蝲器认识的cd它自p载的c,可见c装载器认识的类是它自己装蝲的类的超集。注意我们可以得到类装蝲器的有关的信息,但是已经装蝲到JVM中的cL不能更改它的c装载器的?

  Java中的cȝ装蝲q程也就是代理装载的q程。比?Web览器中的JVM需要装载一个小应用E序TestApplet。JVM调用应用程序装载器ACL(Applet ClassLoader)来完成装载。ACL首先h它的父装载器, 即系l装载器装蝲TestApplet是否装蝲了这个类, ׃TestApplet不在pȝ装蝲器的装蝲路径? 所以系l装载器没有扑ֈq个c? 也就没有装蝲成功。接着ACL自己装蝲TestApplet。ACL通过|络成功地找CTestApplet.class 文gq将它导入到了JVM中。在装蝲q程? JVM发现TestAppet是从类java.applet.Appletl承的。所以JVM再次调用ACL来装载j(lu)ava.applet.AppletcRACL又再ơ按上面的顺序装载Appletc? l果ACL发现他的父装载器已经装蝲了这个类, 所以ACLq接将q个已经装蝲的类q回l了JVM , 完成了Appletcȝ装蝲。接下来,Appletcȝ类也一样处理。最? TestApplet及所有有关的c都装蝲CJVM中?

  四、结?

  cȝ动态装载机制是JVM的一Ҏ(gu)心技? 也是Ҏ(gu)被忽视而引起很多误解的地方。本文介l了JVM中类装蝲的原理、实C及应用,其分析了ClassLoader的结构、用途以及如何利用自定义的ClassLoader装蝲q执行Javac,希望能读者对JVM中的c装载有一个比较深入的理解



竹子 2008-08-21 20:45 发表评论
]]>
转蝲"TOMCAT中文解决"http://www.aygfsteel.com/zhuzi1987/archive/2008/08/16/222466.html竹子竹子Sat, 16 Aug 2008 10:29:00 GMThttp://www.aygfsteel.com/zhuzi1987/archive/2008/08/16/222466.htmlhttp://www.aygfsteel.com/zhuzi1987/comments/222466.htmlhttp://www.aygfsteel.com/zhuzi1987/archive/2008/08/16/222466.html#Feedback0http://www.aygfsteel.com/zhuzi1987/comments/commentRss/222466.htmlhttp://www.aygfsteel.com/zhuzi1987/services/trackbacks/222466.html-------------------
Tomcat 5中文问题
author:kiss__sky@163.com
-------------------

问题描述Q?br />
1 表单提交的数据,用request.getParameter(“xxx”)q回的字W串Zؕ码或者?Q?br /> 2 直接通过url如http://localhost/a.jsp?name=中国Q这L(fng)geth在服务端用request. getParameter(“name”)时返回的是ؕ码;按tomcat4的做法设|Filter也没有用或者用request.setCharacterEncoding("GBK");也不用

原因Q?br /> 1 tomcat的j2ee实现对表单提交即post方式提示时处理参数采用缺省的iso-8859-1来处?br /> 2 tomcat对get方式提交的请求对query-string 处理旉用了和postҎ(gu)不一L(fng)处理方式?与tomcat4不一?所以设|setCharacterEncoding(“gbk”))不v作用?br />

解决办法Q?br />
首先所有的jsp文g都加?


1 实现一个Filter.讄处理字符集ؓ(f)GBK?在tomcat的webapps/servlet-examples目录有一个完整的例子。请参考web.xml和SetCharacterEncodingFilter的配|?

1)只要?TOMCAT安装目录%/ webapps\servlets-examples\WEB-INF\classes\filters\SetCharacterEncodingFilter.class文g拷到你的webapp目录/filters下,如果没有filters目录Q就创徏一个?br /> 2)在你的web.xml里加入如下几行:(x)


<filter>
<filter-name>Set Character Encoding</filter-name>
<filter-class>filters.SetCharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>GBK</param-value>
</init-param>
</filter>

<filter-mapping>
<filter-name>Set Character Encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>


3)完成.

2 get方式的解军_?br /> 1) 打开tomcat的server.xml文gQ找?connector>区块Q加入如下一行:(x)
URIEncoding=”GBK”
完整的应如下Q?br />

<Connector
port="80" maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
enableLookups="false" redirectPort="8443" acceptCount="100"
debug="0" connectionTimeout="20000"
disableUploadTimeout="true"
URIEncoding="GBK"
/>



2)重启tomcat,一切OK?br />
执行如下jsp页试是否成功


<%@ page contentType="text/html;charset=gb2312"%>
<%@ page import="java.util.*"%>

<%

String q=request.getParameter("q");
q = q == null? "没有? : q;

%>


<HTML>
<HEAD><TITLE>新闻列表昄</TITLE>
<META http-equiv=Content-Type content="text/html; charset=gb2312">
<META http-equiv=pragma content=no-cache>
<body>
你提交了Q?br /> <%=q%>

<br>
<form action="tcnchar.jsp" method="post">
输入中文:<input type="text" name="q"><input type="submit" value="定">
<br>
<a href="tcnchar.jsp?q=中国">通过get方式提交</a>

</form>
</BODY></HTML>


试l果如果你输入文本框或者点链都会(x)昄:你提交了”中国”,说明成功!!!!!



特别感谢下面q篇帖子Q帮我解决了中文问题.最后祝大家好运!!!
参考网址Q?br />
http://www.javaworld.com.tw/jute/post/view?bid=9&id=44042&sty=1&tpg=1&age=0



竹子 2008-08-16 18:29 发表评论
]]>
Java实现MD5加密http://www.aygfsteel.com/zhuzi1987/archive/2008/08/12/221579.html竹子竹子Tue, 12 Aug 2008 14:55:00 GMThttp://www.aygfsteel.com/zhuzi1987/archive/2008/08/12/221579.htmlhttp://www.aygfsteel.com/zhuzi1987/comments/221579.htmlhttp://www.aygfsteel.com/zhuzi1987/archive/2008/08/12/221579.html#Feedback0http://www.aygfsteel.com/zhuzi1987/comments/commentRss/221579.htmlhttp://www.aygfsteel.com/zhuzi1987/services/trackbacks/221579.htmlimport java.security.MessageDigest;

/**
 * MD5加密c?br />  * @author zhang
 */
public class MD5Encoding
{
 /**
  *
  *
  */
 private MD5Encoding()
 {
 }

 /**
  * 加密法MD5
  *
  * @param text 明文
  * @return String 密文
  */
 public final static String encoding(String text)
 {
  char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
  String encodingStr = null;
  
  try
  {
   byte[] strTemp = text.getBytes();
   MessageDigest mdTemp = MessageDigest.getInstance("MD5");
   mdTemp.update(strTemp);
   byte[] md = mdTemp.digest();
   int j = md.length;
   char str[] = new char[j * 2];
   int k = 0;
   for (int i = 0; i < j; i++)
   {
    byte byte0 = md[i];
    str[k++] = hexDigits[byte0 >>> 4 & 0xf];
    str[k++] = hexDigits[byte0 & 0xf];
   }
   
   encodingStr = new String(str);
  }
  catch (Exception e)
  {
  }
  
  return encodingStr;
 }
 public static void main(String[] areg)
 {
  MD5Encoding md5 = new MD5Encoding();
  md5.encoding("admin");
 }
}



竹子 2008-08-12 22:55 发表评论
]]>
Tomcat内存优化与连接数http://www.aygfsteel.com/zhuzi1987/archive/2008/08/12/221571.html竹子竹子Tue, 12 Aug 2008 14:46:00 GMThttp://www.aygfsteel.com/zhuzi1987/archive/2008/08/12/221571.htmlhttp://www.aygfsteel.com/zhuzi1987/comments/221571.htmlhttp://www.aygfsteel.com/zhuzi1987/archive/2008/08/12/221571.html#Feedback0http://www.aygfsteel.com/zhuzi1987/comments/commentRss/221571.htmlhttp://www.aygfsteel.com/zhuzi1987/services/trackbacks/221571.html1, Tomcat内存参数配置

          如果是Win与Linuxpȝ启动Tomcat服务?需要在tomcat/bin/catalina.sh?tomcat/bin/catalina.bat两个文g:在两个文仉面加?

SET  CATALINA_OPTS= -Xms64m -Xmx128m

2, Tomcatq接数配|?/font>

       配置Tomcatq接?需要在Server.xml文g里面加如:

      maxThreads="150"              表示最多同时处?50个连? 
      minSpareThreads="25"      表示即没有Z用也开q么多空U程{待  
      maxSpareThreads="75"     表示如果最多可以空75个线E,例如某时L80问,之后没有问了Q则tomcat不会(x)保留80个空U程Q而是关闭5个空的? 
   
  acceptCount="100"   当同时连接的人数辑ֈmaxThreadsӞq可以接收排队的q接Q超q这个连接的则直接返回拒l连接?/font>

            

             connectionTimeout="20000" maxThreads="150"

               minSpareThreads="25" 

              maxSpareThreads="75"

             enableLookups="false"

             acceptCount="100" debug="0"

             disableUploadTimeout="true"
            redirectPort="8443" URIEncoding="UTF-8"/>

URIEncoding="UTF-8"  是设定JSP~码格式.



竹子 2008-08-12 22:46 发表评论
]]>
【{】浅谈DAO模式http://www.aygfsteel.com/zhuzi1987/archive/2008/07/20/216146.html竹子竹子Sun, 20 Jul 2008 01:41:00 GMThttp://www.aygfsteel.com/zhuzi1987/archive/2008/07/20/216146.htmlhttp://www.aygfsteel.com/zhuzi1987/comments/216146.htmlhttp://www.aygfsteel.com/zhuzi1987/archive/2008/07/20/216146.html#Feedback0http://www.aygfsteel.com/zhuzi1987/comments/commentRss/216146.htmlhttp://www.aygfsteel.com/zhuzi1987/services/trackbacks/216146.htmlDAO模式在现在的开发中应用非常的广泛,它可以帮助我们实现持久化逻辑和业务逻辑的分,同时实现对多U持久化实现的支持。当然现在你可以通过 hibernate来实现对多种持久化的支持Q由于新的技术新的方式的出现QDAO也相应的做出了一些调_比如泛型DAOQ在SpringSide中有很还得例子可以参考这斚w的实现?/span>

q里聊下传统意义上的DAO模式Q在阎宏的JAVA与模式书中有详细的介l)Q需要注意的几个斚wQ?/span>

1、不要DAO中出C务逻辑

DAO只需x持久化部分,可以通过Facade来控制事务的边界Q从而提高DAO的复用性,在不同的事务{略中应?/span>

2、不要过多的?DAO层捕捉异?/span>

在很多的开发中Q会(x)喜欢使用Checked ExceptionQ抛到servcie层、再到action层,其实在DAO中发生的异常常常是不可恢复的Q比如DB的连接问题)Q所以应该选择 RuntimeExceptionQ我们所需要的只是log的记录ƈ通知理员,q过全局的异常处理画面告之?/span>

暂时q些Q由于ORM的懒加蝲技术,在DAO中可能会(x)有些调整Qؓ(f)了增加DAO的复用性,q方面的技术也应该剥离出来Q不q暂时还没这么处理过Q所以无法ȝQ希望有q方面经验的人提供一?/span>



竹子 2008-07-20 09:41 发表评论
]]>
[转]单元试(提升?http://www.aygfsteel.com/zhuzi1987/archive/2008/07/20/216143.html竹子竹子Sun, 20 Jul 2008 01:32:00 GMThttp://www.aygfsteel.com/zhuzi1987/archive/2008/07/20/216143.htmlhttp://www.aygfsteel.com/zhuzi1987/comments/216143.htmlhttp://www.aygfsteel.com/zhuzi1987/archive/2008/07/20/216143.html#Feedback0http://www.aygfsteel.com/zhuzi1987/comments/commentRss/216143.htmlhttp://www.aygfsteel.com/zhuzi1987/services/trackbacks/216143.html本节是单元测试的W三。我以ؓ(f)q是重中之重的一章。单元测试的关键在于代码要可。可才能测。要做好单元试Q就必须在代码的可测性方面努力,在设计、重构方面用心。本主要分享我在如何写出可性代码方面的理解Q与大家共勉Q?/span>

单元试(提升?/span>)

------~写可测试性代?/span>

一、可试性设?/span>

1.       接口依赖

q是最重要的一点,因ؓ(f)q可以得我们很Ҏ(gu)的针对一个接口实?/span>Mock对象Q模?/span>/替换实际对象?x)变的很?gu)。达C一个被对象处于一个孤立环境的试要求?/span>


q里Q?/span>ClassA依赖?/span>ClassB的具体实玎ͼTestCaseҎ(gu)无法独立?/span>ClassB?/span>ClassAq行独立试?/span>


因此Q我们将ClassA改ؓ(f)依赖于接?/span>B_Inf。这P可以很容易的实现一?/span>Mock_B替换ClassB?/span>ClassAq行孤立试?/span>

2.       依赖注入

一个方法对外部cȝ依赖Q应该是可注入的。即可以通过构造方法?/span>get/setҎ(gu)的方式在外部依赖关pL入。事实上Q这也ؓ(f)我们在测试用例中替换待测cȝ依赖对象提供了机?x)。不应该出现在方法内部新建对象用的情况?/span>

3.       降低耦合?/span>

待测cd与最的c耦合Q即最交互原则。特别是要减与那些M具体环境?yu)׃能运行的cȝ耦合。可以通过门面模式{对外部调用q行隔离?/span>

5Q?/span>AOP

面向切面~程。给我们提供的启C是Q将真正需要测的逻辑分离出来。摆脱那些无意义且简单重复的代码Ҏ(gu)试的q扰?/span>

6.    明确的契U?/span>

Ҏ(gu)一定要有明清晰的输入/输出。徏议在Ҏ(gu)的注释描qCQ分三段“描述”“前置条g”“后置条g”?/span>

二、可试性重?/span>

1.         可恶的静态方?/span>

在我们的代码中有大量的调用静态方法的地方。用h我们很爽Q但q对试来说却是N。因为我们除了通过改变代码创徏stub来改变这些方法的行ؓ(f)外,我们没有M途径。更要命的是Q写q些stub的代价非常的巨大Q常o人望而却步?/span>

解决Ҏ(gu)Q?/span>

方法内部的q些调用提取?/span>protectedҎ(gu)。在外部创徏待测cȝ子类Q重写该protectedҎ(gu)?/span>

最?jng)_践:(x)


q些静态方法由单态类提供Q单态类由工厂方法获取,具体cM用这些单态类的接口?/span>

我们在方法中通过接口使用对外部模块的调用。一斚wQ隔M外部模块改变Ҏ(gu)们生的冲击Q另一斚wQ也使我们?/span>Mock替换实际的外部组Ӟ创徏孤立试环境成ؓ(f)可能?/span>

2.         待测cL法中Q?/span>new出另一个对象ƈ使用其方?/span>

两种Ҏ(gu)Q?/span>1Q将new 出对象的q程装?/span>protectedҎ(gu)。同重构1?/span>2)该对象提取成类属性,即由使用关系变成兌关系?/span>

3.         分离不可?/span>/不必代?/span>

在不影响的情况下Q将不可部分分d一些不需要测的简单方法中厅R或者将可测的部分提取到一个私有方法中厅R然后针对这个私有方法进行测试?/span>

通常q种做法使用范围有限Q但有些时候还是值的一试?/span>

4.         单一职责

职责太多Q肯定不好测。针对于q一?#8220;不好的Ҏ(gu)必然不好?#8221;。当Ҏ(gu)q大Q承担责任过多时Q拆分是应该的?/span>

 

5.         为类提供一个空构造方法?/span>

我们的各个测试方法都依赖于对象处于一个特定的状态,满一定的前置条g。而要对象置为我们希望的状态,我们必须首先拥有一个对象。然而,很多时候,在一个隔ȝ单元试环境下,构造函数由于各U原因不能正常初始化?/span>

此时Q可以ؓ(f)cL供一个的I的构造方法。在外部构造一?/span>“?/span>”对象Q而后Ҏ(gu)前置条g各个属性设|成需要的Mock对象?/span>

-----------------------------------------------------------------------------------------------------------------------------------------------------------

事实上,要想写出h可测性的代码Q最佳的办法是试驱动开发。先写测试代码把功能体现出来Q再写功能代码让试通过。这样写出的代码显而易见会(x)更具有测试性?/span>


原地址:http://www.aygfsteel.com/wukaichun600/archive/2008/07/18/214125.html



竹子 2008-07-20 09:32 发表评论
]]>
[转]单元试(技能篇)http://www.aygfsteel.com/zhuzi1987/archive/2008/07/20/216142.html竹子竹子Sun, 20 Jul 2008 01:31:00 GMThttp://www.aygfsteel.com/zhuzi1987/archive/2008/07/20/216142.htmlhttp://www.aygfsteel.com/zhuzi1987/comments/216142.htmlhttp://www.aygfsteel.com/zhuzi1987/archive/2008/07/20/216142.html#Feedback0http://www.aygfsteel.com/zhuzi1987/comments/commentRss/216142.htmlhttp://www.aygfsteel.com/zhuzi1987/services/trackbacks/216142.html本节是单元测试系列的W二。重点讲解如何用Mock/Stub和依赖注入技术进行单元测试。关于工具JUnit{则不做累赘介绍?希望通过本章能够帮助大家开始单元测试的有益实践Q与大家共勉Q?/span>

单元试Q技能篇Q?/span>

一?/span>Stub技?/span>

q是最为古老的一U测试技能。通过cdơ上的替换实C对待环境的模拟?/span>

实现的时候有两种途径Q?/span>

1、重写实际类Q在试Ӟ先于实际cd载,卌盖。如Q我们在unittest/stub文g夹下针对于每一个重写类都有相同的包l构和类名:(x)


在类路径中优先加载:(x)


2、在实际代码中添加判断。比如,如果当前是测试环?/span>if(isUT)执行XX操作Q截断真正需要做的事?/span>

    publicvoid sendCommand(int cmdCode)

    {

       if(isUT())

       {

           //...

       }

       else

       {

           //...

       }

    }

Stub技术的问题在于我们在重写q些cȝ时候,不仅仅要x接口Q还要关注其内部逻辑。如果你只是单的q回一个固定的响应Q会(x)很简单。但是对于每一ơ运行需要根据不同的输入q回不同的输出时Ҏ(gu)内部的处理就?x)复杂的多?/span>

׃实现的难度,所以,使用时就要注意:(x)有高价倹{重用度高、数量少。这是_重写一个类Q就可以有一大批cd以用?/span>

二?/span>Mock技?/span>

Mock是目前单元测试中最常用的。用来在对象层次上实现细cd替换十分方便?/span>

当我们在试中,需要其它类/接口的一个方法时Q我们可?span style="color: blue;">通过l承/实现其一个子cd象来替换实际对象。在Mock子类中将需要的Ҏ(gu)直接q回需要的l果p了?/span>

    privateclass Mock_QueryCtrl extends QueryCtrl

    {

       public List queryNEList()

       {

           List neList = new ArrayList();

           //直接填充q返回你需要的数据...

           return neList;

       }

    }

同样Q我们也可以通过试待测cȝ子类来测试待类。这对于被测Ҏ(gu)使用了自w类的方法时很适用?/span>

三、依赖注?/span>

单元试的一个关键就是替换。类层次上的替换Q通过在类路径中提前加载就可以实现。而在对象层次上,java的反机制提供了很好的帮助?/span>

1Q?/span>.获取/注入U有属?/span>

2Q?/span>.执行U有Ҏ(gu)

附:(x)注入U有属性的实现Q?/span>

    publicvoid setFieldObject(Object instance, String fieldName, Object value)

           throws IllegalArgumentException, IllegalAccessException,

           NoSuchFieldException {

       Field field = null;

       Class c = instance.getClass();

       do {

           try

           {

              field = c.getDeclaredField(fieldName);

           } catch (SecurityException e)

           {

              e.printStackTrace();

           } catch (NoSuchFieldException e)

           {

              c = c.getSuperclass();

           }

       }

       while (c.getName() != "java.lang.Object" && field == null);

       if (field != null)

       {

           field.setAccessible(true);

           field.set(instance, value);

       }

       else

       {

           thrownew NoSuchFieldException(fieldName);

       }

    }

注:(x)q是一个简单实玎ͼ实际中需要优化?/span>

四、实例:(x)

下例演示了如何测试类NEListTable?/span>ShowNETable()Ҏ(gu)。其中注意的是,Ҏ(gu)中调用了c?/span>QueryCtrl?/span>queryNEList()Ҏ(gu)?/span>

待测c:(x)

publicclass NEListTable

{

    QueryCtrl ctrl = null;

   

    publicvoid ShowNETable()

    {

       List neList = ctrl.queryNEList();

      

       for(int i = 0;i<neList.size();i++)

       {

           //?/span>neList转换D

       }

      

       //昄表格...

    }

}

publicclass QueryCtrl {

    public List queryNEList()

{

       returnnull;

    }

}

试c:(x)

public class TestNEListTable extends TestCase

{

    private NEListTable table = null;

    private TestHelper helper = null;

    public void testShowNETable()

    {

       Mock_QueryCtrl ctrl = new Mock_QueryCtrl();

       helper.setObjectField(table,"ctrl",ctrl);//?/span>Mock对象注入table

       table.ShowNETable();

       assertTrue(table.getRowCount()>0);

    }

   

    private class Mock_QueryCtrl extends QueryCtrl

    {

       public List queryNEList()

       {

           List neList = new ArrayList();

           //q回你需要的数据...

           return neList;

       }

    }

}



原地址:http://www.aygfsteel.com/wukaichun600/archive/2008/07/10/213790.html



竹子 2008-07-20 09:31 发表评论
]]>
[转]单元试(基础?http://www.aygfsteel.com/zhuzi1987/archive/2008/07/20/216141.html竹子竹子Sun, 20 Jul 2008 01:29:00 GMThttp://www.aygfsteel.com/zhuzi1987/archive/2008/07/20/216141.htmlhttp://www.aygfsteel.com/zhuzi1987/comments/216141.htmlhttp://www.aygfsteel.com/zhuzi1987/archive/2008/07/20/216141.html#Feedback0http://www.aygfsteel.com/zhuzi1987/comments/commentRss/216141.htmlhttp://www.aygfsteel.com/zhuzi1987/services/trackbacks/216141.htmlq篇文章的主旨是在正式进行单元测试之前帮助大家厘清一些概c了解什么是单元? 试,可以做什么,有哪些指导原则。做了又有什么好处,它又存在什么样的局限性。最后重点讲了现在做单元试的难炏V事实上q是M单元试都会(x)面(f)的一? 问题。在q里分n我的观点Q与大家共勉Q?/span>

单元试(基础?/span>)

一?/span>什么是UT

UT的是方法,验的是一个类对外界的承诺。因此,大多数情况下Q我们测的应该是公共Ҏ(gu)Q除非不得已才对U有Ҏ(gu)q行试?/span>

Ҏ(gu)是程序设计的最单位?/span>UT的局限也体现在这里,它ƈ没有针对cM间的交互做检验。所以,不能指望单元试做完了,没有问题了。在q个斚w的欠~,我们可以通过自动化的功能/lg试来完成。这也是开发者测试的一部分?/span>

二?/span>UT的Q?/span>

1.    早的发现问?/span>

说白了,是不要让问题流?/span>厅R让我们的缺L(fng)降低Q把我们的品做的漂?/span>?/span>另一斚wQ一些细cd的问题在q里也确实更Ҏ(gu)发现Q同时也行更大粒度的试做好集成准备?/span>

2.    ~织一层保护网

l新的代码徏立有效的保护?/span> 保证对代码每一份改动,都不?x)对现有pȝ造成伤害。避免了引入问题?/span>

3.写出优雅的代?/span>

~写单元试的过E,实质是用我们自׃码的q程。我们成了第一个真正意义上的体验者。在q个q程中,我们Z使代码易用会(x)q行不断的重构。最l的交付代码必然?x)更优雅?/span>

4.    建立E序员的自信

我们?fn)惯于两g抚wQ不三七二十一把代码写完了?/span>Code阶段l束Q然后不断的调试Q修修补补跑hp?/span>TR4。没人敢_他代码一写完了,p跑v来。这U做法是很没人性的Q系l搞挂几ơ后心里发虚,一点底气都没有?/span>但是Q?/span>q是我们的职业,我们为着自己的荣耀而战。在M时候,都需要信心满盈?/span>

三?/span>UT的基本原?/span>

1.一个类、一个方法、一条\?/span>

我们一ơ只一个类? 一个方法。刚开始做单元试的时候,很多Z(x)自然而然的做成了功能试。因为,前一部分执行的结果恰好ؓ(f)后一部分准备好了输入。而另一斚wQ连l的执行q? E组成了一个明的场景Q让具体的功能变得完整可见,q正是我们期待的Q让我们变得有信心。那Z么不其自然呢?

原因在于Q?/span>

1Q、单元测试要保证一定的微粒度。从单元试到功能测试,q之间的_度?x)越来越大,往后,我们?x)越的xl节。如果直接蟩跃到功能试上,?x)让我们遗漏掉一些问题,在以后的_粒度测试中Q它们会(x)转变为很N现或者不可重现的致命问题?/span>

2Q、上q场景之所? ?x)出玎ͼ是因为先写代码后写测试导致的。相当于代码已经集成Q具备了做功能测试的一定条件。这个时候让再走回头路做单元试Q当然不如直接就做功能测试来 的顺当。所以,应该一个测试、一个方法,一个方法一个测试,q样不断的一步一步的循环q代集成来的好?/span>

另一斚wQؓ(f)了将一个方法的多个不同的执行\径分开Q我?span style="color: blue;">必须保证一ơ只一个方法的一个\径?/span>q样Q前|条件和后置条g׃(x)很明,Ҏ(gu)准备试环境?/span>

2.重构以便于测?/span>

面对着一个方法,你感C{莫展。ƈ不是你的错,而是因ؓ(f)q个Ҏ(gu)很烂。测一个方法就是在使用q个Ҏ(gu)Q你自己都这h奈,来真正使用的h岂不是要骂娘Q?/span>雁过留声Qhq留?/span>。这个时候,重构一下很值得?/span>

3.保证试Ҏ(gu)z?/span>

如果q测试方法都很复杂,N我们q要再写试用例来保证它的正执行不成?q样岂不是麻烦大了!所以,试Ҏ(gu)一定要写的可能的单,写到你认为白痴都能看懂的E度?/span>

四、如何才能做UT

1.代码要首先可,然后才能?/span>

首先要遵?/span>契约式设计。类的每一个方法都应该对外承担了一份契U,有明的前置条g和后|条件?/span> 当你对这个方法进行测试之前必L楚明白这两个条g。一个有效的Ҏ(gu)一定是做了什么事的。一定会(x)产生一定的影响Q我们可以通过对外围环境的改变来检方法生的作用是否如预?/span>(例如,获取某一对象的属性进行检?/span>)?/span>

其次是,?/span>Ce和单一责Q原则。一个方法对外的依赖应该单一Q不应该取决于很多的外部环境。因Z同的外部环境多Q组合项p多,要测的先x件就多。而一个方法对外部环境的媄响太多,则意味着职责不单一Q对于输难测?/span>

曄听有刎ͼq些道理Q你懂了懂Q不懂就不懂Q说了没用。但我认为,如果你还以ؓ(f)q些只是大道理,如果你还惛_它有点切w的感受Q做单元试是一个很好的途径?/span>

2.信Q你该信Q的?/span>

对于已经E_的部分,cM于第三方包,q_部分Q其x遗留pȝ中已l证明是可靠的部分,都可以信仅R这些是我们用例代码依赖的部分,是我们用来检验其它待部分的基石。如果什么都要测Q就?x)变成什么都不了?/span>

3.    单元试要尽量少的增加开发h员的负担?/span>

一斚wQ我们实在被问题单压抑的太久了。所以,从全局上来看待q个问题Q如果可以确实的减少后期的维护压力,Ҏ(gu)们自w而言当然是有益的。所谓增加的负担Q不q是提早了结了一些痛苦?/span>

另一斚wQ?/span>单元试必须自动?/span> Q必?/span>单,?c)化?/span>q是我们要努力的目标?/span>

4.调试的旉用来写单元测?/span>

没有做过自动化单元测试的人永q也不能体会(x)其给E序员带来的自信和好处。如果你q在调试Q不如顺手加个测试。以后,保证同样的问题不?x)从你的眼皮下溜走?/span>

5.    现在的单元测试难在哪里?

难以打桩。因为我们对其它模块的关联是q样的?/span>


q就是麻烦的所在,兌太多。如果我们要,我们p打桩。但是,

1.    望而生畏,太多?/span>

2.    无法下手Q都是直接对象依赖,而不是接口依赖?/span>

所以,你让我来这L(fng)代码Q我是不?x)干的?/span>

因ؓ(f)Q我希望的是q样的:(x)


但是Q我们现在的代码Ơ债太多了。没有条件和能力再回dq些代码q行单元试。而且Q这些功能经q这么多q的l护Q大多已E_。做的性h(hun)比也不高,不够实惠。所以,不必要做?/span>

但在新功能开发过E中Q这些老代码依旧会(x)如恶梦一L(fng)~着我们。让写单元测试过E中常常面(f)着举步l艰的境地。我们不得不在让代码变得可测与对代码的R入性测试之间进行抉择?/span>


原地址:http://www.aygfsteel.com/wukaichun600/archive/2008/06/10/206999.html



竹子 2008-07-20 09:29 发表评论
]]>
վ֩ģ壺 | ÷| ʤ| ǿ| ˳| | ƽң| | | | | | | | | | ƽ| | | | | Ϫ| | ƺ| ˳| | | | | | | | | Ϫ| ̨| | | | Ͻ| ͨ| |