负暄琐话

我的email: rot47('649@ 6(hF+`hd"w=92vhG{>}G3"@l M >:>6?4@56 \F')

用户操作
[即时聊天] [发私信] [加为好友]
囧囧ID:g9yuayon
921140次访问,排名35好友47人,关注者45
姓名:g9yuayon
前世:夜郎国厚脸皮神棍
魅力指数:0
名气:1
宠物:一只从来不对生人叫的看门狗
g9yuayon的文章
原创 244 篇
翻译 4 篇
转载 50 篇
评论 912 篇
g9的公告
最近评论
fferror:g9大大,最后一个C版本的SQUARE(x)是不是有错? 等待回复。
neilton:嘿嘿
neilton:嘿嘿
duguguiyu1984:老大邪恶了。。。呵呵。。。
xingranliuyun:我感觉到这两个人的灵魂就像最后的那段音乐一样,自由、奔放。

我燃了!
文章分类
收藏
    相册
    旅游
    计算机科学
    Lambda the Ultimate
    软件开发
    Reddit编程专栏(RSS)
    正在读的书
    存档
    订阅我的博客
    XML聚合  FeedSky

    原创 实在抵不住张老师的诱惑,又跳坑了收藏

    新一篇: 面向Froozle的开发 | 旧一篇: lamdba算子4:布尔值和选择

    题目在这里 。真是惭愧啊。前天才给朋友说张老师的题目太长,我没有没有本事一目十行立马解答,还是不玩儿了。而且明天就要做演示了,后天就要交作业了,领导还闹着要我陪她溜冰。但后来忍不住看了张老师的帖子,不能自己地想知道答案啊。心里那个痒啊。偏偏各位老大愤怒声讨张老师,就是不给我们小菜鸟们一个爽快的答案。我那个闷骚啊,难以言表。终于对不起朋友,对不起公司,对不起教授,对不起领导,调出了我心爱的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熟悉而已。就像我还对我们部门的代码熟悉呢,不说明什么。但我还是做得很高兴。典型的菜鸟特征啊。

    发表于 @ 2006年08月30日 12:26:00|评论(loading...)|编辑

    新一篇: 面向Froozle的开发 | 旧一篇: lamdba算子4:布尔值和选择

    评论

    #张孝祥 发表于2006-08-30 13:11:00  IP: 221.221.4.*
    好!兄弟,一句话能概括我对你的敬佩,心服口服!
    #张孝祥 发表于2006-08-30 20:31:00  IP: 221.222.79.*
    兄弟,我毫不隐讳对你的敬仰,如果能有机会能与你见面聊聊,真乃一大幸事。特别是如果能利用你空暇时间,兼职为我们讲授一些你的经验,那就更加令人高兴了。我们的培训课程不局限我们规定的内容,只要是你感觉对别人有帮助的经验,都可以到我们的课堂上讲解,这也是我们培训与别的培训的最大区别。
    #g9 发表于2006-08-31 05:03:00  IP: 199.246.40.*
    张老师客气了。
    #Tao 发表于2006-09-01 13:44:00  IP: 47.153.156.*
    碰巧路过,我想问个问题!
    想知道findLoadedClass()都干了些啥!
    从javadoc中可以看到,It returns the class with the given binary name if this loader has been recorded by the Java virtual machine as an initiating loader of a class with that binary name.
    question:
    classloader L1想要load class A , 但是class A已经被classloader L2 load入虚拟机中, 而且classloader L1并不是class A 的initial loader, 那么findLoadedClass() 会返回啥?
    #g9 发表于2006-09-02 00:45:00  IP: 74.116.36.*
    当然找不到A啦。不然要那么多class loader干嘛?Class loader的好处之一就是自扫门前雪,这样我们可以让同一个类的不同实现互不干扰地运行。

    Class的装载遵循三个规则:
    1. 一致性原则。一旦一个类被装载,以后从*同一个*装载*同一个*类时必须返回这个已经装载了的类。
    2. 委托原则。类的装载从父类开始。
    3. 能见度原则。一个类只能看到它自己的classloader和这个classloader祖先装载的类。
    #cm4ever 发表于2006-09-04 08:55:00  IP: 218.19.2.*
    我突然想到一点,国内所在公司由于生存太紧张,都没有时间好好思考如何去学用一个工具。以前我只是看sample,tutorials文档,看来现在还得加上"阅读缺陷列表"一项,以避开相关的错误。
    #Tao 发表于2006-09-04 13:35:00  IP: 47.153.156.*
    谢谢g9的解答,假设有如下的情况:
    1. 在一个JVM中,有两个classloader L1和L2,L1和L2相互之间都没有委托关系,jvm 中有个class A 的reference R1初始为null且被L1 load进来,如果我用L2 load class A,那么我能否将L2 load 的 class A的Object赋给R1?
    2.在一个JVM中,有个classloader L1,它的parent是L2,L1和L2都能直接找到class A,那么通过L1 Load的class A的Object 能否赋值给被L1的parent L2 load 的class A的 Reference?
    #g9yuayon 发表于2006-09-09 10:54:00  IP: 74.116.36.*
    应该是可以的吧。不过我没做过,不知道确切答案。不如Tao老大做做,然后分享一下?至于第二个问题,L1会委托L2去装载A,所以只有一个引用,不存在你问题中的情况。
    发表评论  


    当前用户设置只有注册用户才能发表评论。如果你没有登录,请点击登录
    Csdn Blog version 3.1a
    Copyright © g9