<?xml version="1.0" encoding="GBK" ?>
<rss version="2.0" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:dcterms="http://purl.org/dc/terms/">
 <channel>
  	  <title><![CDATA[路在脚下]]></title>
	  <link>http://blog.163.com/eric_wyf</link>
	  <description><![CDATA[ ]]></description>
	  <language>zh-CN</language>
	  <pubDate>Sat, 5 Jul 2008 13:01:27 +0800</pubDate>
	  <lastBuildDate>Sat, 5 Jul 2008 13:01:27 +0800</lastBuildDate>
	  <docs>http://blogs.law.harvard.edu/tech/rss</docs>
	  <generator><![CDATA[NetEase Space]]></generator>
	  <managingEditor><![CDATA[eric_wyf]]></managingEditor>
	  <webMaster><![CDATA[老王]]></webMaster>
		  <ttl>120</ttl>
	  <image>
	  	<title><![CDATA[路在脚下]]></title>
	  	<url>http://ava.blog.163.com/photo/MfOZ7ca3k3hQlovAze270w==/1422856007272445281.jpg</url>
	  	<link>http://blog.163.com/eric_wyf</link>
	  </image>
  <item>
  	<title><![CDATA[锐欧爆笑熄火广告]]></title>	
    <link>http://blog.163.com/eric_wyf/blog/static/2267217020082611821745</link>
    <description><![CDATA[<div><P style="TEXT-INDENT: 2em">熄我们的火，让别人等去吧</P>
<P style="TEXT-INDENT: 2em">联想：锐欧不再熄火，世界将会怎样？</P>
<P style="TEXT-INDENT: 2em">特步：熄火，非一般感觉。</P>
<P style="TEXT-INDENT: 2em">脑白金：今年开车不熄火，熄火只熄RIO。</P>
<P style="TEXT-INDENT: 2em">百事：熄火无极限。</P>
<P style="TEXT-INDENT: 2em">汇仁肾宝：他熄我也熄</P>
<P style="TEXT-INDENT: 2em">李宁：熄火,一切皆有可能</P>
<P style="TEXT-INDENT: 2em">旺旺：你熄,我熄,大家熄,旺旺</P>
<P style="TEXT-INDENT: 2em">好迪：大家熄，才是真的熄</P>
<P style="TEXT-INDENT: 2em">耐克：Just 熄 it！</P>
<P style="TEXT-INDENT: 2em">钙中钙：现在的锐欧啊，它含金量高，熄一次火顶过去五次，方便！你瞧我，一口气熄五次，不费劲！</P>
<P style="TEXT-INDENT: 2em">雀巢咖啡：次次熄火，意犹未尽～</P>
<P style="TEXT-INDENT: 2em">人头马XO：RIO一开，熄火自然来</P>
<P style="TEXT-INDENT: 2em">飞利浦：让我们熄的更好</P>
<P style="TEXT-INDENT: 2em"></P></div>]]></description>
	    <author><![CDATA[老王]]></author>
	    <comments>http://blog.163.com/eric_wyf/blog/static/2267217020082611821745</comments>
    <slash:comments>0</slash:comments>
    <guid isPermaLink="true">http://blog.163.com/eric_wyf/blog/static/2267217020082611821745</guid>
    <pubDate>Thu, 6 Mar 2008 13:18:21 +0800</pubDate>
    <dcterms:modified>2008-03-06T13:18:21+08:00</dcterms:modified>
  </item>    
  <item>
  	<title><![CDATA[P990的33条实用使用技巧]]></title>	
    <link>http://blog.163.com/eric_wyf/blog/static/22672170200791505638714</link>
    <description><![CDATA[<div><P style="TEXT-INDENT: 2em">1、全屏模式下怎么输入数字:第一种方法：手写，在右边黑色三角箭头的上方写数字。</P>
<P style="TEXT-INDENT: 2em">第二种方法：小键盘，配合alt键使用。</P>
<P style="TEXT-INDENT: 2em">2、外键盘模式的输入法切换方式 ：长按"＃"键切换中英文。在中文输入法的状态下，短按“*”键进行“笔画”、“拼音”、“数字123”的切换。</P>
<P style="TEXT-INDENT: 2em">3、使闪光灯长亮的方法：打开照相功能，打开闪光灯，轻按拍摄键使闪光灯变亮，此时转动滚轮切换为摄像模式，这样闪光灯可以长时间亮着。</P>
<P style="TEXT-INDENT: 2em">4、进入工程模式方法：用左侧的滚轮按上 * 下 下 * 下 * 或用外键盘右*左左*左*。(注意：工程模式不能查看通话时间！具体方法看NO.19)</P>
<P style="TEXT-INDENT: 2em">5、查看手机串号：*#06#。</P>
<P style="TEXT-INDENT: 2em">关于听筒声音过小的解决方法：进入工程模式，测试-扬声器，调到100%后退出。(注意！这种方法是在用滚轮调节不行的情况下再使用，一般打电话时用滚轮可以调节音量的大小，这种方法也不一定对所有的P990都适用。)</P>
<P style="TEXT-INDENT: 2em">6、P990拆了翻盖以后怎么看软件版本：按主菜单进菜单,在按屏目顶上的主菜单有个倒3角行,选择系统信息。</P>
<P style="TEXT-INDENT: 2em">7、如何看通话时间总计：合盖模式下按通话－更多－选择通话总计即可。</P>
<P style="TEXT-INDENT: 2em">8、如何把通讯录倒入大P中：同步或连接电脑通过pc suite for smartphones恢复。</P>
<P style="TEXT-INDENT: 2em">9、如何对通讯录进行备份：点击通讯录，点顶部向下箭头，选择备份(文件地址是在记忆棒的other---&gt;Backup---&gt;Contacts---&gt; "Contacts.</P>
<P style="TEXT-INDENT: 2em">vcf")或连接电脑通过pc suite for smartphones备份。</P>
<P style="TEXT-INDENT: 2em">10、如何去掉自动添加到通讯录的提示：控制面板－设备－通话设置－将添加到通讯录前的打勾去掉。</P>
<P style="TEXT-INDENT: 2em">11、如何将开机时的两个提示去掉：控制面板－设备－将Flight mode（关闭无线电）前的打勾去掉。</P>
<P style="TEXT-INDENT: 2em">12、如何卸载程序：控制面板－设备－其他－卸载。</P>
<P style="TEXT-INDENT: 2em">13、如何添加开机锁和自动键盘锁：控制面板－设备－安全性－锁。全球最大的索爱手机社区！</P>
<P style="TEXT-INDENT: 2em">14、如何开启前摄像头：进入菜单－电话－视频电话。</P>
<P style="TEXT-INDENT: 2em">15、如何安装主题：蓝牙、数据线、红外线、读卡器传到手机，点击即可。</P>
<P style="TEXT-INDENT: 2em">16、如何在编辑联系人中添加更多的信息：进入通讯录，选择对象，点击编辑联系人，点击顶部向下箭头，出现添加字段，根据自己的想法添加所要的信息即可。</P>
<P style="TEXT-INDENT: 2em">17、如何使用原机座充：可以用来充电，进行数据传输。</P>
<P style="TEXT-INDENT: 2em">18、如何使用录音功能：进入菜单－多媒体－录音机。注意：P990不支持通话中录音！</P>
<P style="TEXT-INDENT: 2em">19、如何对通讯录进行分组：进入菜单－点击右上角的图标－编辑文件夹－新建文件夹。这样就可以根据自己的情况进行分组。注意：P990不支持分组铃声，只能一个一个单独设置。可以进行拨打电话。</P>
<P style="TEXT-INDENT: 2em">20、如何对联系人进行群组分配：进入菜单－点击右上角的图标－新建群组。这样就可以根据自己的情况进行设置。注意：不能进行群组铃声设置，但可以群发短信。不能进行拨打电话。</P>
<P style="TEXT-INDENT: 2em">21、如何将菜单图标移动：进入任何一个子菜单，点击顶部的倒三角－设置文件夹－对你想要移动的图标进行编辑。注意：如果你将程序装在记忆卡中，图标在记忆卡拔出再插入后会回到最初安装的“工具”中。</P>
<P style="TEXT-INDENT: 2em">22、如何对合盖时的4个快捷图标进行编辑：合盖模式下点击“更多”－“快捷方式”－将“显示快捷方式图标”去钩，可以将图标隐藏。向上、向下、向左的三个图标可以进行替换。注意：开盖后的四个快捷图标目前是不能编辑的！</P>
<P style="TEXT-INDENT: 2em">23、如何查看手机版本信息：合盖模式下点击更多－状态即可。</P>
<P style="TEXT-INDENT: 2em">24、如何移动子菜单里的图标：进入菜单，点击上面向下的箭头，选择设置文件夹，找到你想要的程序移动即可。全球最大的索爱手机社区！</P>
<P style="TEXT-INDENT: 2em">25、如何解决java程序不能安装的情况：由于P990对中文名的JAVA支持度不好，所以将中文版名改为英文名（控制在8个字符以内）再安装。（此方法为解决JAVA不能安装的方法之一，也不一定能将所有有问题的java都解决）</P>
<P style="TEXT-INDENT: 2em">26、如何使待机画面清晰：用photoshop将你需要的待机画面保存为PNG格式或者保存为JPG格式的时候将效果拉到12最大值即可。</P>
<P style="TEXT-INDENT: 2em">27、如何将GPRS分离：控制面板－连接－互联网帐户－点击顶部向下箭头－选项－首选模式为“仅限CS”。</P>
<P style="TEXT-INDENT: 2em">28、P990支持的视频格式：MP4/3GP/WMV/AVI。</P>
<P style="TEXT-INDENT: 2em">29、如何取消USB充电情况：控制面板－连接－USB－将允许USB充电去钩即可。反之在连接会充电。</P>
<P style="TEXT-INDENT: 2em">30、如何进行图片浏览：进入菜单，点击多媒体，选择图片库，可以对手机内存和记忆卡里的图片进行浏览。</P>
<P style="TEXT-INDENT: 2em">31、如何将蓝牙传到手机的文件更改保存路径：如果是MP3或者是图片文件或文档文件蓝牙传完后不要马上点保存，直接点击打开，这是你会发现在下面有一个保存于的选项，你就可以保存到你想保存的目录了。程序文件不能进行这样的操作。</P>
<P style="TEXT-INDENT: 2em">32、如何删除安装好的主题：控制面板－设备－主题－选择你想删除的主题进入，点击顶部的箭头，选择删除即可。</P>
<P style="TEXT-INDENT: 2em">33、如何在通话中查询通讯录：在通话中点击这个图标，然后在出现的界面上选择通讯录就可以了。</P>
<P style="TEXT-INDENT: 2em"></P></div>]]></description>
	    <author><![CDATA[老王]]></author>
	    <comments>http://blog.163.com/eric_wyf/blog/static/22672170200791505638714</comments>
    <slash:comments>0</slash:comments>
    <guid isPermaLink="true">http://blog.163.com/eric_wyf/blog/static/22672170200791505638714</guid>
    <pubDate>Mon, 15 Oct 2007 12:56:38 +0800</pubDate>
    <dcterms:modified>2007-10-15T12:56:38+08:00</dcterms:modified>
  </item>    
  <item>
  	<title><![CDATA[P990一些选购指南，可供大家参考]]></title>	
    <link>http://blog.163.com/eric_wyf/blog/static/2267217020079110393451</link>
    <description><![CDATA[<div><P>第 1 步：当然是 看大 9 的外观了，看看有没有自己感觉不舒服的地方，比如说外壳有没有划痕之类的，然后，打开后盖看，仔细观察一下，螺丝有没有被拧过的痕迹，也就是螺母上的十字口应该是十分光滑的；电池和机器的触点上的触痕应该是很轻的，至于程度嘛，买之前打开自己的旧手机观察一下就知道了。然后在仔细看看主屏幕、镜头屏幕、有无划痕、指纹痕迹和表面上是否有灰尘，因为卖家卖的水货都是交钱后才给你看货的，所以，机器一般是没有人玩过的！&nbsp; 何况现在买大 9 的人很少，所以从外观上来说应该是极新的！&nbsp; 如果观察到有人玩过或者有硬伤，一个字，换！&nbsp; 要是 JS 说没货了，那就走人！&nbsp; sebbs.it168.com!Q4\%J'\5q,y'w </P>
<P>&nbsp;&nbsp;&nbsp; 第 2 步：经过初步的审查没问题后就可以放电池开机了，开机后首先就是区域和语言的设定，因为 SE 的机器只要换 SIM 卡就要重新设定地区和语言，所以不能凭语言和地区的设定来判断是否有人用过，开机后主要看的有如下几点： </P>
<P>&nbsp;&nbsp; 1 ：开机状态，开机过程有没有卡涩的现象， 首先屏幕亮度是否合格，如果在把亮度调到三分之二以上还感觉明显发暗，那说明液晶有问题，换一台吧！ )]'D s!e;G%_.k</P>
<P>&nbsp;&nbsp;&nbsp; 2 ：用左侧的滚轮和键盘按上 * 下 下 * 下 * 或用外键盘右*左左*左*进入工程模式，里面有服务信息和服务测试，在服务测试项目里几乎所有需要测试的项目都有了，耐下心一项一项的来，这一步是最关键的，一定要注意，屏幕测试时看清楚有没有坏点，震动是不是很沉稳的没有异常，剩下的就是键盘、收音机等等，最后，切记要看看通话总记，推荐在 .30 秒以内，时间太长的话肯定是别人用了！ </P>
<P>&amp;r'q#\$L#H(C#E&amp;c)U4C;F&nbsp;&nbsp;&nbsp; 3 ：在软件信息里，可以看到当前的机器软件版本，目前的机器几乎全是 R9EC001 的， 除此以外，我们还可以通过“ 系统资料 ” 来查询手机当前的软件信息，进入系统资料中可以看到软件版本为 R4B001 、 窗体顶端 窗体 蓝牙 R4F01 、个人助理 R1A14 以及 R1A51 的 CDA 等！ IT168索爱论坛)`.M!L8i;f/t&amp;X3w/d</P>
<P>　　第 3 步：连接耳机听音质，轻轻上下摇动耳机接口看有无声音断续；打个电话听听声音是否清晰，不要打 10086 、 112 之类的电话，最好打个 17951 的，不要怕花钱，因为 17951 的 IP 信号相对比较差，可以更好的测试话机的通话质量，记得带张自己的卡去（如果方便的话），放一放上面的歌，再检查一次耳机和扬声器，这里推荐一首歌：信乐团的死了都要爱（ 80 到 96 千比特 / 秒就可以了），这首歌是比较朋克的，如果把声音放到最大都没有暴音，那扬声器和耳机没问题了。呵呵 ~~~ 音乐方面没问题后，再来看看拍照：这里要注意的是打开镜头盖时，相机的启动速度，应该在将近一秒吧！ ~ 如果太慢那就不太好了，里面的功能就自己试咯！ ~ 包括辅助灯，视频什么的，只要硬件没问题就可以，软件上有问题的话那也不是 JS 的错，呵呵！ ~~ 以后还可以升级嘛！ -C!g$B"B1~3y1j5a</P>
<P>&nbsp;&nbsp;&nbsp; 第 4 步：清点配件，现在 JS 为了出货，现在降低了价格但是却黑掉一部分配件，这是 JS 惯用的伎俩，所以，大家一定要擦亮眼睛，目前的配件是： 一电 (950 毫安 bst-33) 一充 (cst-70) 一耳机 ( 同 K750/M600 等机的标配耳机 ) 两支笔一数据线 (dcu-60) 一带支架底座 (cds-60) 一张 sony 64 兆 msd 卡一 msd 转换卡一挂绳一螺丝刀一 PDA 挡板一光盘，缺一样都不对。 </P>
<P>第 5 步： 开票，要求写清 JS 7 天换机和一年保修，至于其他保修事项就看你怎么 JS 谈了，一般应该带终身免费刷机的服务的！<A href="mailto:6@'C!L8Z5@:x">6@'C!L8Z5@:x</A></P>
<P>&nbsp;&nbsp; 如果以上过程都顺利，在 7 天内多使用再看看有什么问题没有，没问题的话就一切 OK 了！&nbsp;&nbsp; 最后在提点建议：给你的大 P 买张好一点的面膜， 现在有大 P 专用的膜。<BR></P></div>]]></description>
	    <author><![CDATA[老王]]></author>
	    <comments>http://blog.163.com/eric_wyf/blog/static/2267217020079110393451</comments>
    <slash:comments>0</slash:comments>
    <guid isPermaLink="true">http://blog.163.com/eric_wyf/blog/static/2267217020079110393451</guid>
    <pubDate>Thu, 11 Oct 2007 12:39:34 +0800</pubDate>
    <dcterms:modified>2007-10-11T12:40:45+08:00</dcterms:modified>
  </item>    
  <item>
  	<title><![CDATA[IT人必读：写给浮躁的IT同仁]]></title>	
    <link>http://blog.163.com/eric_wyf/blog/static/22672170200791095340339</link>
    <description><![CDATA[<div><P style="TEXT-INDENT: 2em">1.不要看到别人的回复第一句话就说：给个代码吧！你应该想想为什么。当你自己想出来再参考别人的提示，你就知道自己和别人思路的差异。 </P>
<P style="TEXT-INDENT: 2em">2.初学者请不要看太多太多的书那会误人子弟的，先找本系统的学，很多人用了很久都是只对部分功能熟悉而已，不系统还是不够的。</P>
<P style="TEXT-INDENT: 2em">3.看帮助,不要因为很难而自己是初学者所以就不看；帮助永远是最好的参考手册，虽然帮助的文字有时候很难看懂，总觉得不够直观。</P>
<P style="TEXT-INDENT: 2em">4.不要被对象、属性、方法等词汇所迷惑；最根本的是先了解最基础知识。</P>
<P style="TEXT-INDENT: 2em">5.不要放过任何一个看上去很简单的小问题--他们往往并不那么简单，或者可以引伸出很多知识点；不会举一反三你就永远学不会。</P>
<P style="TEXT-INDENT: 2em">6.知道一点东西，并不能说明你会写脚本，<A href="http://www.it130.cn/">脚本</A>是需要经验积累的。</P>
<P style="TEXT-INDENT: 2em">7.学脚本并不难，JSP、ASP、PHP等等也不过如此--难的是长期坚持实践和不遗余力的博览群书。</P>
<P style="TEXT-INDENT: 2em">8.看再多的书是学不全脚本的，要多实践。</P>
<P style="TEXT-INDENT: 2em">9.把时髦的技术挂在嘴边，还不如把过时的技术记在心里。</P>
<P style="TEXT-INDENT: 2em">10.学习脚本最好的方法之一就是多练习。 </P>
<P style="TEXT-INDENT: 2em">11.在任何时刻都不要认为自己手中的书已经足够了。</P>
<P style="TEXT-INDENT: 2em">12.看得懂的书，请仔细看；看不懂的书，请硬着头皮看。</P>
<P style="TEXT-INDENT: 2em">13.别指望看第一遍书就能记住和掌握什么——请看第二遍、第三遍； </P>
<P style="TEXT-INDENT: 2em">14.请把书上的例子亲手到电脑上实践，即使配套光盘中有源文件；</P>
<P style="TEXT-INDENT: 2em">15.把在书中看到的有意义的例子扩充；并将其切实的运用到自己的工作中。 </P>
<P style="TEXT-INDENT: 2em">16.不要漏掉书中任何一个练习——请全部做完并记录下思路；</P>
<P style="TEXT-INDENT: 2em">17.当你用脚本到一半却发现自己用的方法很拙劣时，请不要马上停手；请尽快将余下的部分粗略的完成以保证这个代码的完整性，然后分析自己的错误并重新编写和工作。</P>
<P style="TEXT-INDENT: 2em">18.别心急，写脚本确实不容易；水平是在不断的实践中完善和发展的；</P>
<P style="TEXT-INDENT: 2em">19.每学到一个脚本难点的时候，尝试着对别人讲解这个知识点并让他理解----你能讲清楚才说明你真的理解了。 </P>
<P style="TEXT-INDENT: 2em">20.记录下在和别人交流时发现的自己忽视或不理解的知识点。 </P>
<P style="TEXT-INDENT: 2em">21.保存好你做过的所有的源文件----那是你最好的积累之一。</P>
<P style="TEXT-INDENT: 2em">22.对于网络，还是希望大家能多利用一下，很多问题不是非要到论坛来问的，首先你要学会自己找答案，比如google、百度都是很好的搜索引擎，你只要输入关键字就能找到很多相关资料，别老是等待别人给你希望，看的出你平时一定也很懒！ </P>
<P style="TEXT-INDENT: 2em">23.到一个论坛，你学会去看以前的帖子，不要什么都不看就发帖子问，也许你的问题早就有人问过了，你再问，别人已经不想再重复了，做为初学者，谁也不希望自己的帖子没人回的。 </P>
<P style="TEXT-INDENT: 2em">24，虽然不是打击初学者，但是这句话还是要说：论坛论坛，就是大家讨论的地方，如果你总期望有高手总无偿指点你，除非他是你亲戚！！讨论者，起码是水平相当的才有讨论的说法，如果水平真差距太远了，连基本操作都需要别人给解答，谁还跟你讨论呢</P>
<P style="TEXT-INDENT: 2em"></P></div>]]></description>
	    <author><![CDATA[老王]]></author>
	    <comments>http://blog.163.com/eric_wyf/blog/static/22672170200791095340339</comments>
    <slash:comments>0</slash:comments>
    <guid isPermaLink="true">http://blog.163.com/eric_wyf/blog/static/22672170200791095340339</guid>
    <pubDate>Wed, 10 Oct 2007 09:53:40 +0800</pubDate>
    <dcterms:modified>2007-10-10T09:53:40+08:00</dcterms:modified>
  </item>    
  <item>
  	<title><![CDATA[Java反射机制]]></title>	
    <link>http://blog.163.com/eric_wyf/blog/static/2267217020073313120297</link>
    <description><![CDATA[<div><P>Java反射机制</P>
<P>&nbsp;</P>
<P>摘要</P>
<P>Reflection 是Java被视为动态（或准动态）语言的一个关键性质。这个机制允许程序在运行时透过Reflection APIs取得任何一个已知名称的class的内部信息，包括其modifiers（诸如public, static 等等）、superclass（例如Object）、实现之interfaces（例如Cloneable），也包括fields和methods的所有信息，并可于运行时改变fields内容或唤起methods。本文借由实例，大面积示范Reflection APIs。</P>
<P>&nbsp;</P>
<P>关于本文：</P>
<P>读者基础：具备Java 语言基础。</P>
<P>本文适用工具：JDK1.5</P>
<P>&nbsp;</P>
<P>关键词：</P>
<P>Introspection（内省、内观）</P>
<P>Reflection（反射）</P>
<P>&nbsp;</P>
<P>&nbsp;</P>
<P>有时候我们说某个语言具有很强的动态性，有时候我们会区分动态和静态的不同技术与作法。我们朗朗上口动态绑定（dynamic binding）、动态链接（dynamic linking）、动态加载（dynamic loading）等。然而“动态”一词其实没有绝对而普遍适用的严格定义，有时候甚至像对象导向当初被导入编程领域一样，一人一把号，各吹各的调。</P>
<P>&nbsp;</P>
<P>一般而言，开发者社群说到动态语言，大致认同的一个定义是：“程序运行时，允许改变程序结构或变量类型，这种语言称为动态语言”。从这个观点看，Perl，Python，Ruby是动态语言，C++，Java，C#不是动态语言。</P>
<P>&nbsp;</P>
<P>尽管在这样的定义与分类下Java不是动态语言，它却有着一个非常突出的动态相关机制：Reflection。这个字的意思是“反射、映象、倒影”，用在Java身上指的是我们可以于运行时加载、探知、使用编译期间完全未知的classes。换句话说，Java程序可以加载一个运行时才得知名称的class，获悉其完整构造（但不包括methods定义），并生成其对象实体、或对其fields设值、或唤起其methods1。这种“看透class”的能力（the ability of the program to examine itself）被称为introspection（内省、内观、反省）。Reflection和introspection是常被并提的两个术语。</P>
<P>&nbsp;</P>
<P>Java如何能够做出上述的动态特性呢？这是一个深远话题，本文对此只简单介绍一些概念。整个篇幅最主要还是介绍Reflection APIs，也就是让读者知道如何探索class的结构、如何对某个“运行时才获知名称的class”生成一份实体、为其fields设值、调用其methods。本文将谈到java.lang.Class，以及java.lang.reflect中的Method、Field、Constructor等等classes。</P>
<P>&nbsp;</P>
<P>“Class”class</P>
<P>众所周知Java有个Object class，是所有Java classes的继承根源，其内声明了数个应该在所有Java class中被改写的methods：hashCode()、equals()、clone()、toString()、getClass()等。其中getClass()返回一个Class object。</P>
<P>&nbsp;</P>
<P>Class class十分特殊。它和一般classes一样继承自Object，其实体用以表达Java程序运行时的classes和interfaces，也用来表达enum、array、primitive Java types（boolean, byte, char, short, int, long, float, double）以及关键词void。当一个class被加载，或当加载器（class loader）的defineClass()被JVM调用，JVM 便自动产生一个Class object。如果您想借由“修改Java标准库源码”来观察Class object的实际生成时机（例如在Class的constructor内添加一个println()），不能够！因为Class并没有public constructor（见图1）。本文最后我会拨一小块篇幅顺带谈谈Java标准库源码的改动办法。</P>
<P>&nbsp;</P>
<P>Class是Reflection故事起源。针对任何您想探勘的class，唯有先为它产生一个Class object，接下来才能经由后者唤起为数十多个的Reflection APIs。这些APIs将在稍后的探险活动中一一亮相。</P>
<P>&nbsp;</P>
<P>#001 public final</P>
<P>#002 class Class&lt;T&gt; implements java.io.Serializable,</P>
<P>#003 java.lang.reflect.GenericDeclaration,</P>
<P>#004 java.lang.reflect.Type,</P>
<P>#005 java.lang.reflect.AnnotatedElement {</P>
<P>#006&nbsp;&nbsp;&nbsp; private Class() {}</P>
<P>#007&nbsp;&nbsp;&nbsp; public String toString() {</P>
<P>#008&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return ( isInterface() ? "interface " :</P>
<P>#009&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (isPrimitive() ? "" : "class "))</P>
<P>#010&nbsp;&nbsp;&nbsp; + getName();</P>
<P>#011 }</P>
<P>...</P>
<P>图1：Class class片段。注意它的private empty ctor，意指不允许任何人经由编程方式产生Class object。是的，其object 只能由JVM 产生。</P>
<P>&nbsp;</P>
<P>“Class” object的取得途径</P>
<P>Java允许我们从多种管道为一个class生成对应的Class object。图2是一份整理。</P>
<P>Class object 诞生管道<BR>&nbsp;示例<BR>&nbsp;<BR>运用getClass()</P>
<P>注：每个class 都有此函数<BR>&nbsp;String str = "abc";</P>
<P>Class c1 = str.getClass();<BR>&nbsp;<BR>运用</P>
<P>Class.getSuperclass()2<BR>&nbsp;Button b = new Button();</P>
<P>Class c1 = b.getClass();</P>
<P>Class c2 = c1.getSuperclass();<BR>&nbsp;<BR>运用static method</P>
<P>Class.forName()</P>
<P>（最常被使用）<BR>&nbsp;Class c1 = Class.forName ("java.lang.String");</P>
<P>Class c2 = Class.forName ("java.awt.Button");</P>
<P>Class c3 = Class.forName ("java.util.LinkedList$Entry");</P>
<P>Class c4 = Class.forName ("I");</P>
<P>Class c5 = Class.forName ("[I");<BR>&nbsp;<BR>运用</P>
<P>.class 语法<BR>&nbsp;Class c1 = String.class;</P>
<P>Class c2 = java.awt.Button.class;</P>
<P>Class c3 = Main.InnerClass.class;</P>
<P>Class c4 = int.class;</P>
<P>Class c5 = int[].class;<BR>&nbsp;<BR>运用</P>
<P>primitive wrapper classes</P>
<P>的TYPE 语法</P>
<P>&nbsp;<BR>&nbsp;Class c1 = Boolean.TYPE;</P>
<P>Class c2 = Byte.TYPE;</P>
<P>Class c3 = Character.TYPE;</P>
<P>Class c4 = Short.TYPE;</P>
<P>Class c5 = Integer.TYPE;</P>
<P>Class c6 = Long.TYPE;</P>
<P>Class c7 = Float.TYPE;</P>
<P>Class c8 = Double.TYPE;</P>
<P>Class c9 = Void.TYPE;<BR>&nbsp;</P>
<P><BR>图2：Java 允许多种管道生成Class object。</P>
<P>&nbsp;</P>
<P>Java classes 组成分析</P>
<P>首先容我以图3的java.util.LinkedList为例，将Java class的定义大卸八块，每一块分别对应图4所示的Reflection API。图5则是“获得class各区块信息”的程序示例及执行结果，它们都取自本文示例程序的对应片段。</P>
<P>&nbsp;</P>
<P>package java.util;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //(1)</P>
<P>import java.lang.*;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //(2)</P>
<P>public class LinkedList&lt;E&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //(3)(4)(5)</P>
<P>extends AbstractSequentialList&lt;E&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //(6)</P>
<P>implements List&lt;E&gt;, Queue&lt;E&gt;,</P>
<P>Cloneable, java.io.Serializable&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //(7)</P>
<P>{</P>
<P>private static class Entry&lt;E&gt; { … }//(8)</P>
<P>public LinkedList() { … }&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //(9)</P>
<P>public LinkedList(Collection&lt;? extends E&gt; c) { … }</P>
<P>public E getFirst() { … }&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //(10)</P>
<P>public E getLast() { … }</P>
<P>private transient Entry&lt;E&gt; header = …;&nbsp; //(11)</P>
<P>private transient int size = 0;</P>
<P>}</P>
<P>图3：将一个Java class 大卸八块，每块相应于一个或一组Reflection APIs（图4）。</P>
<P>&nbsp;</P>
<P>Java classes 各成份所对应的Reflection APIs</P>
<P>图3的各个Java class成份，分别对应于图4的Reflection API，其中出现的Package、Method、Constructor、Field等等classes，都定义于java.lang.reflect。</P>
<P>Java class 内部模块（参见图3）<BR>&nbsp;Java class 内部模块说明<BR>&nbsp;相应之Reflection API，多半为Class methods。<BR>&nbsp;返回值类型(return type)<BR>&nbsp;<BR>(1) package<BR>&nbsp;class隶属哪个package<BR>&nbsp;getPackage()<BR>&nbsp;Package<BR>&nbsp;<BR>(2) import<BR>&nbsp;class导入哪些classes<BR>&nbsp;无直接对应之API。</P>
<P>解决办法见图5-2。<BR>&nbsp; <BR>&nbsp;<BR>(3) modifier<BR>&nbsp;class（或methods, fields）的属性</P>
<P>&nbsp;<BR>&nbsp;int getModifiers()</P>
<P>Modifier.toString(int)</P>
<P>Modifier.isInterface(int)<BR>&nbsp;int</P>
<P>String</P>
<P>bool<BR>&nbsp;<BR>(4) class name or interface name<BR>&nbsp;class/interface<BR>&nbsp;名称getName()<BR>&nbsp;String<BR>&nbsp;<BR>(5) type parameters<BR>&nbsp;参数化类型的名称<BR>&nbsp;getTypeParameters() <BR>&nbsp;TypeVariable &lt;Class&gt;[]<BR>&nbsp;<BR>(6) base class<BR>&nbsp;base class（只可能一个）<BR>&nbsp;getSuperClass()<BR>&nbsp;Class<BR>&nbsp;<BR>(7) implemented interfaces<BR>&nbsp;实现有哪些interfaces<BR>&nbsp;getInterfaces()<BR>&nbsp;Class[]</P>
<P>&nbsp;<BR>&nbsp;<BR>(8) inner classes<BR>&nbsp;内部classes<BR>&nbsp;getDeclaredClasses()<BR>&nbsp;Class[]<BR>&nbsp;<BR>(8') outer class<BR>&nbsp;如果我们观察的class 本身是inner classes，那么相对它就会有个outer class。<BR>&nbsp;getDeclaringClass()<BR>&nbsp;Class<BR>&nbsp;<BR>(9) constructors<BR>&nbsp;构造函数getDeclaredConstructors()<BR>&nbsp;不论 public 或private 或其它access level，皆可获得。另有功能近似之取得函数。<BR>&nbsp;Constructor[]<BR>&nbsp;<BR>(10) methods<BR>&nbsp;操作函数getDeclaredMethods()<BR>&nbsp;不论 public 或private 或其它access level，皆可获得。另有功能近似之取得函数。<BR>&nbsp;Method[]<BR>&nbsp;<BR>(11) fields<BR>&nbsp;字段（成员变量）<BR>&nbsp;getDeclaredFields()不论 public 或private 或其它access level，皆可获得。另有功能近似之取得函数。<BR>&nbsp;Field[]<BR>&nbsp;</P>
<P><BR>图4：Java class大卸八块后（如图3），每一块所对应的Reflection API。本表并非</P>
<P>Reflection APIs 的全部。</P>
<P>&nbsp;</P>
<P>Java Reflection API 运用示例</P>
<P>图5示范图4提过的每一个Reflection API，及其执行结果。程序中出现的tName()是个辅助函数，可将其第一自变量所代表的“Java class完整路径字符串”剥除路径部分，留下class名称，储存到第二自变量所代表的一个hashtable去并返回（如果第二自变量为null，就不储存而只是返回）。</P>
<P>&nbsp;</P>
<P>#001 Class c = null;</P>
<P>#002 c = Class.forName(args[0]);</P>
<P>#003</P>
<P>#004 Package p;</P>
<P>#005 p = c.getPackage();</P>
<P>#006</P>
<P>#007 if (p != null)</P>
<P>#008&nbsp;&nbsp;&nbsp; System.out.println("package "+p.getName()+";");</P>
<P>&nbsp;</P>
<P>执行结果（例）：</P>
<P>package java.util;</P>
<P>图5-1：找出class 隶属的package。其中的c将继续沿用于以下各程序片段。</P>
<P>&nbsp;</P>
<P>#001 ff = c.getDeclaredFields();</P>
<P>#002 for (int i = 0; i &lt; ff.length; i++)</P>
<P>#003&nbsp;&nbsp;&nbsp; x = tName(ff[i].getType().getName(), classRef);</P>
<P>#004</P>
<P>#005 cn = c.getDeclaredConstructors();</P>
<P>#006 for (int i = 0; i &lt; cn.length; i++) {</P>
<P>#007&nbsp;&nbsp;&nbsp; Class cx[] = cn[i].getParameterTypes();</P>
<P>#008&nbsp;&nbsp;&nbsp; for (int j = 0; j &lt; cx.length; j++)</P>
<P>#009&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; x = tName(cx[j].getName(), classRef);</P>
<P>#010 }</P>
<P>#011</P>
<P>#012 mm = c.getDeclaredMethods();</P>
<P>#013 for (int i = 0; i &lt; mm.length; i++) {</P>
<P>#014&nbsp;&nbsp;&nbsp; x = tName(mm[i].getReturnType().getName(), classRef);</P>
<P>#015&nbsp;&nbsp;&nbsp; Class cx[] = mm[i].getParameterTypes();</P>
<P>#016&nbsp;&nbsp;&nbsp; for (int j = 0; j &lt; cx.length; j++)</P>
<P>#017&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; x = tName(cx[j].getName(), classRef);</P>
<P>#018 }</P>
<P>#019 classRef.remove(c.getName()); //不必记录自己（不需import 自己）</P>
<P>&nbsp;</P>
<P>执行结果（例）：</P>
<P>import java.util.ListIterator;</P>
<P>import java.lang.Object;</P>
<P>import java.util.LinkedList$Entry;</P>
<P>import java.util.Collection;</P>
<P>import java.io.ObjectOutputStream;</P>
<P>import java.io.ObjectInputStream;</P>
<P>图5-2：找出导入的classes，动作细节详见内文说明。</P>
<P>&nbsp;</P>
<P>#001 int mod = c.getModifiers();</P>
<P>#002 System.out.print(Modifier.toString(mod)); //整个modifier</P>
<P>#003</P>
<P>#004 if (Modifier.isInterface(mod))</P>
<P>#005&nbsp;&nbsp;&nbsp; System.out.print(" "); //关键词 "interface" 已含于modifier</P>
<P>#006 else</P>
<P>#007&nbsp;&nbsp;&nbsp; System.out.print(" class "); //关键词 "class"</P>
<P>#008 System.out.print(tName(c.getName(), null)); //class 名称</P>
<P>&nbsp;</P>
<P>执行结果（例）：</P>
<P>public class LinkedList</P>
<P>图5-3：找出class或interface 的名称，及其属性（modifiers）。</P>
<P>&nbsp;</P>
<P>#001 TypeVariable&lt;Class&gt;[] tv;</P>
<P>#002 tv = c.getTypeParameters(); //warning: unchecked conversion</P>
<P>#003 for (int i = 0; i &lt; tv.length; i++) {</P>
<P>#004&nbsp;&nbsp;&nbsp; x = tName(tv[i].getName(), null); //例如 E,K,V...</P>
<P>#005&nbsp;&nbsp;&nbsp; if (i == 0) //第一个</P>
<P>#006&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.print("&lt;" + x);</P>
<P>#007&nbsp;&nbsp;&nbsp; else //非第一个</P>
<P>#008&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.print("," + x);</P>
<P>#009&nbsp;&nbsp;&nbsp; if (i == tv.length-1) //最后一个</P>
<P>#010&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("&gt;");</P>
<P>#011 }</P>
<P>&nbsp;</P>
<P>执行结果（例）：</P>
<P>public abstract interface Map&lt;K,V&gt;</P>
<P>或 public class LinkedList&lt;E&gt;</P>
<P>图5-4：找出parameterized types 的名称</P>
<P>&nbsp;</P>
<P>#001 Class supClass;</P>
<P>#002 supClass = c.getSuperclass();</P>
<P>#003 if (supClass != null) //如果有super class</P>
<P>#004&nbsp;&nbsp;&nbsp; System.out.print(" extends" +</P>
<P>#005 tName(supClass.getName(),classRef));</P>
<P>&nbsp;</P>
<P>执行结果（例）：</P>
<P>public class LinkedList&lt;E&gt;</P>
<P>extends AbstractSequentialList,</P>
<P>图5-5：找出base class。执行结果多出一个不该有的逗号于尾端。此非本处重点，为简化计，不多做处理。</P>
<P>&nbsp;</P>
<P>#001 Class cc[];</P>
<P>#002 Class ctmp;</P>
<P>#003 //找出所有被实现的interfaces</P>
<P>#004 cc = c.getInterfaces();</P>
<P>#005 if (cc.length != 0)</P>
<P>#006&nbsp;&nbsp;&nbsp; System.out.print(", \r\n" + " implements "); //关键词</P>
<P>#007 for (Class cite : cc) //JDK1.5 新式循环写法</P>
<P>#008&nbsp;&nbsp;&nbsp; System.out.print(tName(cite.getName(), null)+", ");</P>
<P>&nbsp;</P>
<P>执行结果（例）：</P>
<P>public class LinkedList&lt;E&gt;</P>
<P>extends AbstractSequentialList,</P>
<P>implements List, Queue, Cloneable, Serializable,</P>
<P>图5-6：找出implemented interfaces。执行结果多出一个不该有的逗号于尾端。此非本处重点，为简化计，不多做处理。</P>
<P>&nbsp;</P>
<P>#001 cc = c.getDeclaredClasses(); //找出inner classes</P>
<P>#002 for (Class cite : cc)</P>
<P>#003&nbsp;&nbsp;&nbsp; System.out.println(tName(cite.getName(), null));</P>
<P>#004</P>
<P>#005 ctmp = c.getDeclaringClass(); //找出outer classes</P>
<P>#006 if (ctmp != null)</P>
<P>#007&nbsp;&nbsp;&nbsp; System.out.println(ctmp.getName());</P>
<P>&nbsp;</P>
<P>执行结果（例）：</P>
<P>LinkedList$Entry</P>
<P>LinkedList$ListItr</P>
<P>图5-7：找出inner classes 和outer class</P>
<P>&nbsp;</P>
<P>#001 Constructor cn[];</P>
<P>#002 cn = c.getDeclaredConstructors();</P>
<P>#003 for (int i = 0; i &lt; cn.length; i++) {</P>
<P>#004&nbsp;&nbsp;&nbsp; int md = cn[i].getModifiers();</P>
<P>#005&nbsp;&nbsp;&nbsp; System.out.print(" " + Modifier.toString(md) + " " +</P>
<P>#006&nbsp;&nbsp;&nbsp; cn[i].getName());</P>
<P>#007&nbsp;&nbsp;&nbsp; Class cx[] = cn[i].getParameterTypes();</P>
<P>#008&nbsp;&nbsp;&nbsp; System.out.print("(");</P>
<P>#009&nbsp;&nbsp;&nbsp; for (int j = 0; j &lt; cx.length; j++) {</P>
<P>#010&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.print(tName(cx[j].getName(), null));</P>
<P>#011&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (j &lt; (cx.length - 1)) System.out.print(", ");</P>
<P>#012&nbsp;&nbsp;&nbsp; }</P>
<P>#013&nbsp;&nbsp;&nbsp; System.out.print(")");</P>
<P>#014 }</P>
<P>&nbsp;</P>
<P>执行结果（例）：</P>
<P>public java.util.LinkedList(Collection)</P>
<P>public java.util.LinkedList()</P>
<P>图5-8a：找出所有constructors</P>
<P>&nbsp;</P>
<P>#004 System.out.println(cn[i].toGenericString());</P>
<P>&nbsp;</P>
<P>执行结果（例）：</P>
<P>public java.util.LinkedList(java.util.Collection&lt;? extends E&gt;)</P>
<P>public java.util.LinkedList()</P>
<P>图5-8b：找出所有constructors。本例在for 循环内使用toGenericString()，省事。</P>
<P>&nbsp;</P>
<P>#001 Method mm[];</P>
<P>#002 mm = c.getDeclaredMethods();</P>
<P>#003 for (int i = 0; i &lt; mm.length; i++) {</P>
<P>#004&nbsp;&nbsp;&nbsp; int md = mm[i].getModifiers();</P>
<P>#005&nbsp;&nbsp;&nbsp; System.out.print(" "+Modifier.toString(md)+" "+</P>
<P>#006&nbsp;&nbsp;&nbsp; tName(mm[i].getReturnType().getName(), null)+" "+</P>
<P>#007&nbsp;&nbsp;&nbsp; mm[i].getName());</P>
<P>#008&nbsp;&nbsp;&nbsp; Class cx[] = mm[i].getParameterTypes();</P>
<P>#009&nbsp;&nbsp;&nbsp; System.out.print("(");</P>
<P>#010&nbsp;&nbsp;&nbsp; for (int j = 0; j &lt; cx.length; j++) {</P>
<P>#011&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.print(tName(cx[j].getName(), null));</P>
<P>#012&nbsp;&nbsp;&nbsp; if (j &lt; (cx.length - 1)) System.out.print(", ");</P>
<P>#013&nbsp;&nbsp;&nbsp; }</P>
<P>#014&nbsp;&nbsp;&nbsp; System.out.print(")");</P>
<P>#015 }</P>
<P>&nbsp;</P>
<P>执行结果（例）：</P>
<P>public Object get(int)</P>
<P>public int size()</P>
<P>图5-9a：找出所有methods</P>
<P>&nbsp;</P>
<P>#004 System.out.println(mm[i].toGenericString());</P>
<P>&nbsp;</P>
<P>public E java.util.LinkedList.get(int)</P>
<P>public int java.util.LinkedList.size()</P>
<P>图5-9b：找出所有methods。本例在for 循环内使用toGenericString()，省事。</P>
<P>&nbsp;</P>
<P>#001 Field ff[];</P>
<P>#002 ff = c.getDeclaredFields();</P>
<P>#003 for (int i = 0; i &lt; ff.length; i++) {</P>
<P>#004&nbsp;&nbsp;&nbsp; int md = ff[i].getModifiers();</P>
<P>#005&nbsp;&nbsp;&nbsp; System.out.println(" "+Modifier.toString(md)+" "+</P>
<P>#006&nbsp;&nbsp;&nbsp; tName(ff[i].getType().getName(), null) +" "+</P>
<P>#007&nbsp;&nbsp;&nbsp; ff[i].getName()+";");</P>
<P>#008 }</P>
<P>&nbsp;</P>
<P>执行结果（例）：</P>
<P>private transient LinkedList$Entry header;</P>
<P>private transient int size;</P>
<P>图5-10a：找出所有fields</P>
<P>&nbsp;</P>
<P>#004 System.out.println("G: " + ff[i].toGenericString());</P>
<P>&nbsp;</P>
<P>private transient java.util.LinkedList.java.util.LinkedList$Entry&lt;E&gt; ??</P>
<P>java.util.LinkedList.header</P>
<P>private transient int java.util.LinkedList.size</P>
<P>图5-10b：找出所有fields。本例在for 循环内使用toGenericString()，省事。</P>
<P>&nbsp;</P>
<P>找出class参用（导入）的所有classes</P>
<P>没有直接可用的Reflection API可以为我们找出某个class参用的所有其它classes。要获得这项信息，必须做苦工，一步一脚印逐一记录。我们必须观察所有fields的类型、所有methods（包括constructors）的参数类型和回返类型，剔除重复，留下唯一。这正是为什么图5-2程序代码要为tName()指定一个hashtable（而非一个null）做为第二自变量的缘故：hashtable可为我们储存元素（本例为字符串），又保证不重复。</P>
<P>&nbsp;</P>
<P>本文讨论至此，几乎可以还原一个class的原貌（唯有methods 和ctors的定义无法取得）。接下来讨论Reflection 的另三个动态性质：(1) 运行时生成instances，(2) 执</P>
<P>行期唤起methods，(3) 运行时改动fields。</P>
<P>&nbsp;</P>
<P>运行时生成instances</P>
<P>欲生成对象实体，在Reflection 动态机制中有两种作法，一个针对“无自变量ctor”，</P>
<P>一个针对“带参数ctor”。图6是面对“无自变量ctor”的例子。如果欲调用的是“带参数ctor“就比较麻烦些，图7是个例子，其中不再调用Class的newInstance()，而是调用Constructor 的newInstance()。图7首先准备一个Class[]做为ctor的参数类型（本例指定为一个double和一个int），然后以此为自变量调用getConstructor()，获得一个专属ctor。接下来再准备一个Object[] 做为ctor实参值（本例指定3.14159和125），调用上述专属ctor的newInstance()。</P>
<P>&nbsp;</P>
<P>#001 Class c = Class.forName("DynTest");</P>
<P>#002 Object obj = null;</P>
<P>#003 obj = c.newInstance(); //不带自变量</P>
<P>#004 System.out.println(obj);</P>
<P>图6：动态生成“Class object 所对应之class”的对象实体；无自变量。</P>
<P>&nbsp;</P>
<P>#001 Class c = Class.forName("DynTest");</P>
<P>#002 Class[] pTypes = new Class[] { double.class, int.class };</P>
<P>#003 Constructor ctor = c.getConstructor(pTypes);</P>
<P>#004 //指定parameter list，便可获得特定之ctor</P>
<P>#005</P>
<P>#006 Object obj = null;</P>
<P>#007 Object[] arg = new Object[] {3.14159, 125}; //自变量</P>
<P>#008 obj = ctor.newInstance(arg);</P>
<P>#009 System.out.println(obj);</P>
<P>图7：动态生成“Class object 对应之class”的对象实体；自变量以Object[]表示。</P>
<P>&nbsp;</P>
<P>运行时调用methods</P>
<P>这个动作和上述调用“带参数之ctor”相当类似。首先准备一个Class[]做为ctor的参数类型（本例指定其中一个是String，另一个是Hashtable），然后以此为自变量调用getMethod()，获得特定的Method object。接下来准备一个Object[]放置自变量，然后调用上述所得之特定Method object的invoke()，如图8。知道为什么索取Method object时不需指定回返类型吗？因为method overloading机制要求signature（署名式）必须唯一，而回返类型并非signature的一个成份。换句话说，只要指定了method名称和参数列，就一定指出了一个独一无二的method。</P>
<P>&nbsp;</P>
<P>#001 public String func(String s, Hashtable ht)</P>
<P>#002 {</P>
<P>#003 …System.out.println("func invoked"); return s;</P>
<P>#004 }</P>
<P>#005 public static void main(String args[])</P>
<P>#006 {</P>
<P>#007 Class c = Class.forName("Test");</P>
<P>#008 Class ptypes[] = new Class[2];</P>
<P>#009 ptypes[0] = Class.forName("java.lang.String");</P>
<P>#010 ptypes[1] = Class.forName("java.util.Hashtable");</P>
<P>#011 Method m = c.getMethod("func",ptypes);</P>
<P>#012 Test obj = new Test();</P>
<P>#013 Object args[] = new Object[2];</P>
<P>#014 arg[0] = new String("Hello,world");</P>
<P>#015 arg[1] = null;</P>
<P>#016 Object r = m.invoke(obj, arg);</P>
<P>#017 Integer rval = (String)r;</P>
<P>#018 System.out.println(rval);</P>
<P>#019 }</P>
<P>图8：动态唤起method</P>
<P>&nbsp;</P>
<P>运行时变更fields内容</P>
<P>与先前两个动作相比，“变更field内容”轻松多了，因为它不需要参数和自变量。首先调用Class的getField()并指定field名称。获得特定的Field object之后便可直接调用Field的get()和set()，如图9。</P>
<P>&nbsp;</P>
<P>#001 public class Test {</P>
<P>#002 public double d;</P>
<P>#003</P>
<P>#004 public static void main(String args[])</P>
<P>#005 {</P>
<P>#006 Class c = Class.forName("Test");</P>
<P>#007 Field f = c.getField("d"); //指定field 名称</P>
<P>#008 Test obj = new Test();</P>
<P>#009 System.out.println("d= " + (Double)f.get(obj));</P>
<P>#010 f.set(obj, 12.34);</P>
<P>#011 System.out.println("d= " + obj.d);</P>
<P>#012 }</P>
<P>#013 }</P>
<P>图9：动态变更field 内容</P>
<P>&nbsp;</P>
<P>Java 源码改动办法</P>
<P>先前我曾提到，原本想借由“改动Java标准库源码”来测知Class object的生成，但由于其ctor原始设计为private，也就是说不可能透过这个管道生成Class object（而是由class loader负责生成），因此“在ctor中打印出某种信息”的企图也就失去了意义。</P>
<P>&nbsp;</P>
<P>这里我要谈点题外话：如何修改Java标准库源码并让它反应到我们的应用程序来。假设我想修改java.lang.Class，让它在某些情况下打印某种信息。首先必须找出标准源码！当你下载JDK 套件并安装妥当，你会发现jdk150\src\java\lang 目录（见图10）之中有Class.java，这就是我们此次行动的标准源码。备份后加以修改，编译获得Class.class。接下来准备将.class 搬移到jdk150\jre\lib\endorsed（见图10）。</P>
<P>&nbsp;</P>
<P>这是一个十分特别的目录，class loader将优先从该处读取内含classes的.jar文件——成功的条件是.jar内的classes压缩路径必须和Java标准库的路径完全相同。为此，我们可以将刚才做出的Class.class先搬到一个为此目的而刻意做出来的\java\lang目录中，压缩为foo.zip（任意命名，唯需夹带路径java\lang），再将这个foo.zip搬到jdk150\jre\lib\endorsed并改名为foo.jar。此后你的应用程序便会优先用上这里的java.lang.Class。整个过程可写成一个批处理文件（batch file），如图11，在DOS Box中使用。</P>
<P>&nbsp;</P>
<P><BR>图10：JDK1.5 安装后的目录组织。其中的endorsed 是我新建。</P>
<P>&nbsp;</P>
<P>del e:\java\lang\*.class //清理干净</P>
<P>del c:\jdk150\jre\lib\endorsed\foo.jar //清理干净</P>
<P>c:</P>
<P>cd c:\jdk150\src\java\lang</P>
<P>javac -Xlint:unchecked Class.java //编译源码</P>
<P>javac -Xlint:unchecked ClassLoader.java //编译另一个源码（如有必要）</P>
<P>move *.class e:\java\lang //搬移至刻意制造的目录中</P>
<P>e:</P>
<P>cd e:\java\lang //以下压缩至适当目录</P>
<P>pkzipc -add -path=root c:\jdk150\jre\lib\endorsed\foo.jar *.class</P>
<P>cd e:\test //进入测试目录</P>
<P>javac -Xlint:unchecked Test.java //编译测试程序</P>
<P>java Test //执行测试程序</P>
<P>图11：一个可在DOS Box中使用的批处理文件（batch file），用以自动化java.lang.Class</P>
<P>的修改动作。Pkzipc(.exe)是个命令列压缩工具，add和path都是其命令。</P>
<P>&nbsp;</P>
<P>更多信息</P>
<P>以下是视野所及与本文主题相关的更多讨论。这些信息可以弥补因文章篇幅限制而带来的不足，或带给您更多视野。</P>
<P>&nbsp;</P>
<P>l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "Take an in-depth look at the Java Reflection API -- Learn about the new Java 1.1 tools forfinding out information about classes", by Chuck McManis。此篇文章所附程序代码是本文示例程序的主要依据（本文示例程序示范了更多Reflection APIs，并采用JDK1.5 新式的for-loop 写法）。</P>
<P>l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "Take a look inside Java classes -- Learn to deduce properties of a Java class from inside aJava program", by Chuck McManis。</P>
<P>l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "The basics of Java class loaders -- The fundamentals of this key component of the Javaarchitecture", by Chuck McManis。</P>
<P>l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 《The Java Tutorial Continued》, Sun microsystems. Lesson58-61, "Reflection".</P>
<P>&nbsp;</P>
<P>注1用过诸如MFC这类所谓 Application Framework的程序员也许知道，MFC有所谓的dynamic creation。但它并不等同于Java的动态加载或动态辨识；所有能够在MFC程序中起作用的classes，都必须先在编译期被编译器“看见”。</P>
<P>&nbsp;</P>
<P>注2如果操作对象是Object，Class.getSuperClass()会返回null。</P>
<P>&nbsp;</P></div>]]></description>
	    <author><![CDATA[老王]]></author>
	    <comments>http://blog.163.com/eric_wyf/blog/static/2267217020073313120297</comments>
    <slash:comments>0</slash:comments>
    <guid isPermaLink="true">http://blog.163.com/eric_wyf/blog/static/2267217020073313120297</guid>
    <pubDate>Tue, 3 Apr 2007 13:31:20 +0800</pubDate>
    <dcterms:modified>2007-04-03T13:31:20+08:00</dcterms:modified>
  </item>    
  <item>
  	<title><![CDATA[愚人节，愚人了一把]]></title>	
    <link>http://blog.163.com/eric_wyf/blog/static/2267217020073295044656</link>
    <description><![CDATA[<div><P style="TEXT-INDENT: 2em">周日起了个早去上课，做了将近2个小时的车到了学校，结果一看教师没人，心想一直没上课，可能是改教师了，结果找了整个楼都没有，后来打电话给同学才知道今天停了一次课，我靠！白白的浪费了我这份积极性和一上午的时间，结果周日上午就在4个小时的车程中度过了，TMD。正好是愚人节，自己当了回愚人！</P></div>]]></description>
	    <author><![CDATA[老王]]></author>
	    <comments>http://blog.163.com/eric_wyf/blog/static/2267217020073295044656</comments>
    <slash:comments>0</slash:comments>
    <guid isPermaLink="true">http://blog.163.com/eric_wyf/blog/static/2267217020073295044656</guid>
    <pubDate>Mon, 2 Apr 2007 09:50:44 +0800</pubDate>
    <dcterms:modified>2007-04-02T09:50:44+08:00</dcterms:modified>
  </item>    
  <item>
  	<title><![CDATA[时代的晚上]]></title>	
    <link>http://blog.163.com/eric_wyf/blog/static/2267217020072270357925</link>
    <description><![CDATA[<div><P><BR>没有新的语言 也没有新的方式<BR>没有新的力量 能够表达新的感情<BR>不是什么痛苦 也不是天生爱较劲<BR>不过是积压以久的一些本能的反应<BR>情况太复杂 现实太残酷了<BR>谁知道忍受的极限到了会是什么样的结果<BR>请摸着我的手吧&nbsp; 我孤独的姑娘<BR>检查一下我的心里的病是否和你的一样</P>
<P>不是谈论政治 可还是有点慌张<BR>可能是因为过去的精神压力如今还没有得到释放<BR>别看我在微笑 也别觉得我轻松<BR>我回家单独严肃时才会真的感到忧伤<BR>我的心在疼痛 像童年的委屈<BR>却不是那么简单也不是那么容易<BR>请摸着我的手吧 我温柔的姑娘<BR>是不是我越软弱就越像你的情人</P>
<P>请看着我的眼睛 你不要改变方向<BR>不要因为我太激动而要开始感到紧张<BR>把那只手也给我&nbsp; 把它放在那我的心上<BR>感觉一下我的心跳是否是否还有力量<BR>你的小手冰凉&nbsp; 像你的眼神一样<BR>我感到你身上也有力量却没有使出的地方<BR>请摸着我的手吧&nbsp; 我坚强的姑娘<BR>也许你比我更敏感 更有话要讲</P>
<P>你会相信我吗&nbsp; 你会依靠我吗<BR>你是否能够控制得住我如果我疯了<BR>你无所事事吗 你TM需要震憾吗<BR>可是我们生活的这辈子有太多的事还不能干哪<BR>行为太缓慢了&nbsp; 意识太落后了<BR>眼前我们能够做的事只是肉体上需要的<BR>请摸着我的手吧&nbsp; 我美丽的姑娘<BR>让我安慰你度过这时代的晚上<BR></P></div>]]></description>
	    <author><![CDATA[老王]]></author>
	    <comments>http://blog.163.com/eric_wyf/blog/static/2267217020072270357925</comments>
    <slash:comments>0</slash:comments>
    <guid isPermaLink="true">http://blog.163.com/eric_wyf/blog/static/2267217020072270357925</guid>
    <pubDate>Tue, 27 Mar 2007 12:03:57 +0800</pubDate>
    <dcterms:modified>2007-03-27T12:03:57+08:00</dcterms:modified>
  </item>    
 </channel>
</rss>