﻿<?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</title><link>http://www.blogjava.net/hao446tian/category/48039.html</link><description /><language>zh-cn</language><lastBuildDate>Fri, 09 Aug 2013 08:54:04 GMT</lastBuildDate><pubDate>Fri, 09 Aug 2013 08:54:04 GMT</pubDate><ttl>60</ttl><item><title>SIFT特征匹配算法简介【转载】</title><link>http://www.blogjava.net/hao446tian/archive/2013/08/09/402635.html</link><dc:creator>昊天</dc:creator><author>昊天</author><pubDate>Fri, 09 Aug 2013 08:33:00 GMT</pubDate><guid>http://www.blogjava.net/hao446tian/archive/2013/08/09/402635.html</guid><wfw:comment>http://www.blogjava.net/hao446tian/comments/402635.html</wfw:comment><comments>http://www.blogjava.net/hao446tian/archive/2013/08/09/402635.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hao446tian/comments/commentRss/402635.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hao446tian/services/trackbacks/402635.html</trackback:ping><description><![CDATA[<p style="margin: 0px 0px 10px; text-indent: 2em; font-size: 13px; padding: 0px; border: 0px; background-color: #ffffff; font-family: 微软雅黑, Verdana, Tahoma, 'Lucida Grande', Arial, sans-serif; line-height: 24px; "><span style="font-family: Arial; ">鉴于自己的毕设是与视频检索有关，而在图像和视频检索领域中，D.Lowe和他的&#8220;亲儿子&#8221;&#8212;&#8212;SIFT( Scale Invariant Feature Transform )算法是不能错过的经典论题，我在之前闲逛过的一个技术博客站点中找到了介绍这一经典算法基本概念的文章，原文地址：http://www.dakaren.com/index.php/archives/639.htm &nbsp;</span><span style="text-indent: 2em; ">&nbsp;</span></p><p style="margin: 0px 0px 10px; text-indent: 2em; font-size: 13px; padding: 0px; border: 0px; background-color: #ffffff; font-family: 微软雅黑, Verdana, Tahoma, 'Lucida Grande', Arial, sans-serif; line-height: 24px; "><span style="font-family: Arial; ">1、SIFT算法基本概念</span></p><p style="margin: 0px 0px 10px; text-indent: 2em; font-size: 13px; padding: 0px; border: 0px; background-color: #ffffff; font-family: 微软雅黑, Verdana, Tahoma, 'Lucida Grande', Arial, sans-serif; line-height: 24px; "><span style="font-family: Arial; ">Sift是David Lowe于1999年提出的局部特征描述子，可以处理两幅图像之间发生平移、旋转、仿射变换情况下的匹配问题，具有良好的不变性和很强的匹配能力。SIFT算法是一种提取局部特征的算法，也是一种模式识别技术，其基本思想是在尺度空间寻找极值点，提取位置，尺度，旋转不变量，它主要包括两个阶段，一个是Sift特征的生成，即从多幅图像中提取对尺度缩放、旋转、亮度变化无关的特征向量；第二阶段是Sift特征向量的匹配。Sift及其扩展算法已被证实在同类描述子中具有最强的健壮性，目前是国内外研究的热点。</span></p><p style="margin: 0px 0px 10px; text-indent: 2em; font-size: 13px; padding: 0px; border: 0px; background-color: #ffffff; font-family: 微软雅黑, Verdana, Tahoma, 'Lucida Grande', Arial, sans-serif; line-height: 24px; "><span style="font-family: Arial; ">2、SIFT算法的主要特点：</span></p><p style="margin: 0px 0px 10px; text-indent: 2em; font-size: 13px; padding: 0px; border: 0px; background-color: #ffffff; font-family: 微软雅黑, Verdana, Tahoma, 'Lucida Grande', Arial, sans-serif; line-height: 24px; "><span style="font-family: Arial; ">a) SIFT特征是图像的局部特征，其对旋转、尺度缩放、亮度变化保持不变 性，对视角变化、仿射变换、噪声也保持一定程度的稳定性，而对物体运动、遮 挡、噪声等因素也保持较好的可匹配性，从而可以实现差异较大的两幅图像之间 特征的匹配。</span></p><p style="margin: 0px 0px 10px; text-indent: 2em; font-size: 13px; padding: 0px; border: 0px; background-color: #ffffff; font-family: 微软雅黑, Verdana, Tahoma, 'Lucida Grande', Arial, sans-serif; line-height: 24px; "><span style="font-family: Arial; ">b) 独特性(Distinctiveness)好，信息量丰富，适用于在海量特征数据库中进行 快速、准确的匹配，比原有的harris点匹配方式具有更高的匹配准确度。</span></p><p style="margin: 0px 0px 10px; text-indent: 2em; font-size: 13px; padding: 0px; border: 0px; background-color: #ffffff; font-family: 微软雅黑, Verdana, Tahoma, 'Lucida Grande', Arial, sans-serif; line-height: 24px; "><span style="font-family: Arial; ">c) 多量性，即使少数的几个物体也可以产生大量SIFT特征向量。</span></p><p style="margin: 0px 0px 10px; text-indent: 2em; font-size: 13px; padding: 0px; border: 0px; background-color: #ffffff; font-family: 微软雅黑, Verdana, Tahoma, 'Lucida Grande', Arial, sans-serif; line-height: 24px; "><span style="font-family: Arial; ">d) 高速性，经优化的SIFT匹配算法甚至可以达到实时的要求。</span></p><p style="margin: 0px 0px 10px; text-indent: 2em; font-size: 13px; padding: 0px; border: 0px; background-color: #ffffff; font-family: 微软雅黑, Verdana, Tahoma, 'Lucida Grande', Arial, sans-serif; line-height: 24px; "><span style="font-family: Arial; ">e) 可扩展性，可以很方便的与其他形式的特征向量进行联合。</span></p><p style="margin: 0px 0px 10px; text-indent: 2em; font-size: 13px; padding: 0px; border: 0px; background-color: #ffffff; font-family: 微软雅黑, Verdana, Tahoma, 'Lucida Grande', Arial, sans-serif; line-height: 24px; "><span style="font-family: Arial; ">SIFT算法基于图像特征尺度选择的思想，建立图像的多尺度空间，在不同尺度下检测到同一个特征点，确定特征点位置的同时确定其所在尺度，以达到尺度抗缩放的目的。剔除一些对比度较低的点以及边缘响应点，并提取旋转不变特征描述符以达到抗仿射变换的目的。</span></p><p style="margin: 0px 0px 10px; text-indent: 2em; font-size: 13px; padding: 0px; border: 0px; background-color: #ffffff; font-family: 微软雅黑, Verdana, Tahoma, 'Lucida Grande', Arial, sans-serif; line-height: 24px; "><span style="font-family: Arial; ">3、SIFT算法步骤：</span></p><p style="margin: 0px 0px 10px; text-indent: 2em; font-size: 13px; padding: 0px; border: 0px; background-color: #ffffff; font-family: 微软雅黑, Verdana, Tahoma, 'Lucida Grande', Arial, sans-serif; line-height: 24px; "><span style="font-family: Arial; ">1） 构建尺度空间，检测极值点，获得尺度不变性；</span></p><p style="margin: 0px 0px 10px; text-indent: 2em; font-size: 13px; padding: 0px; border: 0px; background-color: #ffffff; font-family: 微软雅黑, Verdana, Tahoma, 'Lucida Grande', Arial, sans-serif; line-height: 24px; "><span style="font-family: Arial; ">2） 特征点过滤并进行精确定位；</span></p><p style="margin: 0px 0px 10px; text-indent: 2em; font-size: 13px; padding: 0px; border: 0px; background-color: #ffffff; font-family: 微软雅黑, Verdana, Tahoma, 'Lucida Grande', Arial, sans-serif; line-height: 24px; "><span style="font-family: Arial; ">3） 为每个关键点指定方向参数</span></p><p style="margin: 0px 0px 10px; text-indent: 2em; font-size: 13px; padding: 0px; border: 0px; background-color: #ffffff; font-family: 微软雅黑, Verdana, Tahoma, 'Lucida Grande', Arial, sans-serif; line-height: 24px; "><span style="font-family: Arial; ">4） 生成关键点的描述子</span></p><p style="margin: 0px 0px 10px; text-indent: 2em; font-size: 13px; padding: 0px; border: 0px; background-color: #ffffff; font-family: 微软雅黑, Verdana, Tahoma, 'Lucida Grande', Arial, sans-serif; line-height: 24px; "><span style="font-family: Arial; ">5） 当两幅图像的Sift特征向量生成以后，下一步就可以采用关键点特征向 量的欧式距离来作为两幅图像中关键点的相似性判定度量。取一幅图中的某个关键点，通过遍历找到另一幅图中的距离最近的两个关键点。在这两个关键点中，如果次近距离除以最近距离小于某个阙值，则判定为一对匹配点。降低这个比例阈值，SIFT匹配点数目会减少，但更加稳定。</span></p><p style="margin: 0px 0px 10px; text-indent: 2em; font-size: 13px; padding: 0px; border: 0px; background-color: #ffffff; font-family: 微软雅黑, Verdana, Tahoma, 'Lucida Grande', Arial, sans-serif; line-height: 24px; "><span style="font-family: Arial; ">4、SIFT算法发展历程：</span></p><p style="margin: 0px 0px 10px; text-indent: 2em; font-size: 13px; padding: 0px; border: 0px; background-color: #ffffff; font-family: 微软雅黑, Verdana, Tahoma, 'Lucida Grande', Arial, sans-serif; line-height: 24px; "><span style="font-family: Arial; ">Sift算子最早是由David.G.Lowe于1999年提出的，当时主要用于对象识别。2004年David.G.Lowe对该算子做了全面的总结及更深入的发展和完善，正式提出了一种基于尺度空间的、对图像缩放、旋转甚至仿射变换保持不变性的图像局部特征描述算子&#8212;&#8212;Sift（ Scale Invariant Feature Transform )算子，即尺度不变特征变换。Rob Hess 基于GSL和Opencv编写了相应的C语言程序，后来Y.Ke将其描述子部分用PCA代替直方图的方式，对其进行改进。在Mikolajczyk对包括Sift算子在内的十种局部描述子所做的不变性对比实验中，Sift及其扩展算法已被证实在同类描述子中具有最强的健壮性。</span></p><p style="margin: 0px 0px 10px; text-indent: 2em; font-size: 13px; padding: 0px; border: 0px; background-color: #ffffff; font-family: 微软雅黑, Verdana, Tahoma, 'Lucida Grande', Arial, sans-serif; line-height: 24px; "><span style="font-family: Arial; ">主要文献：</span></p><p style="margin: 0px 0px 10px; text-indent: 2em; font-size: 13px; padding: 0px; border: 0px; background-color: #ffffff; font-family: 微软雅黑, Verdana, Tahoma, 'Lucida Grande', Arial, sans-serif; line-height: 24px; "><span style="font-family: Arial; ">1）David G. Lowe, &#8220;Object recognition from local scale-invariant features,&#8221; International Conference on Computer Vision, Corfu, Greece&nbsp;&nbsp;2）David G. Lowe, &#8220;Distinctive image features from scale-invariant keypoints,&#8221; International Journal of Computer Vision,</span></p><p style="margin: 0px 0px 10px; text-indent: 2em; font-size: 13px; padding: 0px; border: 0px; background-color: #ffffff; font-family: 微软雅黑, Verdana, Tahoma, 'Lucida Grande', Arial, sans-serif; line-height: 24px; "><span style="font-family: Arial; ">3）Y. Ke and R. Sukthankar. PCA-SIFT: A More Distinctive Representation for Local Image Descriptors.Computer Vision and Pattern Recognition, 2004</span></p><p style="margin: 0px 0px 10px; text-indent: 2em; font-size: 13px; padding: 0px; border: 0px; background-color: #ffffff; font-family: 微软雅黑, Verdana, Tahoma, 'Lucida Grande', Arial, sans-serif; line-height: 24px; "><span style="font-family: Arial; ">5、关于局部不变特征</span></p><p style="margin: 0px 0px 10px; text-indent: 2em; font-size: 13px; padding: 0px; border: 0px; background-color: #ffffff; font-family: 微软雅黑, Verdana, Tahoma, 'Lucida Grande', Arial, sans-serif; line-height: 24px; "><span style="font-family: Arial; ">1)局部不变特征的概念</span></p><p style="margin: 0px 0px 10px; text-indent: 2em; font-size: 13px; padding: 0px; border: 0px; background-color: #ffffff; font-family: 微软雅黑, Verdana, Tahoma, 'Lucida Grande', Arial, sans-serif; line-height: 24px; "><span style="font-family: Arial; ">局部不变特征就是由局部邻域所构成的一个图像模式。局部不变特征可以是点集，也可以是边缘集合，或者一些小的图像块集合，甚至是上述集合的复合体。局部不变特征认为图像中总是存在一些特殊的区域，这些区域中的特征比其它图像区域的特征更加稳定，信息含量更高，能够表征图像的内容。局部不变特征的局部是指特征只是图像的局部区域，不变性是指该特征不会因为图像经历了各种变换而发生变化。</span></p><p style="margin: 0px 0px 10px; text-indent: 2em; font-size: 13px; padding: 0px; border: 0px; background-color: #ffffff; font-family: 微软雅黑, Verdana, Tahoma, 'Lucida Grande', Arial, sans-serif; line-height: 24px; "><span style="font-family: Arial; ">2）局部不变特征特点</span></p><p style="margin: 0px 0px 10px; text-indent: 2em; font-size: 13px; padding: 0px; border: 0px; background-color: #ffffff; font-family: 微软雅黑, Verdana, Tahoma, 'Lucida Grande', Arial, sans-serif; line-height: 24px; "><span style="font-family: Arial; ">局部不变特征的种类繁多，适合不同的特征提取场合，各自独立性较强，相互之间可以组合和借鉴。复合类型的局部不变特征可能会增加计算负担，但是能够取得更好的性能。</span></p><p style="margin: 0px 0px 10px; text-indent: 2em; font-size: 13px; padding: 0px; border: 0px; background-color: #ffffff; font-family: 微软雅黑, Verdana, Tahoma, 'Lucida Grande', Arial, sans-serif; line-height: 24px; "><span style="font-family: Arial; ">3）局部不变特征的应用</span></p><p style="margin: 0px 0px 10px; text-indent: 2em; font-size: 13px; padding: 0px; border: 0px; background-color: #ffffff; font-family: 微软雅黑, Verdana, Tahoma, 'Lucida Grande', Arial, sans-serif; line-height: 24px; "><span style="font-family: Arial; ">局部不变特征是一种十分有效的工具，大量研究表明它能够适应各种图像处理的应用场合，特别是在模拟人类视觉系统的物体识别领域，拥有强大的应用性。从直观的人类视觉印象来看，人类视觉对物体的描述也是局部化的，基于局部不变特征的图像识别方法十分接近于人类视觉机理，通过局部化的特征组合，形成对目标物体的整体印象，这就为局部不变特征提取方法提供了生物学上的解释，因此局部不变特征也得到了广泛应用。</span></p><p style="margin: 0px 0px 10px; text-indent: 2em; font-size: 13px; padding: 0px; border: 0px; background-color: #ffffff; font-family: 微软雅黑, Verdana, Tahoma, 'Lucida Grande', Arial, sans-serif; line-height: 24px; "><span style="font-family: Arial; ">4）特征描述符</span></p><p style="margin: 0px 0px 10px; text-indent: 2em; font-size: 13px; padding: 0px; border: 0px; background-color: #ffffff; font-family: 微软雅黑, Verdana, Tahoma, 'Lucida Grande', Arial, sans-serif; line-height: 24px; "><span style="font-family: Arial; ">特征描述符(Featrue Descriptors)指的是检测图像的局部特征（比如边缘、角点、轮廓等），然后根据匹配目标的需要进行特征的组合、变换，以形成易于匹配、稳定性好的特征向量，从而把图像匹配问题转化为特征的匹配问题，进而将特征的匹配问题转化为特征空间特征向量的聚类问题。</span></p><p style="margin: 0px 0px 10px; text-indent: 2em; font-size: 13px; padding: 0px; border: 0px; background-color: #ffffff; font-family: 微软雅黑, Verdana, Tahoma, 'Lucida Grande', Arial, sans-serif; line-height: 24px; "><span style="font-family: Arial; ">5）局部不变特征检测与局部不变特征区域的概念</span></p><p style="margin: 0px 0px 10px; text-indent: 2em; font-size: 13px; padding: 0px; border: 0px; background-color: #ffffff; font-family: 微软雅黑, Verdana, Tahoma, 'Lucida Grande', Arial, sans-serif; line-height: 24px; "><span style="font-family: Arial; ">局部不变特征检测就是从图像中检测出具有某种几何和光学不变性(geometric and photometric invariant)的局部不变特征区域。局部不变特征区域是以特征点(feature point or key point)为中心带有尺度信息的图像局部区域。局部不变特征认为，在大多数的图像中总能找到一些性质特殊的区域，它们可以稳定的提取，并且对各种图像变化具有良好的鲁棒性且包涵更多的图像内容信息。</span></p><p style="margin: 0px 0px 10px; text-indent: 2em; font-size: 13px; padding: 0px; border: 0px; background-color: #ffffff; font-family: 微软雅黑, Verdana, Tahoma, 'Lucida Grande', Arial, sans-serif; line-height: 24px; "><span style="font-family: Arial; ">6、基于局部不变特征的图像处理理论和技术主要包括四个部分：</span></p><p style="margin: 0px 0px 10px; text-indent: 2em; font-size: 13px; padding: 0px; border: 0px; background-color: #ffffff; font-family: 微软雅黑, Verdana, Tahoma, 'Lucida Grande', Arial, sans-serif; line-height: 24px; "><span style="font-family: Arial; ">1）图像尺度空间：图像数据包含大量混杂在一起的特征信息，按照局部不变特征的思想，这些特征信息是归属于不同类型不同属性的目标物体，其位置和控制区域各不相同，不同分布和参数的特征相互叠加和组合，这使得特征提取变得困难，所以需将这些特征进行一定的&#8220;分离&#8221;操作，将各类特征分散到整个图像数据空间中去，图像尺度空间就是为图像的各种不同类特征分离提供的一种数据表示法。</span></p><p style="margin: 0px 0px 10px; text-indent: 2em; font-size: 13px; padding: 0px; border: 0px; background-color: #ffffff; font-family: 微软雅黑, Verdana, Tahoma, 'Lucida Grande', Arial, sans-serif; line-height: 24px; "><span style="font-family: Arial; ">2）局部不变特征检测：在尺度空间内构造不变特征检测函数，生成对应尺度下的局部不变特征空间，检测其中具有一定特征显著性的局部不变特征区域，并把它作为特征描述的目标区域，确定每个特征的尺度系数，局部不变特征结构的位置和尺度范围。这些局部区域及其包含的信息形成对图像语义结构信息的表示，为进一步的特征描述提供图像内容的结构和范围信息。</span></p><p style="margin: 0px 0px 10px; text-indent: 2em; font-size: 13px; padding: 0px; border: 0px; background-color: #ffffff; font-family: 微软雅黑, Verdana, Tahoma, 'Lucida Grande', Arial, sans-serif; line-height: 24px; "><span style="font-family: Arial; ">3）局部不变特征描述：局部不变特征检测获得的特征仅仅给出了图像内容的结构信息，局部不变特征区域还需要从图像尺度空间表示的数据形式转化特征描述向量。局部不变特征描述就是用局部不变特征描述符(Local feature descriptor)去描述局部不变特征区域，用尽可能相互独立和完备的特征描述数据来表示复杂组合的目标物体，完整详细地描述图像内容，给出图像的语义信息。</span></p><p style="margin: 0px 0px 10px; text-indent: 2em; font-size: 13px; padding: 0px; border: 0px; background-color: #ffffff; font-family: 微软雅黑, Verdana, Tahoma, 'Lucida Grande', Arial, sans-serif; line-height: 24px; "><span style="font-family: Arial; ">4）特征匹配和检索：特征提取的最终目的是使用这些特征来进行目标识别和特征的检索，通过对特征描述空间中的特征数据进行分类、匹配和检索，实现各种图像识别应用。由于其良好的鲁棒性和抗干扰性，使的它作为目标识别中机器学习样本描述的首选特征，图像和视频检索方法也大都采用局部不变特征作为学习和检索的依据。</span></p><p style="margin: 0px 0px 10px; text-indent: 2em; font-size: 13px; padding: 0px; border: 0px; background-color: #ffffff; font-family: 微软雅黑, Verdana, Tahoma, 'Lucida Grande', Arial, sans-serif; line-height: 24px; "><span style="font-family: Arial; ">7、局部不变特征发展方向</span></p><p style="margin: 0px 0px 10px; text-indent: 2em; font-size: 13px; padding: 0px; border: 0px; background-color: #ffffff; font-family: 微软雅黑, Verdana, Tahoma, 'Lucida Grande', Arial, sans-serif; line-height: 24px; "><span style="font-family: Arial; ">目前，局部不变特征主要分为两个发展方向：</span></p><p style="margin: 0px 0px 10px; text-indent: 2em; font-size: 13px; padding: 0px; border: 0px; background-color: #ffffff; font-family: 微软雅黑, Verdana, Tahoma, 'Lucida Grande', Arial, sans-serif; line-height: 24px; "><span style="font-family: Arial; ">1) 结构化的局部不变特征提取模型，也就是特征提取模型分为四个较为清晰的处理模块（上文中有提到）。在局部不变特征检测方面，D.Lowe提出基于扩散方程的尺度不变的SIFT特征检测方法，以及由角点检测发展而来的Multi-scale Harris检测，具有仿射不变性的Harris-Laplace/Affine检测等，目前局部不变特征检测方法逐渐向着检测具有多种不变性和抗干扰性强的局部不变特征的方向发展。局部不变特征描述技术更加广泛，其中以SIFT，GLOH,Steerable Filters,Shape Context,Complex Filters等为主要特征描述符。特征检索和匹配模块一般是面向图像模式识别的具体应用场合，如图像检索，机器学习的样本特征集合，目标识别中的样本特征数据库等，同时在视频的检索领域也获得不错的效果。</span></p><p style="margin: 0px 0px 10px; text-indent: 2em; font-size: 13px; padding: 0px; border: 0px; background-color: #ffffff; font-family: 微软雅黑, Verdana, Tahoma, 'Lucida Grande', Arial, sans-serif; line-height: 24px; "><span style="font-family: Arial; ">2) 模仿人类的视觉系统，通过模仿人类视觉系统的运作原理提出了显著性区域理论。这一理论认为图像中的每个局部区域的重要性和影响范围并非同等重要，即特征不是同等显著的，其主要理论来源是Marr的计算机视觉理论和Treisman的特征整合理论，一般也称为&#8220;原子论&#8221;。该理论认为视觉的过程开始于对物体的特征性质和简单组成部分的分析，是从局部性</span></p><p style="margin: 0px 0px 10px; text-indent: 2em; font-size: 13px; padding: 0px; border: 0px; background-color: #ffffff; font-family: 微软雅黑, Verdana, Tahoma, 'Lucida Grande', Arial, sans-serif; line-height: 24px; "><span style="font-family: Arial; ">质到大范围性质，图像中的每个局部不变特征的视觉显著性是不同的，所以在局部不变特征的提取和描述时也遵循与人眼视觉注意选择原理相类似的机制（Visual Selective Attention Mechanism）。</span></p><p style="margin: 0px 0px 10px; text-indent: 2em; font-size: 13px; padding: 0px; border: 0px; background-color: #ffffff; font-family: 微软雅黑, Verdana, Tahoma, 'Lucida Grande', Arial, sans-serif; line-height: 24px; "><span style="font-family: Arial; ">8、软件：SIFT Keypoint Detector</span></p><p style="margin: 0px 0px 10px; text-indent: 2em; font-size: 13px; padding: 0px; border: 0px; background-color: #ffffff; font-family: 微软雅黑, Verdana, Tahoma, 'Lucida Grande', Arial, sans-serif; line-height: 24px; "><span style="font-family: Arial; ">该软件是可以在Linux或Windows系统中运行的汇编代码形式的SIFT特征点检测器， 它可以输出特征点和可以匹配到一个简单的ASCII格式文件需要的所有信息。 所提供的MATLAB程序和示例C代码可以读取特征点并根据它们对两幅图片进行匹配。</span></p><p style="margin: 0px 0px 10px; text-indent: 2em; font-size: 13px; padding: 0px; border: 0px; background-color: #ffffff; font-family: 微软雅黑, Verdana, Tahoma, 'Lucida Grande', Arial, sans-serif; line-height: 24px; "><span style="font-family: Arial; ">9、应用前景</span></p><p style="margin: 0px 0px 10px; text-indent: 2em; font-size: 13px; padding: 0px; border: 0px; background-color: #ffffff; font-family: 微软雅黑, Verdana, Tahoma, 'Lucida Grande', Arial, sans-serif; line-height: 24px; "><span style="font-family: Arial; ">SIFT算法是模式识别的一种高效手段，凡模式识别的应用方面都可以运用SIFT算法来改进识别速度。</span></p><p style="margin: 0px 0px 10px; text-indent: 2em; font-size: 13px; padding: 0px; border: 0px; background-color: #ffffff; font-family: 微软雅黑, Verdana, Tahoma, 'Lucida Grande', Arial, sans-serif; line-height: 24px; "><span style="font-family: Arial; ">医学：运动学人体机能研究</span></p><p style="margin: 0px 0px 10px; text-indent: 2em; font-size: 13px; padding: 0px; border: 0px; background-color: #ffffff; font-family: 微软雅黑, Verdana, Tahoma, 'Lucida Grande', Arial, sans-serif; line-height: 24px; "><span style="font-family: Arial; ">仿生学：人工模拟生物</span></p><p style="margin: 0px 0px 10px; text-indent: 2em; font-size: 13px; padding: 0px; border: 0px; background-color: #ffffff; font-family: 微软雅黑, Verdana, Tahoma, 'Lucida Grande', Arial, sans-serif; line-height: 24px; "><span style="font-family: Arial; ">人工智能：智能机器人、智能驾驶</span></p><p style="margin: 0px 0px 10px; text-indent: 2em; font-size: 13px; padding: 0px; border: 0px; background-color: #ffffff; font-family: 微软雅黑, Verdana, Tahoma, 'Lucida Grande', Arial, sans-serif; line-height: 24px; "><span style="font-family: Arial; ">刑侦技术：跟踪</span></p><p style="margin: 0px 0px 10px; text-indent: 2em; font-size: 13px; padding: 0px; border: 0px; background-color: #ffffff; font-family: 微软雅黑, Verdana, Tahoma, 'Lucida Grande', Arial, sans-serif; line-height: 24px; "><span style="font-family: Arial; ">军事用途：敌友识别（战机、战舰、潜艇、雷达跟踪等等）</span></p><img src ="http://www.blogjava.net/hao446tian/aggbug/402635.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hao446tian/" target="_blank">昊天</a> 2013-08-09 16:33 <a href="http://www.blogjava.net/hao446tian/archive/2013/08/09/402635.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Spring中实现AOP的两种方式</title><link>http://www.blogjava.net/hao446tian/archive/2012/04/11/373821.html</link><dc:creator>昊天</dc:creator><author>昊天</author><pubDate>Wed, 11 Apr 2012 08:49:00 GMT</pubDate><guid>http://www.blogjava.net/hao446tian/archive/2012/04/11/373821.html</guid><wfw:comment>http://www.blogjava.net/hao446tian/comments/373821.html</wfw:comment><comments>http://www.blogjava.net/hao446tian/archive/2012/04/11/373821.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hao446tian/comments/commentRss/373821.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hao446tian/services/trackbacks/373821.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 这里演示的是Spring中使用AspectJ注解和XML配置两种方式实现AOP下面是使用AspectJ注解实现AOP的Java Project首先是位于classpath下的applicationContext.xml文件&nbsp;Code highlighting produced by Actipro CodeHighlighter (freeware)http://www....&nbsp;&nbsp;<a href='http://www.blogjava.net/hao446tian/archive/2012/04/11/373821.html'>阅读全文</a><img src ="http://www.blogjava.net/hao446tian/aggbug/373821.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hao446tian/" target="_blank">昊天</a> 2012-04-11 16:49 <a href="http://www.blogjava.net/hao446tian/archive/2012/04/11/373821.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>自定义ClassLoader</title><link>http://www.blogjava.net/hao446tian/archive/2012/02/16/370064.html</link><dc:creator>昊天</dc:creator><author>昊天</author><pubDate>Thu, 16 Feb 2012 01:39:00 GMT</pubDate><guid>http://www.blogjava.net/hao446tian/archive/2012/02/16/370064.html</guid><wfw:comment>http://www.blogjava.net/hao446tian/comments/370064.html</wfw:comment><comments>http://www.blogjava.net/hao446tian/archive/2012/02/16/370064.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hao446tian/comments/commentRss/370064.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hao446tian/services/trackbacks/370064.html</trackback:ping><description><![CDATA[JVM在加载类的时候，都是通过ClassLoader的loadClass()方法来加载class的，loadClass(String name)方法： <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" href="http://www.iteye.com/topic/70072#"></a>&nbsp;<a title="收藏这段代码" href="javascript:void()"></a></div></div>
<ol class="dp-j"><li><span class="keyword">public</span><span>&nbsp;Class&lt;?&gt;&nbsp;loadClass(String&nbsp;name)&nbsp;</span><span class="keyword">throws</span><span>&nbsp;ClassNotFoundException&nbsp;{ &nbsp;&nbsp;</span></li><li><span></span><span class="keyword">return</span><span>&nbsp;loadClass(name,&nbsp;</span><span class="keyword">false</span><span>); &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li></ol></div><pre class="java" title="自定义ClassLoader" style="display: none" name="code" codeable_type="Post" codeable_id="260290" source_url="http://www.iteye.com/topic/70072#260290" pre_index="0"> public Class&lt;?&gt; loadClass(String name) throws ClassNotFoundException {
	return loadClass(name, false);
    }
</pre><br />loadClass(String name)方法再调用loadClass(String name, boolean resolve)方法: <br />&nbsp;&nbsp;&nbsp;&nbsp; - name - 类的二进制名称 <br />&nbsp;&nbsp;&nbsp;&nbsp; - resolve - 如果该参数为 true，则分析这个类 <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" href="http://www.iteye.com/topic/70072#"></a>&nbsp;<a title="收藏这段代码" href="javascript:void()"></a></div></div>
<ol class="dp-j"><li><span class="keyword">protected</span><span>&nbsp;</span><span class="keyword">synchronized</span><span>&nbsp;Class&lt;?&gt;&nbsp;loadClass(String&nbsp;name,&nbsp;</span><span class="keyword">boolean</span><span>&nbsp;resolve) &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">throws</span><span>&nbsp;ClassNotFoundException &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;First,&nbsp;check&nbsp;if&nbsp;the&nbsp;class&nbsp;has&nbsp;already&nbsp;been&nbsp;loaded </span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//JVM&nbsp;规范规定ClassLoader可以在缓存保留它所加载的Class，如果一个Class已经被加载过，则直接从缓存中获取 </span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;Class&nbsp;c&nbsp;=&nbsp;findLoadedClass(name); &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">if</span><span>&nbsp;(c&nbsp;==&nbsp;</span><span class="keyword">null</span><span>)&nbsp;{ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">try</span><span>&nbsp;{ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">if</span><span>&nbsp;(parent&nbsp;!=&nbsp;</span><span class="keyword">null</span><span>)&nbsp;{ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;c&nbsp;=&nbsp;parent.loadClass(name,&nbsp;</span><span class="keyword">false</span><span>); &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span class="keyword">else</span><span>&nbsp;{ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;c&nbsp;=&nbsp;findBootstrapClass0(name); &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span class="keyword">catch</span><span>&nbsp;(ClassNotFoundException&nbsp;e)&nbsp;{ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;If&nbsp;still&nbsp;not&nbsp;found,&nbsp;then&nbsp;invoke&nbsp;findClass&nbsp;in&nbsp;order </span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;to&nbsp;find&nbsp;the&nbsp;class. </span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;c&nbsp;=&nbsp;findClass(name); &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">if</span><span>&nbsp;(resolve)&nbsp;{ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;resolveClass(c); &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span>&nbsp;c; &nbsp;&nbsp;</span></span></li><li><span>}&nbsp;&nbsp;</span></li></ol></div><pre class="java" title="自定义ClassLoader" style="display: none" name="code" codeable_type="Post" codeable_id="260290" source_url="http://www.iteye.com/topic/70072#260290" pre_index="1">protected synchronized Class&lt;?&gt; loadClass(String name, boolean resolve)
	throws ClassNotFoundException
    {
	// First, check if the class has already been loaded
	//JVM 规范规定ClassLoader可以在缓存保留它所加载的Class，如果一个Class已经被加载过，则直接从缓存中获取
	Class c = findLoadedClass(name);
	if (c == null) {
	    try {
		if (parent != null) {
		    c = parent.loadClass(name, false);
		} else {
		    c = findBootstrapClass0(name);
		}
	    } catch (ClassNotFoundException e) {
	        // If still not found, then invoke findClass in order
	        // to find the class.
	        c = findClass(name);
	    }
	}
	if (resolve) {
	    resolveClass(c);
	}
	return c;
}
</pre><br />如果ClassLoader并没有加载这个class，则调用findBootstrapClass0: <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" href="http://www.iteye.com/topic/70072#"></a>&nbsp;<a title="收藏这段代码" href="javascript:void()"></a></div></div>
<ol class="dp-j"><li><span class="keyword">private</span><span>&nbsp;Class&nbsp;findBootstrapClass0(String&nbsp;name) &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">throws</span><span>&nbsp;ClassNotFoundException &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;check(); &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">if</span><span>&nbsp;(!checkName(name)) &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">throw</span><span>&nbsp;</span><span class="keyword">new</span><span>&nbsp;ClassNotFoundException(name); &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span>&nbsp;findBootstrapClass(name); &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li></ol></div><pre class="java" title="自定义ClassLoader" style="display: none" name="code" codeable_type="Post" codeable_id="260290" source_url="http://www.iteye.com/topic/70072#260290" pre_index="2">private Class findBootstrapClass0(String name)
	throws ClassNotFoundException
    {
	check();
	if (!checkName(name))
	    throw new ClassNotFoundException(name);
	return findBootstrapClass(name);
    }
</pre><br />该方法会调用check()方法来判断这个类是否已经初始化，并且通过checkName(name)来判断由name指定的这个类是否存在 <br />最后调用findBootstrapClass(name): <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" href="http://www.iteye.com/topic/70072#"></a>&nbsp;<a title="收藏这段代码" href="javascript:void()"></a></div></div>
<ol class="dp-j"><li><span class="keyword">private</span><span>&nbsp;</span><span class="keyword">native</span><span>&nbsp;Class&nbsp;findBootstrapClass(String&nbsp;name) &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">throws</span><span>&nbsp;ClassNotFoundException;&nbsp;&nbsp;</span></span></li></ol></div><pre class="java" title="自定义ClassLoader" style="display: none" name="code" codeable_type="Post" codeable_id="260290" source_url="http://www.iteye.com/topic/70072#260290" pre_index="3">private native Class findBootstrapClass(String name)
	throws ClassNotFoundException;
</pre><br />而这个findBootstrapClass方法是一个native方法，这是我们的root loader，这个载入方法并非是由JAVA所写，而是C++写的，它会最终调用JVM中的原生findBootstrapClass方法来完成类的加载。 <br /><br />如果上面两个都找不到，则使用findClass(name)来查找指定类名的Class: <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" href="http://www.iteye.com/topic/70072#"></a>&nbsp;<a title="收藏这段代码" href="javascript:void()"></a></div></div>
<ol class="dp-j"><li><span class="keyword">protected</span><span>&nbsp;Class&lt;?&gt;&nbsp;findClass(String&nbsp;name)&nbsp;</span><span class="keyword">throws</span><span>&nbsp;ClassNotFoundException&nbsp;{ &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">throw</span><span>&nbsp;</span><span class="keyword">new</span><span>&nbsp;ClassNotFoundException(name); &nbsp;&nbsp;</span></span></li><li><span>}&nbsp;&nbsp;</span></li></ol></div><pre class="java" title="自定义ClassLoader" style="display: none" name="code" codeable_type="Post" codeable_id="260290" source_url="http://www.iteye.com/topic/70072#260290" pre_index="4">protected Class&lt;?&gt; findClass(String name) throws ClassNotFoundException {
	throw new ClassNotFoundException(name);
}
</pre><br /><strong>JDK5.0中的说明：</strong> <br />使用指定的二进制名称查找类。此方法应该被类加载器的实现重写，该实现按照委托模型来加载类。在通过父类加载器检查所请求的类后，此方法将被 loadClass 方法调用。默认实现抛出一个 ClassNotFoundException。 <br />所以，我们在自定义类中，只需要重写findClass()即可。 <br />MyClassLoader类： <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" href="http://www.iteye.com/topic/70072#"></a>&nbsp;<a title="收藏这段代码" href="javascript:void()"></a></div></div>
<ol class="dp-j"><li><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">class</span><span>&nbsp;MyClassLoader&nbsp;</span><span class="keyword">extends</span><span>&nbsp;ClassLoader&nbsp;{ &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">private</span><span>&nbsp;String&nbsp;fileName; &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;MyClassLoader(String&nbsp;fileName)&nbsp;{ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">this</span><span>.fileName&nbsp;=&nbsp;fileName; &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">protected</span><span>&nbsp;Class&lt;?&gt;&nbsp;findClass(String&nbsp;className)&nbsp;</span><span class="keyword">throws</span><span>&nbsp;ClassNotFoundException&nbsp;{ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Class&nbsp;clazz&nbsp;=&nbsp;</span><span class="keyword">this</span><span>.findLoadedClass(className); &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">if</span><span>&nbsp;(</span><span class="keyword">null</span><span>&nbsp;==&nbsp;clazz)&nbsp;{ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">try</span><span>&nbsp;{ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;classFile&nbsp;=&nbsp;getClassFile(className); &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FileInputStream&nbsp;fis&nbsp;=&nbsp;</span><span class="keyword">new</span><span>&nbsp;FileInputStream(classFile); &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FileChannel&nbsp;fileC&nbsp;=&nbsp;fis.getChannel(); &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ByteArrayOutputStream&nbsp;baos&nbsp;=&nbsp;</span><span class="keyword">new</span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ByteArrayOutputStream(); &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WritableByteChannel&nbsp;outC&nbsp;=&nbsp;Channels.newChannel(baos); &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ByteBuffer&nbsp;buffer&nbsp;=&nbsp;ByteBuffer.allocateDirect(</span><span class="number"><font color="#c00000">1024</font></span><span>); &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">while</span><span>&nbsp;(</span><span class="keyword">true</span><span>)&nbsp;{ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">int</span><span>&nbsp;i&nbsp;=&nbsp;fileC.read(buffer); &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">if</span><span>&nbsp;(i&nbsp;==&nbsp;</span><span class="number"><font color="#c00000">0</font></span><span>&nbsp;||&nbsp;i&nbsp;==&nbsp;-</span><span class="number"><font color="#c00000">1</font></span><span>)&nbsp;{ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">break</span><span>; &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;buffer.flip(); &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;outC.write(buffer); &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;buffer.clear(); &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fis.close(); &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">byte</span><span>[]&nbsp;bytes&nbsp;=&nbsp;baos.toByteArray(); &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;clazz&nbsp;=&nbsp;defineClass(className,&nbsp;bytes,&nbsp;</span><span class="number"><font color="#c00000">0</font></span><span>,&nbsp;bytes.length); &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span class="keyword">catch</span><span>&nbsp;(FileNotFoundException&nbsp;e)&nbsp;{ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace(); &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span class="keyword">catch</span><span>&nbsp;(IOException&nbsp;e)&nbsp;{ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace(); &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span>&nbsp;clazz; &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">private</span><span>&nbsp;</span><span class="keyword">byte</span><span>[]&nbsp;loadClassBytes(String&nbsp;className)&nbsp;</span><span class="keyword">throws</span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ClassNotFoundException&nbsp;{ &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">try</span><span>&nbsp;{ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;classFile&nbsp;=&nbsp;getClassFile(className); &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FileInputStream&nbsp;fis&nbsp;=&nbsp;</span><span class="keyword">new</span><span>&nbsp;FileInputStream(classFile); &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FileChannel&nbsp;fileC&nbsp;=&nbsp;fis.getChannel(); &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ByteArrayOutputStream&nbsp;baos&nbsp;=&nbsp;</span><span class="keyword">new</span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ByteArrayOutputStream(); &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WritableByteChannel&nbsp;outC&nbsp;=&nbsp;Channels.newChannel(baos); &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ByteBuffer&nbsp;buffer&nbsp;=&nbsp;ByteBuffer.allocateDirect(</span><span class="number"><font color="#c00000">1024</font></span><span>); &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">while</span><span>&nbsp;(</span><span class="keyword">true</span><span>)&nbsp;{ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">int</span><span>&nbsp;i&nbsp;=&nbsp;fileC.read(buffer); &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">if</span><span>&nbsp;(i&nbsp;==&nbsp;</span><span class="number"><font color="#c00000">0</font></span><span>&nbsp;||&nbsp;i&nbsp;==&nbsp;-</span><span class="number"><font color="#c00000">1</font></span><span>)&nbsp;{ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">break</span><span>; &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;buffer.flip(); &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;outC.write(buffer); &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;buffer.clear(); &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fis.close(); &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span>&nbsp;baos.toByteArray(); &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span class="keyword">catch</span><span>&nbsp;(IOException&nbsp;fnfe)&nbsp;{ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">throw</span><span>&nbsp;</span><span class="keyword">new</span><span>&nbsp;ClassNotFoundException(className); &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">private</span><span>&nbsp;String&nbsp;getClassFile(String&nbsp;name)&nbsp;{ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;StringBuffer&nbsp;sb&nbsp;=&nbsp;</span><span class="keyword">new</span><span>&nbsp;StringBuffer(fileName); &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;name&nbsp;=&nbsp;name.replace(</span><span class="string">'.'</span><span>,&nbsp;File.separatorChar)&nbsp;+&nbsp;</span><span class="string">".class"</span><span>; &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sb.append(File.separator&nbsp;+&nbsp;name); &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span>&nbsp;sb.toString(); &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li><li><span>}&nbsp;&nbsp;</span></li></ol></div><pre class="java" title="自定义ClassLoader" style="display: none" name="code" codeable_type="Post" codeable_id="260290" source_url="http://www.iteye.com/topic/70072#260290" pre_index="5">public class MyClassLoader extends ClassLoader {
    private String fileName;

    public MyClassLoader(String fileName) {
        this.fileName = fileName;
    }

    protected Class&lt;?&gt; findClass(String className) throws ClassNotFoundException {
        Class clazz = this.findLoadedClass(className);
        if (null == clazz) {
            try {
                String classFile = getClassFile(className);
                FileInputStream fis = new FileInputStream(classFile);
                FileChannel fileC = fis.getChannel();
                ByteArrayOutputStream baos = new
                        ByteArrayOutputStream();
                WritableByteChannel outC = Channels.newChannel(baos);
                ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
                while (true) {
                    int i = fileC.read(buffer);
                    if (i == 0 || i == -1) {
                        break;
                    }
                    buffer.flip();
                    outC.write(buffer);
                    buffer.clear();
                }
                fis.close();
                byte[] bytes = baos.toByteArray();

                clazz = defineClass(className, bytes, 0, bytes.length);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return clazz;
    }
    private byte[] loadClassBytes(String className) throws
            ClassNotFoundException {
        try {
            String classFile = getClassFile(className);
            FileInputStream fis = new FileInputStream(classFile);
            FileChannel fileC = fis.getChannel();
            ByteArrayOutputStream baos = new
                    ByteArrayOutputStream();
            WritableByteChannel outC = Channels.newChannel(baos);
            ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
            while (true) {
                int i = fileC.read(buffer);
                if (i == 0 || i == -1) {
                    break;
                }
                buffer.flip();
                outC.write(buffer);
                buffer.clear();
            }
            fis.close();
            return baos.toByteArray();
        } catch (IOException fnfe) {
            throw new ClassNotFoundException(className);
        }
    }
    private String getClassFile(String name) {
        StringBuffer sb = new StringBuffer(fileName);
        name = name.replace('.', File.separatorChar) + ".class";
        sb.append(File.separator + name);
        return sb.toString();
    }
}
</pre><br />该类中通过调用defineClass(String name, byte[] b, int off, int len)方法来定义一个类： <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" href="http://www.iteye.com/topic/70072#"></a>&nbsp;<a title="收藏这段代码" href="javascript:void()"></a></div></div>
<ol class="dp-j"><li><span class="keyword">protected</span><span>&nbsp;</span><span class="keyword">final</span><span>&nbsp;Class&lt;?&gt;&nbsp;defineClass(String&nbsp;name,&nbsp;</span><span class="keyword">byte</span><span>[]&nbsp;b,&nbsp;</span><span class="keyword">int</span><span>&nbsp;off,&nbsp;</span><span class="keyword">int</span><span>&nbsp;len) &nbsp;&nbsp;</span></li><li><span></span><span class="keyword">throws</span><span>&nbsp;ClassFormatError &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;</span></li><li><span></span><span class="keyword">return</span><span>&nbsp;defineClass(name,&nbsp;b,&nbsp;off,&nbsp;len,&nbsp;</span><span class="keyword">null</span><span>); &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li></ol></div><pre class="java" title="自定义ClassLoader" style="display: none" name="code" codeable_type="Post" codeable_id="260290" source_url="http://www.iteye.com/topic/70072#260290" pre_index="6"> protected final Class&lt;?&gt; defineClass(String name, byte[] b, int off, int len)
	throws ClassFormatError
    {
	return defineClass(name, b, off, len, null);
    }
</pre><br /><strong>注：</strong>MyClassLoader加载类时有一个局限，必需指定<strong>.class</strong>文件，而不能指定<strong>.jar</strong>文件。MainClassLoader类： <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" href="http://www.iteye.com/topic/70072#"></a>&nbsp;<a title="收藏这段代码" href="javascript:void()"></a></div></div>
<ol class="dp-j"><li><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">class</span><span>&nbsp;MainClassLoader&nbsp;{ &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">static</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;main(String[]&nbsp;args)&nbsp;{ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">try</span><span>&nbsp;{ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MyClassLoader&nbsp;tc&nbsp;=&nbsp;</span><span class="keyword">new</span><span>&nbsp;MyClassLoader(</span><span class="string">"F:\\OpenLib\\"</span><span>); &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Class&nbsp;c&nbsp;=&nbsp;tc.findClass(</span><span class="string">"Test"</span><span>); &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;c.newInstance(); &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span class="keyword">catch</span><span>&nbsp;(ClassNotFoundException&nbsp;e)&nbsp;{ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace();&nbsp; &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span class="keyword">catch</span><span>&nbsp;(IllegalAccessException&nbsp;e)&nbsp;{ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace(); &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span class="keyword">catch</span><span>&nbsp;(InstantiationException&nbsp;e)&nbsp;{ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace();&nbsp; &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li><li><span>}&nbsp;&nbsp;</span></li></ol></div><pre class="java" title="自定义ClassLoader" style="display: none" name="code" codeable_type="Post" codeable_id="260290" source_url="http://www.iteye.com/topic/70072#260290" pre_index="7">public class MainClassLoader {
    public static void main(String[] args) {
        try {
            MyClassLoader tc = new MyClassLoader("F:\\OpenLib\\");
            Class c = tc.findClass("Test");
            c.newInstance();
        } catch (ClassNotFoundException e) {
            e.printStackTrace(); 
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace(); 
        }
    }
}
</pre><br />最后是一个简单的Test测试类： <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" href="http://www.iteye.com/topic/70072#"></a>&nbsp;<a title="收藏这段代码" href="javascript:void()"></a></div></div>
<ol class="dp-j"><li><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">class</span><span>&nbsp;Test &nbsp;&nbsp;</span></li><li><span>{ &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;Test()&nbsp;{ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span class="string">"Test"</span><span>); &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">static</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;main(String[]&nbsp;args)&nbsp;{ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span class="string">"Hello&nbsp;World"</span><span>); &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li><li><span>}&nbsp;&nbsp;</span></li></ol></div><pre class="java" title="自定义ClassLoader" style="display: none" name="code" codeable_type="Post" codeable_id="260290" source_url="http://www.iteye.com/topic/70072#260290" pre_index="8">public class Test
{
	public Test() {
		System.out.println("Test");
	}
	public static void main(String[] args) {
		System.out.println("Hello World");
	}
}
</pre><img src ="http://www.blogjava.net/hao446tian/aggbug/370064.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hao446tian/" target="_blank">昊天</a> 2012-02-16 09:39 <a href="http://www.blogjava.net/hao446tian/archive/2012/02/16/370064.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>通过分析JDK源代码研究Hash 存储机制</title><link>http://www.blogjava.net/hao446tian/archive/2011/10/25/362018.html</link><dc:creator>昊天</dc:creator><author>昊天</author><pubDate>Tue, 25 Oct 2011 08:37:00 GMT</pubDate><guid>http://www.blogjava.net/hao446tian/archive/2011/10/25/362018.html</guid><wfw:comment>http://www.blogjava.net/hao446tian/comments/362018.html</wfw:comment><comments>http://www.blogjava.net/hao446tian/archive/2011/10/25/362018.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hao446tian/comments/commentRss/362018.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hao446tian/services/trackbacks/362018.html</trackback:ping><description><![CDATA[<p>实际上，HashSet 和 HashMap 之间有很多相似之处，对于 HashSet 而言，系统采用 Hash 算法决定集合元素的存储位置，这样可以保证能快速存、取集合元素；对于 HashMap 而言，系统 key-value 当成一个整体进行处理，系统总是根据 Hash 算法来计算 key-value 的存储位置，这样可以保证能快速存、取 Map 的 key-value 对。</p>
<p>在介绍集合存储之前需要指出一点：虽然集合号称存储的是 Java 对象，但实际上并不会真正将 Java 对象放入 Set 集合中，只是在 Set 集合中保留这些对象的引用而言。也就是说：Java 集合实际上是多个引用变量所组成的集合，这些引用变量指向实际的 Java 对象。</p>
<div class="ibm-alternate-rule">
<hr />
</div>
<p sizcache="25" sizset="79"><a name="major2"><span class="atitle"><strong><font size="5">HashMap 的存储实现</font></strong></span></a></p>
<p>当程序试图将多个 key-value 放入 HashMap 中时，以如下代码片段为例：</p>
<table cellspacing="0" cellpadding="0" width="100%" border="0" sizcache="2" sizset="0">
<tbody sizcache="1" sizset="0">
<tr>
<td class="code-outline"><pre class="displaycode"> HashMap&lt;String , Double&gt; map = new HashMap&lt;String , Double&gt;(); 
 map.put("语文" , 80.0); 
 map.put("数学" , 89.0); 
 map.put("英语" , 78.2); 
</pre></td></tr></tbody></table><br />
<p>HashMap 采用一种所谓的&#8220;Hash 算法&#8221;来决定每个元素的存储位置。</p>
<p>当程序执行 map.put("语文" , 80.0); 时，系统将调用"语文"的 hashCode() 方法得到其 hashCode 值&#8212;&#8212;每个 Java 对象都有 hashCode() 方法，都可通过该方法获得它的 hashCode 值。得到这个对象的 hashCode 值之后，系统会根据该 hashCode 值来决定该元素的存储位置。</p>
<p>我们可以看 HashMap 类的 put(K key , V value) 方法的源代码：</p>
<table cellspacing="0" cellpadding="0" width="100%" border="0" sizcache="2" sizset="1">
<tbody sizcache="1" sizset="1">
<tr>
<td class="code-outline"><pre class="displaycode"> public V put(K key, V value) 
 { 
	 // 如果 key 为 null，调用 putForNullKey 方法进行处理
	 if (key == null) 
		 return putForNullKey(value); 
	 // 根据 key 的 keyCode 计算 Hash 值
	 int hash = hash(key.hashCode()); 
	 // 搜索指定 hash 值在对应 table 中的索引
 <strong>	 int i = indexFor(hash, table.length);</strong>
	 // 如果 i 索引处的 Entry 不为 null，通过循环不断遍历 e 元素的下一个元素
	 for (Entry&lt;K,V&gt; e = table[i]; e != null; e = e.next) 
	 { 
		 Object k; 
		 // 找到指定 key 与需要放入的 key 相等（hash 值相同
		 // 通过 equals 比较放回 true）
		 if (e.hash == hash &amp;&amp; ((k = e.key) == key 
			 || key.equals(k))) 
		 { 
			 V oldValue = e.value; 
			 e.value = value; 
			 e.recordAccess(this); 
			 return oldValue; 
		 } 
	 } 
	 // 如果 i 索引处的 Entry 为 null，表明此处还没有 Entry 
	 modCount++; 
	 // 将 key、value 添加到 i 索引处
	 addEntry(hash, key, value, i); 
	 return null; 
 } 
</pre></td></tr></tbody></table><br />
<div class="ibm-container ibm-alt-header dw-container-sidebar" sizcache="25" sizset="80"><a name="sidebar2"></a>
<h2>JDK 源码</h2>
<div class="ibm-container-body">
<p>在 JDK 安装目录下可以找到一个 src.zip 压缩文件，该文件里包含了 Java 基础类库的所有源文件。只要读者有学习兴趣，随时可以打开这份压缩文件来阅读 Java 类库的源代码，这对提高读者的编程能力是非常有帮助的。需要指出的是：src.zip 中包含的源代码并没有包含像上文中的中文注释，这些注释是笔者自己添加进去的。</p></div></div>
<p>上面程序中用到了一个重要的内部接口：Map.Entry，每个 Map.Entry 其实就是一个 key-value 对。从上面程序中可以看出：当系统决定存储 HashMap 中的 key-value 对时，完全没有考虑 Entry 中的 value，仅仅只是根据 key 来计算并决定每个 Entry 的存储位置。这也说明了前面的结论：我们完全可以把 Map 集合中的 value 当成 key 的附属，当系统决定了 key 的存储位置之后，value 随之保存在那里即可。</p>
<p>上面方法提供了一个根据 hashCode() 返回值来计算 Hash 码的方法：hash()，这个方法是一个纯粹的数学计算，其方法如下：</p>
<table cellspacing="0" cellpadding="0" width="60%" border="0" sizcache="2" sizset="2">
<tbody sizcache="1" sizset="2">
<tr>
<td class="code-outline"><pre class="displaycode">static int hash(int h) 
{ 
    h ^= (h &gt;&gt;&gt; 20) ^ (h &gt;&gt;&gt; 12); 
    return h ^ (h &gt;&gt;&gt; 7) ^ (h &gt;&gt;&gt; 4); 
} 
</pre></td></tr></tbody></table><br />
<p>对于任意给定的对象，只要它的 hashCode() 返回值相同，那么程序调用 hash(int h) 方法所计算得到的 Hash 码值总是相同的。接下来程序会调用 indexFor(int h, int length) 方法来计算该对象应该保存在 table 数组的哪个索引处。indexFor(int h, int length) 方法的代码如下：</p>
<table cellspacing="0" cellpadding="0" width="100%" border="0" sizcache="2" sizset="3">
<tbody sizcache="1" sizset="3">
<tr>
<td class="code-outline"><pre class="displaycode">static int indexFor(int h, int length) 
{ 
    return h &amp; (length-1); 
}
</pre></td></tr></tbody></table><br />
<p>这个方法非常巧妙，它总是通过 h <code><font size="2">&amp;</font></code>(table.length -1) 来得到该对象的保存位置&#8212;&#8212;而 HashMap 底层数组的长度总是 2 的 n 次方，这一点可参看后面关于 HashMap 构造器的介绍。</p>
<p>当 length 总是 2 的倍数时，h <code><font size="2">&amp; (length-1)</font></code> <code><font size="2">将是一个非常巧妙的设计：假设 h=5,length=16, 那么 h &amp; length - 1 将得到 5；如果 h=6,length=16, 那么 h &amp; length - 1 将得到 6 &#8230;&#8230;如果 h=15,length=16, 那么 h &amp; length - 1 将得到 15；但是当 h=16 时 , length=16 时，那么 h &amp; length - 1 将得到 0 了；当 h=17 时 , length=16 时，那么 h &amp; length - 1 将得到 1 了&#8230;&#8230;这样保证计算得到的索引值总是位于 table 数组的索引之内。</font></code> </p>
<p>根据上面 put 方法的源代码可以看出，当程序试图将一个 key-value 对放入 HashMap 中时，程序首先根据该 key 的 hashCode() 返回值决定该 Entry 的存储位置：如果两个 Entry 的 key 的 hashCode() 返回值相同，那它们的存储位置相同。如果这两个 Entry 的 key 通过 equals 比较返回 true，新添加 Entry 的 value 将覆盖集合中原有 Entry 的 value，但 key 不会覆盖。如果这两个 Entry 的 key 通过 equals 比较返回 false，新添加的 Entry 将与集合中原有 Entry 形成 Entry 链，而且新添加的 Entry 位于 Entry 链的头部&#8212;&#8212;具体说明继续看 addEntry() 方法的说明。</p>
<p>当向 HashMap 中添加 key-value 对，由其 key 的 hashCode() 返回值决定该 key-value 对（就是 Entry 对象）的存储位置。当两个 Entry 对象的 key 的 hashCode() 返回值相同时，将由 key 通过 eqauls() 比较值决定是采用覆盖行为（返回 true），还是产生 Entry 链（返回 false）。</p>
<p>上面程序中还调用了 addEntry(hash, key, value, i); 代码，其中 addEntry 是 HashMap 提供的一个包访问权限的方法，该方法仅用于添加一个 key-value 对。下面是该方法的代码：</p>
<table cellspacing="0" cellpadding="0" width="100%" border="0" sizcache="2" sizset="4">
<tbody sizcache="1" sizset="4">
<tr>
<td class="code-outline"><pre class="displaycode">void addEntry(int hash, K key, V value, int bucketIndex) 
{ 
    // 获取指定 bucketIndex 索引处的 Entry 
    Entry&lt;K,V&gt; e = table[bucketIndex]; 	 // &#9312;
    // 将新创建的 Entry 放入 bucketIndex 索引处，并让新的 Entry 指向原来的 Entry 
    table[bucketIndex] = new Entry&lt;K,V&gt;(hash, key, value, e); 
    // 如果 Map 中的 key-value 对的数量超过了极限
    if (size++ &gt;= threshold) 
        // 把 table 对象的长度扩充到 2 倍。
        resize(2 * table.length); 	 // &#9313;
} 
</pre></td></tr></tbody></table><br />
<p>上面方法的代码很简单，但其中包含了一个非常优雅的设计：系统总是将新添加的 Entry 对象放入 table 数组的 bucketIndex 索引处&#8212;&#8212;如果 bucketIndex 索引处已经有了一个 Entry 对象，那新添加的 Entry 对象指向原有的 Entry 对象（产生一个 Entry 链），如果 bucketIndex 索引处没有 Entry 对象，也就是上面程序&#9312;号代码的 e 变量是 null，也就是新放入的 Entry 对象指向 null，也就是没有产生 Entry 链。</p>
<div class="ibm-alternate-rule">
<hr />
</div>
<p class="ibm-ind-link ibm-back-to-top" sizcache="25" sizset="81"><a class="ibm-anchor-up-link" href="http://www.ibm.com/developerworks/cn/java/j-lo-hash/#ibm-pcon"><font color="#996699"><strong>回页首</strong></font></a></p>
<p sizcache="25" sizset="82"><a name="major3"><span class="atitle"><strong><font size="5">Hash 算法的性能选项</font></strong></span></a></p>
<p>根据上面代码可以看出，在同一个 bucket 存储 Entry 链的情况下，新放入的 Entry 总是位于 bucket 中，而最早放入该 bucket 中的 Entry 则位于这个 Entry 链的最末端。</p>
<p>上面程序中还有这样两个变量：</p>
<ul><li>size：该变量保存了该 HashMap 中所包含的 key-value 对的数量。</li><li>threshold：该变量包含了 HashMap 能容纳的 key-value 对的极限，它的值等于 HashMap 的容量乘以负载因子（load factor）。 </li></ul>
<p>从上面程序中&#9313;号代码可以看出，当 size++ &gt;= threshold 时，HashMap 会自动调用 resize 方法扩充 HashMap 的容量。每扩充一次，HashMap 的容量就增大一倍。</p>
<p>上面程序中使用的 table 其实就是一个普通数组，每个数组都有一个固定的长度，这个数组的长度就是 HashMap 的容量。HashMap 包含如下几个构造器：</p>
<ul><li>HashMap()：构建一个初始容量为 16，负载因子为 0.75 的 HashMap。</li><li>HashMap(int initialCapacity)：构建一个初始容量为 initialCapacity，负载因子为 0.75 的 HashMap。</li><li>HashMap(int initialCapacity, float loadFactor)：以指定初始容量、指定的负载因子创建一个 HashMap。 </li></ul>
<p>当创建一个 HashMap 时，系统会自动创建一个 table 数组来保存 HashMap 中的 Entry，下面是 HashMap 中一个构造器的代码：</p>
<table cellspacing="0" cellpadding="0" width="100%" border="0" sizcache="2" sizset="5">
<tbody sizcache="1" sizset="5">
<tr>
<td class="code-outline"><pre class="displaycode"> // 以指定初始化容量、负载因子创建 HashMap 
 public HashMap(int initialCapacity, float loadFactor) 
 { 
	 // 初始容量不能为负数
	 if (initialCapacity &lt; 0) 
		 throw new IllegalArgumentException( 
		"Illegal initial capacity: " + 
			 initialCapacity); 
	 // 如果初始容量大于最大容量，让出示容量
	 if (initialCapacity &gt; MAXIMUM_CAPACITY) 
		 initialCapacity = MAXIMUM_CAPACITY; 
	 // 负载因子必须大于 0 的数值
	 if (loadFactor &lt;= 0 || Float.isNaN(loadFactor)) 
		 throw new IllegalArgumentException( 
		 loadFactor); 
	 // 计算出大于 initialCapacity 的最小的 2 的 n 次方值。
	 int capacity = 1; 
	 while (capacity &lt; initialCapacity) 
		 capacity &lt;&lt;= 1; 
	 this.loadFactor = loadFactor; 
	 // 设置容量极限等于容量 * 负载因子
	 threshold = (int)(capacity * loadFactor); 
	 // 初始化 table 数组
	 table = new Entry[capacity]; 			 // &#9312;
	 init(); 
 } 
</pre></td></tr></tbody></table><br />
<p>上面代码中粗体字代码包含了一个简洁的代码实现：找出大于 initialCapacity 的、最小的 2 的 n 次方值，并将其作为 HashMap 的实际容量（由 capacity 变量保存）。例如给定 initialCapacity 为 10，那么该 HashMap 的实际容量就是 16。</p>
<div class="ibm-container ibm-alt-header dw-container-sidebar" sizcache="25" sizset="83"><a name="sidebar3"></a>
<h2>initialCapacity 与 HashTable 的容量</h2>
<div class="ibm-container-body">
<p>创建 HashMap 时指定的 initialCapacity 并不等于 HashMap 的实际容量，通常来说，HashMap 的实际容量总比 initialCapacity 大一些，除非我们指定的 initialCapacity 参数值恰好是 2 的 n 次方。当然，掌握了 HashMap 容量分配的知识之后，应该在创建 HashMap 时将 initialCapacity 参数值指定为 2 的 n 次方，这样可以减少系统的计算开销。</p></div></div>
<p>程序&#9312;号代码处可以看到：table 的实质就是一个数组，一个长度为 capacity 的数组。</p>
<p>对于 HashMap 及其子类而言，它们采用 Hash 算法来决定集合中元素的存储位置。当系统开始初始化 HashMap 时，系统会创建一个长度为 capacity 的 Entry 数组，这个数组里可以存储元素的位置被称为&#8220;桶（bucket）&#8221;，每个 bucket 都有其指定索引，系统可以根据其索引快速访问该 bucket 里存储的元素。</p>
<p>无论何时，HashMap 的每个&#8220;桶&#8221;只存储一个元素（也就是一个 Entry），由于 Entry 对象可以包含一个引用变量（就是 Entry 构造器的的最后一个参数）用于指向下一个 Entry，因此可能出现的情况是：HashMap 的 bucket 中只有一个 Entry，但这个 Entry 指向另一个 Entry &#8212;&#8212;这就形成了一个 Entry 链。如图 1 所示：</p><br /><a name="fig1"><strong><font face="Arial" size="2">图 1. HashMap 的存储示意</font></strong></a><br /><font face="Arial" size="2"><img height="240" alt="图 1. HashMap 的存储示意" src="http://www.ibm.com/developerworks/cn/java/j-lo-hash/image001.jpg" width="486" /></font> <br />
<div class="ibm-alternate-rule">
<hr />
</div>
<p class="ibm-ind-link ibm-back-to-top" sizcache="25" sizset="85"><a class="ibm-anchor-up-link" href="http://www.ibm.com/developerworks/cn/java/j-lo-hash/#ibm-pcon"><font color="#996699"><strong>回页首</strong></font></a></p>
<p sizcache="25" sizset="86"><a name="major4"><span class="atitle"><strong><font size="5">HashMap 的读取实现</font></strong></span></a></p>
<p>当 HashMap 的每个 bucket 里存储的 Entry 只是单个 Entry &#8212;&#8212;也就是没有通过指针产生 Entry 链时，此时的 HashMap 具有最好的性能：当程序通过 key 取出对应 value 时，系统只要先计算出该 key 的 hashCode() 返回值，在根据该 hashCode 返回值找出该 key 在 table 数组中的索引，然后取出该索引处的 Entry，最后返回该 key 对应的 value 即可。看 HashMap 类的 get(K key) 方法代码：</p>
<table cellspacing="0" cellpadding="0" width="100%" border="0" sizcache="2" sizset="6">
<tbody sizcache="1" sizset="6">
<tr>
<td class="code-outline"><pre class="displaycode"> public V get(Object key) 
 { 
	 // 如果 key 是 null，调用 getForNullKey 取出对应的 value 
	 if (key == null) 
		 return getForNullKey(); 
	 // 根据该 key 的 hashCode 值计算它的 hash 码
	 int hash = hash(key.hashCode()); 
	 // 直接取出 table 数组中指定索引处的值，
	 for (Entry&lt;K,V&gt; e = table[indexFor(hash, table.length)]; 
		 e != null; 
		 // 搜索该 Entry 链的下一个 Entr 
		 e = e.next) 		 // &#9312;
	 { 
		 Object k; 
		 // 如果该 Entry 的 key 与被搜索 key 相同
		 if (e.hash == hash &amp;&amp; ((k = e.key) == key 
			 || key.equals(k))) 
			 return e.value; 
	 } 
	 return null; 
 } 
</pre></td></tr></tbody></table><br />
<p>从上面代码中可以看出，如果 HashMap 的每个 bucket 里只有一个 Entry 时，HashMap 可以根据索引、快速地取出该 bucket 里的 Entry；在发生&#8220;Hash 冲突&#8221;的情况下，单个 bucket 里存储的不是一个 Entry，而是一个 Entry 链，系统只能必须按顺序遍历每个 Entry，直到找到想搜索的 Entry 为止&#8212;&#8212;如果恰好要搜索的 Entry 位于该 Entry 链的最末端（该 Entry 是最早放入该 bucket 中），那系统必须循环到最后才能找到该元素。</p>
<p>归纳起来简单地说，HashMap 在底层将 key-value 当成一个整体进行处理，这个整体就是一个 Entry 对象。HashMap 底层采用一个 Entry[] 数组来保存所有的 key-value 对，当需要存储一个 Entry 对象时，会根据 Hash 算法来决定其存储位置；当需要取出一个 Entry 时，也会根据 Hash 算法找到其存储位置，直接取出该 Entry。由此可见：HashMap 之所以能快速存、取它所包含的 Entry，完全类似于现实生活中母亲从小教我们的：不同的东西要放在不同的位置，需要时才能快速找到它。</p>
<p>当创建 HashMap 时，有一个默认的负载因子（load factor），其默认值为 0.75，这是时间和空间成本上一种折衷：增大负载因子可以减少 Hash 表（就是那个 Entry 数组）所占用的内存空间，但会增加查询数据的时间开销，而查询是最频繁的的操作（HashMap 的 get() 与 put() 方法都要用到查询）；减小负载因子会提高数据查询的性能，但会增加 Hash 表所占用的内存空间。</p>
<p>掌握了上面知识之后，我们可以在创建 HashMap 时根据实际需要适当地调整 load factor 的值；如果程序比较关心空间开销、内存比较紧张，可以适当地增加负载因子；如果程序比较关心时间开销，内存比较宽裕则可以适当的减少负载因子。通常情况下，程序员无需改变负载因子的值。</p>
<p>如果开始就知道 HashMap 会保存多个 key-value 对，可以在创建时就使用较大的初始化容量，如果 HashMap 中 Entry 的数量一直不会超过极限容量（capacity * load factor），HashMap 就无需调用 resize() 方法重新分配 table 数组，从而保证较好的性能。当然，开始就将初始容量设置太高可能会浪费空间（系统需要创建一个长度为 capacity 的 Entry 数组），因此创建 HashMap 时初始化容量设置也需要小心对待。</p>
<div class="ibm-alternate-rule">
<hr />
</div>
<p class="ibm-ind-link ibm-back-to-top" sizcache="25" sizset="87"><a class="ibm-anchor-up-link" href="http://www.ibm.com/developerworks/cn/java/j-lo-hash/#ibm-pcon"><font color="#996699"><strong>回页首</strong></font></a></p>
<p sizcache="25" sizset="88"><a name="major5"><span class="atitle"><strong><font size="5">HashSet 的实现</font></strong></span></a></p>
<p>对于 HashSet 而言，它是基于 HashMap 实现的，HashSet 底层采用 HashMap 来保存所有元素，因此 HashSet 的实现比较简单，查看 HashSet 的源代码，可以看到如下代码：</p>
<table cellspacing="0" cellpadding="0" width="100%" border="0" sizcache="2" sizset="7">
<tbody sizcache="1" sizset="7">
<tr>
<td class="code-outline"><pre class="displaycode"> public class HashSet&lt;E&gt; 
	 extends AbstractSet&lt;E&gt; 
	 implements Set&lt;E&gt;, Cloneable, java.io.Serializable 
 { 
	 // 使用 HashMap 的 key 保存 HashSet 中所有元素
	 private transient HashMap&lt;E,Object&gt; map; 
	 // 定义一个虚拟的 Object 对象作为 HashMap 的 value 
	 private static final Object PRESENT = new Object(); 
	 ... 
	 // 初始化 HashSet，底层会初始化一个 HashMap 
	 public HashSet() 
	 { 
		 map = new HashMap&lt;E,Object&gt;(); 
	 } 
	 // 以指定的 initialCapacity、loadFactor 创建 HashSet 
	 // 其实就是以相应的参数创建 HashMap 
	 public HashSet(int initialCapacity, float loadFactor) 
	 { 
		 map = new HashMap&lt;E,Object&gt;(initialCapacity, loadFactor); 
	 } 
	 public HashSet(int initialCapacity) 
	 { 
		 map = new HashMap&lt;E,Object&gt;(initialCapacity); 
	 } 
	 HashSet(int initialCapacity, float loadFactor, boolean dummy) 
	 { 
		 map = new LinkedHashMap&lt;E,Object&gt;(initialCapacity 
			 , loadFactor); 
	 } 
	 // 调用 map 的 keySet 来返回所有的 key 
	 public Iterator&lt;E&gt; iterator() 
	 { 
		 return map.keySet().iterator(); 
	 } 
	 // 调用 HashMap 的 size() 方法返回 Entry 的数量，就得到该 Set 里元素的个数
	 public int size() 
	 { 
		 return map.size(); 
	 } 
	 // 调用 HashMap 的 isEmpty() 判断该 HashSet 是否为空，
	 // 当 HashMap 为空时，对应的 HashSet 也为空
	 public boolean isEmpty() 
	 { 
		 return map.isEmpty(); 
	 } 
	 // 调用 HashMap 的 containsKey 判断是否包含指定 key 
	 //HashSet 的所有元素就是通过 HashMap 的 key 来保存的
	 public boolean contains(Object o) 
	 { 
		 return map.containsKey(o); 
	 } 
	 // 将指定元素放入 HashSet 中，也就是将该元素作为 key 放入 HashMap 
	 public boolean add(E e) 
	 { 
		 return map.put(e, PRESENT) == null; 
	 } 
	 // 调用 HashMap 的 remove 方法删除指定 Entry，也就删除了 HashSet 中对应的元素
	 public boolean remove(Object o) 
	 { 
		 return map.remove(o)==PRESENT; 
	 } 
	 // 调用 Map 的 clear 方法清空所有 Entry，也就清空了 HashSet 中所有元素
	 public void clear() 
	 { 
		 map.clear(); 
	 } 
	 ... 
 } 
</pre></td></tr></tbody></table><br />
<p>由上面源程序可以看出，HashSet 的实现其实非常简单，它只是封装了一个 HashMap 对象来存储所有的集合元素，所有放入 HashSet 中的集合元素实际上由 HashMap 的 key 来保存，而 HashMap 的 value 则存储了一个 PRESENT，它是一个静态的 Object 对象。</p>
<p>HashSet 的绝大部分方法都是通过调用 HashMap 的方法来实现的，因此 HashSet 和 HashMap 两个集合在实现本质上是相同的。</p>
<div class="ibm-container ibm-alt-header dw-container-sidebar" sizcache="25" sizset="89"><a name="sidebar4"></a>
<h2>HashMap 的 put 与 HashSet 的 add</h2>
<div class="ibm-container-body">
<p>由于 HashSet 的 add() 方法添加集合元素时实际上转变为调用 HashMap 的 put() 方法来添加 key-value 对，当新放入 HashMap 的 Entry 中 key 与集合中原有 Entry 的 key 相同（hashCode() 返回值相等，通过 equals 比较也返回 true），新添加的 Entry 的 value 将覆盖原来 Entry 的 value，但 key 不会有任何改变，因此如果向 HashSet 中添加一个已经存在的元素，新添加的集合元素（底层由 HashMap 的 key 保存）不会覆盖已有的集合元素。</p></div></div>
<p>掌握上面理论知识之后，接下来看一个示例程序，测试一下自己是否真正掌握了 HashMap 和 HashSet 集合的功能。</p>
<table cellspacing="0" cellpadding="0" width="60%" border="0" sizcache="2" sizset="8">
<tbody sizcache="1" sizset="8">
<tr>
<td class="code-outline"><pre class="displaycode"> class Name
{
    private String first; 
    private String last; 
    
    public Name(String first, String last) 
    { 
        this.first = first; 
        this.last = last; 
    } 

    public boolean equals(Object o) 
    { 
        if (this == o) 
        { 
            return true; 
        } 
        
	if (o.getClass() == Name.class) 
        { 
            Name n = (Name)o; 
            return n.first.equals(first) 
                &amp;&amp; n.last.equals(last); 
        } 
        return false; 
    } 
}

public class HashSetTest
{
    public static void main(String[] args)
    { 
        Set&lt;Name&gt; s = new HashSet&lt;Name&gt;();
        s.add(new Name("abc", "123"));
        System.out.println(
            s.contains(new Name("abc", "123")));
    }
} 
</pre></td></tr></tbody></table><br />
<p>上面程序中向 HashSet 里添加了一个 new Name("abc", "123") 对象之后，立即通过程序判断该 HashSet 是否包含一个 new Name("abc", "123") 对象。粗看上去，很容易以为该程序会输出 true。</p>
<p>实际运行上面程序将看到程序输出 false，这是因为 HashSet 判断两个对象相等的标准除了要求通过 equals() 方法比较返回 true 之外，还要求两个对象的 hashCode() 返回值相等。而上面程序没有重写 Name 类的 hashCode() 方法，两个 Name 对象的 hashCode() 返回值并不相同，因此 HashSet 会把它们当成 2 个对象处理，因此程序返回 false。</p>
<p>由此可见，当我们试图把某个类的对象当成 HashMap 的 key，或试图将这个类的对象放入 HashSet 中保存时，重写该类的 equals(Object obj) 方法和 hashCode() 方法很重要，而且这两个方法的返回值必须保持一致：当该类的两个的 hashCode() 返回值相同时，它们通过 equals() 方法比较也应该返回 true。通常来说，所有参与计算 hashCode() 返回值的关键属性，都应该用于作为 equals() 比较的标准。</p>
<div class="ibm-container ibm-alt-header dw-container-sidebar" sizcache="25" sizset="90"><a name="sidebar5"></a>
<h2>hashCode() 和 equals()</h2>
<div class="ibm-container-body">
<p>关于如何正确地重写某个类的 hashCode() 方法和 equals() 方法，请参考疯狂 Java 体系的《疯狂 Java 讲义》一书中相关内容。</p></div></div>
<p>如下程序就正确重写了 Name 类的 hashCode() 和 equals() 方法，程序如下：</p>
<table cellspacing="0" cellpadding="0" width="60%" border="0" sizcache="2" sizset="9">
<tbody sizcache="1" sizset="9">
<tr>
<td class="code-outline"><pre class="displaycode">class Name 
{ 
    private String first;
    private String last;
    public Name(String first, String last)
    { 
        this.first = first; 
        this.last = last; 
    } 
    // 根据 first 判断两个 Name 是否相等
    public boolean equals(Object o) 
    { 
        if (this == o) 
        { 
            return true; 
        } 
        if (o.getClass() == Name.class) 
        { 
            Name n = (Name)o; 
            return n.first.equals(first); 
        } 
        return false; 
    } 
	 
    // 根据 first 计算 Name 对象的 hashCode() 返回值
    public int hashCode() 
    { 
        return first.hashCode(); 
    }

    public String toString() 
    { 
        return "Name[first=" + first + ", last=" + last + "]"; 
    } 
 } 
 
 public class HashSetTest2 
 { 
    public static void main(String[] args) 
    { 
        HashSet&lt;Name&gt; set = new HashSet&lt;Name&gt;(); 
        set.add(new Name("abc" , "123")); 
        set.add(new Name("abc" , "456")); 
        System.out.println(set); 
    } 
}
</pre></td></tr></tbody></table><br />
<p>上面程序中提供了一个 Name 类，该 Name 类重写了 equals() 和 toString() 两个方法，这两个方法都是根据 Name 类的 first 实例变量来判断的，当两个 Name 对象的 first 实例变量相等时，这两个 Name 对象的 hashCode() 返回值也相同，通过 equals() 比较也会返回 true。</p>
<p>程序主方法先将第一个 Name 对象添加到 HashSet 中，该 Name 对象的 first 实例变量值为"abc"，接着程序再次试图将一个 first 为"abc"的 Name 对象添加到 HashSet 中，很明显，此时没法将新的 Name 对象添加到该 HashSet 中，因为此处试图添加的 Name 对象的 first 也是" abc"，HashSet 会判断此处新增的 Name 对象与原有的 Name 对象相同，因此无法添加进入，程序在&#9312;号代码处输出 set 集合时将看到该集合里只包含一个 Name 对象，就是第一个、last 为"123"的 Name 对象。</p><img src ="http://www.blogjava.net/hao446tian/aggbug/362018.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hao446tian/" target="_blank">昊天</a> 2011-10-25 16:37 <a href="http://www.blogjava.net/hao446tian/archive/2011/10/25/362018.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java annotation 自定义注释@interface的用法 </title><link>http://www.blogjava.net/hao446tian/archive/2011/10/25/361960.html</link><dc:creator>昊天</dc:creator><author>昊天</author><pubDate>Tue, 25 Oct 2011 02:07:00 GMT</pubDate><guid>http://www.blogjava.net/hao446tian/archive/2011/10/25/361960.html</guid><wfw:comment>http://www.blogjava.net/hao446tian/comments/361960.html</wfw:comment><comments>http://www.blogjava.net/hao446tian/archive/2011/10/25/361960.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hao446tian/comments/commentRss/361960.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hao446tian/services/trackbacks/361960.html</trackback:ping><description><![CDATA[一、什么是注释 <br /><br />&nbsp;&nbsp;&nbsp; 说起注释，得先提一提什么是元数据(metadata)。所谓元数据就是数据的数据。也就是说，元数据是描述数据的。就象数据表中的字段一样，每个字段描述了这个字段下的数据的含义。而J2SE5.0中提供的注释就是java源代码的元数据，也就是说注释是描述java源代码的。在J2SE5.0中可以自定义注释。使用时在@后面跟注释的名字。 <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />二、J2SE5.0中预定义的注释 <br /><br />&nbsp;&nbsp;&nbsp; 在J2SE5.0的java.lang包中预定义了三个注释。它们是Override、Deprecated和SuppressWarnings。下面分别解释它们的含义。 <br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.Override注释：仅用于方法（不可用于类、包的生命或其他），指明注释的方法将覆盖超类中的方法（如果覆盖父类的方法而没有注 <br />释就无法编译该类），注释还能确保注释父类方法的拼写是正确（错误的编写，编译器不认为是子类的新方法，而会报错） <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.@Deprecated注释：对不应再使用的方法进行注释，与正在声明为过时的方法放在同一行。使用被&nbsp;&nbsp;&nbsp;&nbsp; Deprecated注释的方法，编译器会 <br />提示方法过时警告（&#8221;Warring&#8221;） <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3.@SuppressWarnings注释：单一注释，可以通过数组提供变量，变量值指明要阻止的特定类型警告（忽略某些警告）。数组中的变量指明要阻止的警告@SuppressWarnings(value={&#8221;unchecked&#8221;,&#8221;fallthrough&#8221;})） <br /><br />三、自定义注释@interface <br /><br />@interface：注释声明，定义注释类型（与默认的Override等三种注释类型类似)。请看下面实例： <br /><br />注释类1： <br /><br />package a.test; <br /><br />import java.lang.annotation.Documented; <br />import java.lang.annotation.ElementType; <br />import java.lang.annotation.Retention; <br />import java.lang.annotation.RetentionPolicy; <br />import java.lang.annotation.Target; <br /><br />@Documented <br />@Retention(RetentionPolicy.RUNTIME) <br />@Target(ElementType.TYPE) <br />public @interface FirstAnno { <br />String value() default "FirstAnno"; <br />} <br /><br />注释类2： <br /><br />package a.test; <br /><br />import java.lang.annotation.Documented; <br />import java.lang.annotation.ElementType; <br />import java.lang.annotation.Retention; <br />import java.lang.annotation.RetentionPolicy; <br />import java.lang.annotation.Target; <br /><br />@Documented <br />@Retention(RetentionPolicy.RUNTIME) <br />@Target(ElementType.METHOD) <br />public @interface SecondAnnotation { <br />//&nbsp; 注释中含有两个参数 <br />&nbsp;&nbsp;&nbsp; String name() default "Hrmzone"; <br />&nbsp;&nbsp;&nbsp; String url() default "hrmzone.cn"; <br /><br />} <br /><br />注释类3： <br /><br />package a.test; <br /><br />import java.lang.annotation.Documented; <br />import java.lang.annotation.ElementType; <br />import java.lang.annotation.Retention; <br />import java.lang.annotation.RetentionPolicy; <br />import java.lang.annotation.Target; <br /><br />@Documented <br />@Retention(RetentionPolicy.RUNTIME) <br />@Target(ElementType.FIELD) <br />public @interface Kitto { <br />String value() default "kitto"; <br />} <br /><br />使用类： <br /><br />package a.test; <br />@FirstAnno("http://hrmzone.cn") <br />public class Anno { <br />@Kitto("测试") <br />private String test = ""; <br />//&nbsp; 不赋值注释中的参数，使用默认参数 <br />&nbsp;&nbsp;&nbsp; @SecondAnnotation() <br />&nbsp;&nbsp;&nbsp; public String getDefault() { <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return "get default Annotation"; <br />&nbsp;&nbsp;&nbsp; } <br />&nbsp;&nbsp;&nbsp; @SecondAnnotation(name="desktophrm",url="desktophrm.com") <br />&nbsp;&nbsp;&nbsp; public String getDefine() { <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return "get define Annotation"; <br />&nbsp;&nbsp;&nbsp; } <br /><br />} <br /><br />测试类： <br /><br />package a.test; <br /><br />import java.lang.reflect.Field; <br />import java.lang.reflect.Method; <br />import java.util.ArrayList; <br />import java.util.List; <br /><br />public class AnnoTest { <br />public static void main(String[] args) throws ClassNotFoundException { <br />&nbsp; // 要使用到反射中的相关内容 <br />&nbsp; Class c = Class.forName("a.test.Anno"); <br />&nbsp; Method[] method = c.getMethods(); <br />&nbsp; boolean flag = c.isAnnotationPresent(FirstAnno.class); <br />&nbsp; if (flag) { <br />&nbsp;&nbsp; FirstAnno first = (FirstAnno) c.getAnnotation(FirstAnno.class); <br />&nbsp;&nbsp; System.out.println("First Annotation:" + first.value() + "\n"); <br />&nbsp; } <br /><br />&nbsp; List&lt;Method&gt; list = new ArrayList&lt;Method&gt;(); <br />&nbsp; for (int i = 0; i &lt; method.length; i++) { <br />&nbsp;&nbsp;&nbsp; list.add(method[i]); <br />&nbsp; } <br /><br />&nbsp; for (Method m : list) { <br />&nbsp;&nbsp; SecondAnnotation anno = m.getAnnotation(SecondAnnotation.class); <br />&nbsp;&nbsp; if(anno == null) <br />&nbsp;&nbsp;&nbsp; continue; <br />&nbsp;&nbsp; <br />&nbsp;&nbsp; System.out.println("second annotation's\nname:\t" + anno.name() <br />&nbsp;&nbsp;&nbsp;&nbsp; + "\nurl:\t" + anno.url()); <br />&nbsp; } <br />&nbsp; <br />&nbsp; List&lt;Field&gt; fieldList = new ArrayList&lt;Field&gt;(); <br />&nbsp; for(Field f : c.getDeclaredFields()){//访问所有字段 <br />&nbsp;&nbsp; Kitto k = f.getAnnotation(Kitto.class); <br />&nbsp;&nbsp; System.out.println("----kitto anno: " + k.value()); <br />&nbsp; } <br />} <br /><br />} <br /><br /><br />结合源文件中注释，想必对注释的应用有所了解。下面深入了解。 <br />&nbsp;&nbsp;&nbsp;&nbsp; 深入注释： <br />&nbsp;&nbsp;&nbsp;&nbsp; @Target:指定程序元定义的注释所使用的地方，它使用了另一个类：ElementType，是一个枚举类定义了注释类型可以应用到不同的程序元素以免使用者误用。看看java.lang.annotation 下的源代码： <br /><br />@Documented&nbsp; <br />@Retention(RetentionPolicy.RUNTIME)&nbsp; <br />@Target(ElementType.ANNOTATION_TYPE)&nbsp; <br />public @interface Target {&nbsp; <br />&nbsp;&nbsp;&nbsp; ElementType[] value();&nbsp; <br />} <br /><br /><br />&nbsp;&nbsp;&nbsp;&nbsp; ElementType是一个枚举类型，指明注释可以使用的地方，看看ElementType类： <br />public enum ElementType {&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp; TYPE, // 指定适用点为 class, interface, enum&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp; FIELD, // 指定适用点为 field&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp; METHOD, // 指定适用点为 method&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp; PARAMETER, // 指定适用点为 method 的 parameter&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp; CONSTRUCTOR, // 指定适用点为 constructor&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp; LOCAL_VARIABLE, // 指定使用点为 局部变量&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp; ANNOTATION_TYPE, //指定适用点为 annotation 类型&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp; PACKAGE // 指定适用点为 package&nbsp; <br />} <br />&nbsp;&nbsp;&nbsp;&nbsp; @Retention：这个元注释和java编译器处理注释的注释类型方式相关，告诉编译器在处理自定义注释类型的几种不同的选择，需要使用RetentionPolicy枚举类。此枚举类只有一个成员变量，可以不用指明成名名称而赋值，看Retention的源代码： <br /><br />@Documented&nbsp; <br />@Retention(RetentionPolicy.RUNTIME)&nbsp; <br />@Target(ElementType.ANNOTATION_TYPE)&nbsp; <br />public @interface Retention {&nbsp; <br />&nbsp;&nbsp;&nbsp; RetentionPolicy value();&nbsp; <br />} <br />&nbsp;&nbsp;&nbsp;&nbsp; 类中有个RetentionPolicy类，也是一个枚举类，具体看代码： <br /><br />public enum RetentionPolicy {&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp; SOURCE, // 编译器处理完Annotation后不存储在class中&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp; CLASS, // 编译器把Annotation存储在class中，这是默认值&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp; RUNTIME // 编译器把Annotation存储在class中，可以由虚拟机读取,反射需要&nbsp; <br />} <br />&nbsp;&nbsp;&nbsp;&nbsp; @Documented：是一个标记注释，表示注释应该出现在类的javadoc中，因为在默认情况下注释时不包括在javadoc中的。 <br /><br />所以如果花费了大量的时间定义一个注释类型，并想描述注释类型的作用，可以使用它。 <br /><br />注意他与@Retention(RetentionPolicy.RUNTIME)配合使用，因为只有将注释保留在编译后的类文件中由虚拟机加载， <br /><br />然后javadoc才能将其抽取出来添加至javadoc中。 <br />&nbsp;&nbsp;&nbsp;&nbsp; @Inherited：将注释同样继承至使用了该注释类型的方法中（表达有点问题，就是如果一个方法使用了的注释用了@inherited， <br /><br />那么其子类的该方法同样继承了该注释） <br />注意事项： <br />&nbsp;&nbsp;&nbsp;&nbsp; 1.所有的Annotation自动继承java.lang.annotation接口 <br />&nbsp;&nbsp;&nbsp;&nbsp; 2.自定义注释的成员变量访问类型只能是public、default；(所有的都能访问，源作者没用到函数：getDeclaredFields而已) <br />&nbsp;&nbsp;&nbsp;&nbsp; 3.成员变量的只能使用基本类型（byte、short、int、char、long、double、float、boolean和String、Enum、Class、annotations以及该类型的数据）(没有限制，大家可以修改测试一下，就清楚) <br />&nbsp;&nbsp;&nbsp;&nbsp; 4.如果只有一个成员变量，最好将参数名称设为value，赋值时不用制定名称而直接赋值 <br />&nbsp;&nbsp;&nbsp;&nbsp; 5.在实际应用中，还可以使用注释读取和设置Bean中的变量。 <img src ="http://www.blogjava.net/hao446tian/aggbug/361960.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hao446tian/" target="_blank">昊天</a> 2011-10-25 10:07 <a href="http://www.blogjava.net/hao446tian/archive/2011/10/25/361960.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>eXtremeComponents参考文档</title><link>http://www.blogjava.net/hao446tian/archive/2011/09/28/359701.html</link><dc:creator>昊天</dc:creator><author>昊天</author><pubDate>Wed, 28 Sep 2011 07:35:00 GMT</pubDate><guid>http://www.blogjava.net/hao446tian/archive/2011/09/28/359701.html</guid><wfw:comment>http://www.blogjava.net/hao446tian/comments/359701.html</wfw:comment><comments>http://www.blogjava.net/hao446tian/archive/2011/09/28/359701.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hao446tian/comments/commentRss/359701.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hao446tian/services/trackbacks/359701.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: Jeff Johnston版本1.0.0本文档允许在遵守以下两条原则的条件下被使用和传播： 1）不能凭借本文档索取任何费用 2）以任何方式（印刷物或电子版）使用和传播时本文档时，必须包含本版权申明 (更新中...)Table of Contents&nbsp;前言eXtremeComponents是一系列提供高级显示的开源JSP定制标...&nbsp;&nbsp;<a href='http://www.blogjava.net/hao446tian/archive/2011/09/28/359701.html'>阅读全文</a><img src ="http://www.blogjava.net/hao446tian/aggbug/359701.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hao446tian/" target="_blank">昊天</a> 2011-09-28 15:35 <a href="http://www.blogjava.net/hao446tian/archive/2011/09/28/359701.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java之类加载机制</title><link>http://www.blogjava.net/hao446tian/archive/2011/03/14/346183.html</link><dc:creator>昊天</dc:creator><author>昊天</author><pubDate>Mon, 14 Mar 2011 01:49:00 GMT</pubDate><guid>http://www.blogjava.net/hao446tian/archive/2011/03/14/346183.html</guid><wfw:comment>http://www.blogjava.net/hao446tian/comments/346183.html</wfw:comment><comments>http://www.blogjava.net/hao446tian/archive/2011/03/14/346183.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hao446tian/comments/commentRss/346183.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hao446tian/services/trackbacks/346183.html</trackback:ping><description><![CDATA[<p>在java.lang包里有个ClassLoader类，ClassLoader 的基本目标是对类的请求提供服务，按需动态装载类和资<br />
源，只有当一个类要使用(使用new 关键字来实例化一个类)的时候，类加载器才会加载这个类并初始化。<br />
一个Java应用程序可以使用不同类型的类加载器。例如Web Application Server中，Servlet的加载使用开发<br />
商自定义的类加载器， java.lang.String在使用JVM系统加载器,Bootstrap Class Loader，开发商定义的其他类<br />
则由AppClassLoader加载。在JVM里由类名和类加载器区别不同的Java类型。因此，JVM允许我们使用不同<br />
的加载器加载相同namespace的java类，而实际上这些相同namespace的java类可以是完全不同的类。这种<br />
机制可以保证JDK自带的java.lang.String是唯一的。<br />
2. 加载类的两种方式：<br />
（1）&nbsp; 隐式方式<br />
使用new关键字让类加载器按需求载入所需的类<br />
（2）&nbsp; 显式方式<br />
由 java.lang.Class的forName()方法加载<br />
public static Class forName(String className)<br />
public static Class forName(String className, boolean initialize,ClassLoader loader)<br />
参数说明：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; className - 所需类的完全限定名<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; initialize - 是否必须初始化类(静态代码块的初始化)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; loader - 用于加载类的类加载器</p>
<p>调用只有一个参数的forName()方法等效于 Class.forName(className, true, loader)。<br />
这两个方法，最后都要连接到原生方法forName0()，其定义如下：<br />
private static native Class forName0(String name, boolean initialize,ClassLoader loader)<br />
&nbsp;throws ClassNotFoundException;<br />
只有一个参数的forName()方法，最后调用的是:<br />
forName0(className, true, ClassLoader.getCallerClassLoader());<br />
而三个参数的forName()，最后调用的是:<br />
forName0(name, initialize, loader);<br />
所以，不管使用的是new 來实例化某个类、或是使用只有一个参数的Class.forName()方法，内部都隐含<br />
了&#8220;载入类 ＋ 运行静态代码块&#8221;的步骤。而使用具有三个参数的Class.forName()方法时，如果第二个参数<br />
为false，那么类加载器只会加载类，而不会初始化静态代码块，只有当实例化这个类的时候，静态代码块<br />
才会被初始化，静态代码块是在类第一次实例化的时候才初始化的。<br />
直接使用类加载器<br />
获得对象所属的类 : getClass()方法<br />
获得该类的类加载器 : getClassLoader()方法<br />
3.执行java XXX.class的过程<br />
找到JRE——》找到jvm.dll——》启动JVM并进行初始化——》产生Bootstrap Loader——》<br />
载入ExtClassLoader——》载入AppClassLoader——》执行java XXX.class</p>
 <img src ="http://www.blogjava.net/hao446tian/aggbug/346183.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hao446tian/" target="_blank">昊天</a> 2011-03-14 09:49 <a href="http://www.blogjava.net/hao446tian/archive/2011/03/14/346183.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>