实在抵不住张老师的诱惑,又跳坑了
張老師說: 從第一行打印的內容上可以看到: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
??????????????????????????????????????????????????????????????????????????????
到這個時候我可以肯定三件事了:
嗯,這個顯然是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熟悉而已。就像我還對我們部門的代碼熟悉呢,不說明什么。但我還是做得很高興。典型的菜鳥特征啊。
總結
以上是生活随笔為你收集整理的实在抵不住张老师的诱惑,又跳坑了的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: matlab运行stata命令,一文读懂
- 下一篇: ABAQUS 工程仿真分析基础入门到精通