题目在 这里 。真是惭愧啊。前天才给 朋友说张老师的题目太长,我没有没有本事一目十行立马解答,还是不玩儿了。而且明天就要做演示了,后天就要交作业了,领导还闹着要我陪她溜冰。但后来忍不住看了张老师的帖子,不能自己地想知道答案啊。心里那个痒啊。偏偏各位老大愤怒声讨张老师,就是不给我们小菜鸟们一个爽快的答案。我那个闷骚啊,难以言表。终于对不起朋友,对不起公司,对不起教授,对不起领导,调出了我心爱的svn,来了一把svn -co http://svn.apache.org/repos/asf/ant/core/tags/ANT_165(因为我用ANT 1.6.5)。靠,后来发现这一步纯属多事。嗯,没有搞出最后答案,但我已经没有兴趣了。目前的发现就算抛砖引玉吧:

张老师说: 从第一行打印的内容上可以看到:AuxiliaryClass类的类装载器为MainClass。这个结果与我的预期不同,因为按照类加载器的委托机制,MailClass类加载器将先委托其父级类装载器AppClassLoader加载AuxiliaryClass,而AuxiliaryClass所在的目录f:/project已经在第6步中加入到了Classpath环境变量当中,AppClassLoader可以成功加载AuxiliaryClass,所以,第一行打印出来的类装载器应该是AppClassLoader。

其实嗫,这个结果和张老师的预期是一样的。委托机制仍然在起作用。没法不起啊。源码说话:
01: protected synchronized Class loadClass (String name , boolean resolve ) throws ClassNotFoundException {
02:         // First, check if the class has already been loaded
03:         Class c = findLoadedClass (name ) ;
04:         if (c = = null ) {
05:                 try {
06:                         if (parent ! = null ) {
07:                                 c = parent . loadClass (name , false ) ;
08:                         } else {
09:                                 c = findBootstrapClass0 (name ) ;
10:                         }
11:                 } catch (ClassNotFoundException e ) {
12:                         // If still not found, then invoke findClass in order
13:                         // to find the class.
14:                         c = findClass (name ) ;
15:                 }
16:         }
17:         if (resolve ) {
18:                 resolveClass (c ) ;
19:         }
20:         return c ;
21: }

注意第07行。只要被装载的类没有被装载过,parent.loadClass()就一定会被调用。 我们最后看到的是MainClass,那唯一的结论就是ClassNotFoundException被抛出。第11到第14行被执行。可是我们在CLASSPATH里加入了到AuxiliaryClass的路径啊!张老大可是做了实验的。还好,福尔摩斯老大的话响起来:排除所有不可能的东东。剩下的看起来再不可能发生也是真相。不过呢,人见人耐的高爷爷也说过:小心了,俺只证明了这个算法正确,还没有运行程序来验证。所以俺决定继续下去,找点证据。于是我在MainClass里添加了下面这个方法:

23:     protected synchronized Class loadClass(String className, boolean resolveClass) throws ClassNotFoundException {
24:         // Ask the VM to look in its cache.
25:         Class loadedClass = findLoadedClass(className);
26:         // search in getParent() if not found
27:         if (loadedClass == null) {
28:                 System.out.println("loaded class is null");
29:                 try {
30:                         if (getParent() == null) {
31:                                 System.out.println("getParent() is null, class name is "+className);
32:                                 System.out.println("using system class loader "+getSystemClassLoader());
33:                                 //System.out.println("URLs: "+java.util.Arrays.asList(getSystemClassLoader().getURLs()));
34:                                 loadedClass = getSystemClassLoader().loadClass(className);
35:                                 System.out.println("now system class loader is: "+getSystemClassLoader());
36:                                 System.out.println("now loaded class is: "+loadedClass.getName());
37:                         } else{
38:                                 System.out.println("using parent "+getParent()+" to load "+className);
39:                                 System.out.println("parent loader's urls: "+java.util.Arrays.asList(((java.net.URLClassLoader)getParent()).getURLs()));
40:                                 loadedClass = getParent().loadClass(className);
41:                                 System.out.println("getParent() is not null, getParent() loads class: "+loadedClass.getName());
42:                         }
43:                 } catch (ClassNotFoundException e) {
44:                         // don't do anything.  Catching this exception is the normal protocol for
45:                         // getParent() classloaders telling use they couldn't find a class.
46:                         System.out.println("ClassNotFound by"+ getParent()+e);
47:                         e.printStackTrace();
48:                 }
49:
50:                 // not findLoadedClass or by getParent().loadClass, try locally
51:                 if (loadedClass == null) loadedClass = findClass(className);
52:         }
53:
54:         // resolve if required
55:         if (resolveClass) resolveClass(loadedClass);
56:         return loadedClass;
57:    }

也就是说,我写了一个自己的loadClass(),和ClassLoader里的几乎一样。唯一的区别是我加了不少调试句子。再运行一下张老师的build.xml,除原来张老师提到的输出以外,得到如下输出:

[java] found loaded class: null [java] loaded class is null[java] using parent sun.misc.Launcher$AppClassLoader@65251c45 to load cn.it cast.AuxiliaryClass
[java] parent loader's urls: [file:/D:/tools/ant/lib/ant-launcher.jar]
[java] ClassNotFound bysun.misc.Launcher$AppClassLoader@65251c45java.lang.ClassNotFoundException: cn.itcast.AuxiliaryClass
[java] java.lang.ClassNotFoundException: cn.itcast.AuxiliaryClass
                                                                              
到这个时候我可以肯定三件事了:

  1. sun.misc.Launcher$AppClassLoader是被调用了的。
  2. Classpath是被改动了的。AppClassLoader只能看到[file:/D:/tools/ant/lib/ant-launcher.jar]。也就是说,ANT把系统CLASSPATH里的值用ANT命令行里规定的-classpath里的值替换了。
  3. 前面讨论的ClassNotFoundException的确被抛出。

嗯,这个显然是ANT的问题。如果在run这个target里调用java这个task时加上fork="true",就可以看到如下的输出。说明ANT新生成的JVM就没有CLASSPATH的问题,因为新生成的JVM直接调用java, 不通过ant launcher。如果在eclipse里用代码调用ANT的Main.main(),也可以看到张老师期望的输出。说明用了自定义的ClassLoader,可以绕开这个问题。sun.misc.Launcher$AppClassLoader
sun.misc.Launcher$ExtClassLoader

那ANT为什么会改动CLASSPATH蹑?这个俺就不知道了。所以我在开头说我没有找到最后答案。毕竟张老师问的是ANT造成这个结果的机制。不过我们可以肯定这个错误没有发生在AntClassLoader和AntClassLoader2这两个类里(我也许错了)。也就是说,我很怀疑这个bug和ANT的classloader直接相关。

所谓google在手,一个顶九。于是我找到了这个bug report. 看来张老师的确发现了ANT的一个bug。看来这个bug已经在ant 1.7里被修复。造成bug的具体原因我还是不知道。不过这重要么?不重要么?ANT的一个bug而已,我想不出去了解这个bug的意义何在。我还有几百个bug要修补,几百个feature要添加,几百篇论文要读。去关心ANT上百错误中一个对我来说无异于自虐。呵呵,见谅见谅,其实都是菜鸟水平不够的托词而已。我的动力很小,我的借口很多,我。。。。去陪领导溜冰乐。。

其实这个问题的相关内容其实也不深入,无关系统设计,无关算法,无关具体应用。无非是某个编程错误而已。就算谁熟知ANT代码,也是对ANT熟悉而已。就像我还对我们部门的代码熟悉呢,不说明什么。但我还是做得很高兴。典型的菜鸟特征啊。

实在抵不住张老师的诱惑,又跳坑了相关推荐

  1. 又倒在了税务上,难道真的是抵不住“金钱”的诱惑,选择“铤而走险”?

    依法纳税本是每个公民应尽的义务. 这几年,有关明星.网红.大咖偷税,漏税的名人不少.应该说,对于很多普通人来说,确实无法理解,身价上亿,每天以百万千万进账的收入,他们却偏偏选择偷税漏税.难道真的是最终 ...

  2. 打印循环换行_科学向日葵在线课堂 ——张老师讲Python 第八课 周而复始为循环2...

    点击蓝字关注我们 张老师讲编程--和爸爸妈妈一起学Python Python 的编辑器有很多,例如 PyCharm.Spyder.Notepad++等等,大家根据需要选择一个就好,初期程序代码量不大, ...

  3. 逻辑推理:张老师的生日

    题目描述 小明和小强都是张老师的学生,张老师的生日是M月N日,2人都知道张老师的生日是下列10组中的一天: 3月4日 3月5日 3月8日6月4日 6月7日9月1日 9月5日12月1日 12月2日 12 ...

  4. 张孝祥去世 网友沉痛哀悼 张老师走好

    2011年的最后一天,也就是12月31日,曾经创立了传智博客在北京因疾病突发而突然逝世,享年年仅38岁.人说天妒英才,张孝祥老师年仅38岁,这位曾经为中国it崛起事业奉献了一生的无私的技术老师,英年早 ...

  5. (SQL)查询选修张老师讲授所有课程的学生题解

    题面 思路是,用多个嵌套搜索. 筛选选了张老师课的学生的学号,并计算他选了多少门张老师的课 同时计算出了张老师教了多少门课 如果该学生选的张老师的课的数量等于张老师教的课的数量说明他全选了. SQL: ...

  6. 张老师的生日[逻辑题]

    小明和小强都是张老师的学生,张老师的生日是M月N日, 2人都知道张老师的生日是下列10组中的一天, 张老师把M值告诉了小明,把N值告诉了小强, 张老师问他们知道他的生日是那一天吗? 3月4日 3月5日 ...

  7. 10-28 查询选修张老师讲授所有课程的学生(对自己来说有难度的一道题)

    10-28 查询选修张老师讲授所有课程的学生(MSSQL) 分数 10 全屏浏览题目 切换布局 作者 张庆 单位 集美大学 本题目要求编写SQL语句, 查询选修了张老师所讲授的所有课程的学生. 提示: ...

  8. 微软的一道经典逻辑推理题:小明和小强都是张老师的学生,张老师的生日是M月N日

    微软的一道经典逻辑推理题:小明和小强都是张老师的学生,张老师的生日是M月N日 分类: 天下杂侃 2008-08-07 23:37 17495人阅读 评论(21) 收藏 举报 题目是这样的: 小明和小强 ...

  9. 小明和小强都是张老师的学生,张老师的生日是M月N日问题

    小明和小强都是张老师的学生,张老师的生日是M月N日,2人都不知道张老师的生日是下列10组中的一天,张老师把M值告诉了小明,把N值告诉了小强,张老师问他们知道他的生日是那一天吗? 3月4日 3月5日 3 ...

  10. 小明和小强都是张老师的学生,张老师的生日是M月N日,

    小明和小强都是张老师的学生,张老师的生日是M月N日,   2人都知道张老师的生日是下列10组中的一天,张老师把M值告诉了小明,   把N值告诉了小强,张老师问他们知道他的生日是那一天吗?   3月4日 ...

最新文章

  1. Oracle总结第二篇【视图、索引、事务、用户权限、批量操作】
  2. ip netns 命令使用
  3. 学习笔记Spark(四)—— Spark编程基础(创建RDD、RDD算子、文件读取与存储)
  4. 悬挑脚手架卸载钢丝绳要求_安全不可忽视!脚手架搭设彩色图集,动画展示施工全过程,抠细节...
  5. 【Python】查找目标值在列表中的索引序号
  6. Active Directory边界
  7. 区块链软件公司:区块链使用程序如何成为战胜商场应战的垫脚石
  8. 前端学习(510):多列布局
  9. Go语言如何操纵Kafka才能保证消息不丢?
  10. elementui组件_elementui 中 loading 组件源码解析(续)
  11. BNUOJ 34978 汉诺塔 (概率dp)
  12. 贝叶斯估计原理及流程
  13. Python3的opencv环境搭建简易教程
  14. 【老生谈算法】基于matlab的指纹处理和识别算法详解及程序源码——指纹识别算法
  15. 怎么用QQ截取右击出来的内容
  16. Excel如何在姓名与字母之间加空格
  17. PVE中安装openwrt(IMG镜像文件)
  18. 基于JSP的房屋租赁系统
  19. MT6755_MT6750芯片技术资料
  20. JAVA WEB_JSP的初步(6)

热门文章

  1. Hadoop高可用安装
  2. 网站都变成灰色,一行代码就搞定了!
  3. 第二届中国Rust开发者大会议程介绍
  4. 「数据架构」什么是数据流程图(DFD)?如何绘制DFD?
  5. 云端运行python_云端部署python代码及安装MySQL
  6. 一封谷歌账号辅助邮箱变更的广告邮件
  7. pcre2 知:介绍
  8. MySQL之desc查看表结构的详细信息
  9. Android WebView播放视频flash(判断是否安装flash插件)
  10. Android矩阵运算总结