张孝祥专栏

以平常心工作,远离忧虑,除了让自己快乐,也要让别人快乐!

用户操作
[即时聊天] [发私信] [加为好友]
张孝祥ID:zhangxiaoxiang
556338次访问,排名75好友4人,关注者145
zhangxiaoxiang的文章
原创 129 篇
翻译 0 篇
转载 2 篇
评论 339 篇
张孝祥的公告
《深入体验Java Web开发内幕——高级特性》已经出版。 传智播客开展:先培训,就业后再还款活。详细信息查询:http://www.itcast.cn/goodnews.htm
最近评论
kwlong2008:

来看看朋友,最近过的怎么样?俺的空间是介绍
网站制作网站建设的,有时间也常去一下我的空间谢谢,
kwlong2008:

来看看朋友,最近过的怎么样?俺的空间是介绍
网站制作网站建设的,有时间也常去一下我的空间谢谢,
kwlong2008:

来看看朋友,最近过的怎么样?俺的空间是介绍
网站制作网站建设的,有时间也常去一下我的空间谢谢,
kwlong2008:

来看看朋友,最近过的怎么样?俺的空间是介绍
网站制作网站建设的,有时间也常去一下我的空间谢谢,
programmer_duncan:谢谢张老师分享!!!
文章分类
收藏
    相册
    传智播客原创教材展示
    培训
    《深入体验javaweb开发内幕——高级特性》出版啦!
    培训就业后还款计划正式启航
    良少的blog
    存档
    软件项目交易
    订阅我的博客
    XML聚合  FeedSky
    订阅到鲜果
    订阅到Google
    订阅到抓虾
    订阅到BlogLines
    订阅到Yahoo
    订阅到GouGou
    订阅到飞鸽
    订阅到Rojo
    订阅到newsgator
    订阅到netvibes

    原创 向真正Java高手请教ant构建工具的类装载器问题收藏

    新一篇: 8月27培训日记 | 旧一篇: 8-26日培训日记

    问题概述:每个ClassLoader本身只能分别加载特定位置和目录中的类,但是,ClassLoader被设计成了一种委托模式,使得某一个ClassLoader可以委托它的父级类装载器去加载类,从而让应用程序可以借助某一个子级的ClassLoader去多个位置和目录中进行类的加载。这就好比“儿子”除了可以花自己的钱,他还可以花“父亲”的钱,“父亲”又可以花“父亲的父亲”的钱,所以,最终能通过“儿子”花出去的钱包括他历代前辈的钱。类装载器一级级委托到BootStrap类加载器,当BootStrap无法加载当前所要加载的类时,然后才一级级回退到子孙类装载器去进行真正的加载。当回退到最初的类装载器时,如果它自己也不能完成类的装载,那就应报告ClassNotFoundException异常。
    现在的问题是,我编写了一个类装载器去加载特定目录中的类,使用java.exe测试这个类加载器时,测试结果完全正常,可以看到委托效果。而我使用ant工具去调用测试程序时,结果就有点问题了,我编写的类装载器似乎并没有委托其父级类加载器去加载类,而总是自己加载。由于本人才学疏浅,且实在没有精力去研究ant工具的源码,无法了解其类加载内部细节,现在特针对这个问题,向真正的java高手们请教。为了便于高手们快速了解我的问题所在,也便于一些中手们学习,我写出了详细的实验步骤,对于java新手,建议不要参与讨论了,免得我耽误了您宝贵时间。

    1.源程序:MainClass.java
    package cn.itcast;
    public class MainClass
    {
     public static void main(String [] args)
     {
      ClassLoader loader = MainClass.class.getClassLoader();
      //打印出当前的类装载器,及该类装载器的各级父类装载器
      while(loader != null)
      {
       System.out.println(loader.getClass().getName());
       loader = loader.getParent();
      }
      //加载AuxiliaryClass类
      System.out.println(AuxiliaryClass.class.getName());
     }
      
    }
    源程序:AuxiliaryClass.java
    package cn.itcast;
    public class AuxiliaryClass
    {
    }

    2.源文件及build结果文件的目录结构
        f:\project
            |__src
            |       |__cn
            |              |__itcast
            |                      |__MainClass.java
            |                      |__AuxiliaryClass.java
            |__build.xml
            |__classes
                     |__cn
                          |__itcast
                                      |__MainClass.class
                                      |__AuxiliaryClass.class
    3.build.xml文件内容
    <project name="antloader" default="run">
     <property name="classes.dir" value="classes" />
     <property name="src.dir" value="src" /> 

     <target name="init">
      <mkdir dir="${classes.dir}" />
     </target>

     <target name="compile" depends="init">
      <javac destdir="${classes.dir}" >
       <src path="${src.dir}" />
      </javac>
     </target>
     
     <target name="run" depends="compile">
      <java classname="cn.itcast.MyClassLoader">
       <classpath>
        <pathelement location="${classes.dir}"/>
       </classpath>
      </java>
     </target>
    </project>
    4.进入project目录中运行ant,执行结果正常,如下:
          org.apache.tools.ant.loader.AntClassLoader2
          sun.misc.Launcher$AppClassLoader
          sun.misc.Launcher$ExtClassLoader
          cn.itcast.AuxiliaryClass
    5.修改build.xml文件,将最后名称为“run”的target(执行目标)修改成如下形式,即不设置其中的<classpath>子元素。
     <target name="run" depends="compile">
      <java classname="cn.itcast.MyClassLoader">
       <!--classpath>
        <pathelement location="${classes.dir}"/>
       </classpath-->
      </java>
     </target>
    再次执行ant,将报告如下错误信息
    Could not find cn.itcast.MainClass. Make sure you have it in your classpath
            at org.apache.tools.ant.taskdefs.ExecuteJava.execute(ExecuteJava.java:170)
    在执行ant的命令行窗口中设置classpath环境变量:
           set CLASSPATH=f:\project\classes;
    再次执行ant,执行结果正常,如下:
    java.net.URLClassLoader
    sun.misc.Launcher$AppClassLoader
    sun.misc.Launcher$ExtClassLoader
    cn.itcast.AuxiliaryClass
    这个实验说明CLASSPATH环境变量对ant起了作用,并且在这种情况下,类的加载入器不再是org.apache.tools.ant.loader.AntClassLoader2,而是java.net.URLClassLoader。
    6.修改build.xml文件,让ant生成的AuxiliaryClass.class文件与MainClass文件位于不同的目录中,即结果目录如下:
        f:\project
            |__src
            |     |__cn
            |           |__itcast
            |                  |__MainClass.java
            |                  |__AuxiliaryClass.java
            |__build.xml
            |__classes
            |         |__cn
            |             |__itcast
            |                     |__MainClass.class
            |__cn
                    |__itcast
                             |__AuxiliaryClass.class
    修改后的build.xml文件内容如下:
    <project name="antloader" default="run">
     <property name="classes.dir" value="classes" />
     <property name="src.dir" value="src" /> 
     <property name="mainclass" value="cn.itcast.MainClass" /> 
     
     <target name="init">
      <mkdir dir="${classes.dir}" />
     </target>

     <target name="compile" depends="init">
      <javac destdir="${classes.dir}" >
       <src path="${src.dir}" />
       <include name="cn/itcast/MainClass.java" />
      </javac>
      <delete file="${classes.dir}/cn/itcast/AuxiliaryClass.class" />
      <javac destdir="." >
       <src path="${src.dir}" />
       <include name="cn/itcast/AuxiliaryClass.java" />
      </javac>
     </target>
     
     <target name="run" depends="clean,compile">
      <java classname="${mainclass}">
       <!--classpath>
        <pathelement location="${classes.dir}"/>
       </classpath-->
       <arg line="${arg0} ${arg1}" />
      </java>
     </target>
     
     <target name="clean">
      <delete dir="${classes.dir}" />
     </target>
     
    </project>
    因为第一个javac任务编译MainClass.java时,也会编译它引用的AuxiliaryClass.java文件,所以,增加了delete任务删除掉生成的AuxiliaryClass.class文件,然后再使用一个javac任务将AuxiliaryClass.java编译到另外一个目录中。java任务中也增加了一个<arg>子元素,用于为java虚拟机传递参数,在这一步暂时不需要这个元素,在下一步的实验中将使用这个元素。
    再次执行ant,将报告如下错误信息
    Could not find cn.itcast.Auxiliary. Make sure you have it in your classpath
            at org.apache.tools.ant.taskdefs.ExecuteJava.execute(ExecuteJava.java:170)
    在执行ant的命令行窗口中设置classpath环境变量,将编译后生成的AuxiliaryClass.class类所在的目录也加入进CLASSPATH环境变量中:
           set CLASSPATH=f:\project\classes;f:\project;
    再次执行ant,执行结果正常,如下:
    java.net.URLClassLoader
    sun.misc.Launcher$AppClassLoader
    sun.misc.Launcher$ExtClassLoader
    cn.itcast.AuxiliaryClass
    这个实验再次说明CLASSPATH环境变量对ant起了作用,将AuxiliaryClass.class放在了classpath环境变量指定的另外一个目录中,也可以被ant工具的java任务装载。
    7.修改MainClass.java文件,让其扩展成一个类装载器,专门负责从一个特定的目录中去加载类。MainClass同时也作为一个启动运行类,在其main方法中通过MainClass这个类装载器加载AuxiliaryClass类。
    源程序:MainClass.java
    package cn.itcast;
    import java.io.*;

    public class MainClass extends ClassLoader
    {
     private String path = null;
     public MainClass(String path)
     {
      //错误检查省略
      this.path = path;
     }

     protected Class findClass(String name) throws ClassNotFoundException
     {
      try
      {
       File f = new File(path,name.substring(name.lastIndexOf('.')+1) + ".class");
       FileInputStream fis = new FileInputStream(f);
       ByteArrayOutputStream bos = new ByteArrayOutputStream();
       int b = 0;
       while((b=fis.read()) != -1)
       {
        bos.write(b);
       }
       byte [] buf = bos.toByteArray();
       fis.close();
       bos.close();
       return defineClass(name,buf,0,buf.length);
      }catch(Exception e)
      {
       throw new ClassNotFoundException(name + "is not found!");
      }
     } 
     
     public static void main(String [] args) throws Exception
     {
      Class cls = new MainClass(args[1]).loadClass(args[0]);
      ClassLoader loader = cls.getClassLoader();
      //打印出的动态加载的AuxiliaryClass的类装载器,及该类装载器的各级父类装载器
      while(loader != null)
      {
       System.out.println(loader.getClass().getName());
       loader = loader.getParent();
      }
     }
      
    }
    按如下方式执行ant命令,其中第一个参数为要加载的类,第二个参数为到哪个目录中去加载如类。
    ant -Darg0=cn.itcast.AuxiliaryClass -Darg1=cn\itcast
    命令执行的结果为:
         cn.itcast.MainClass
         sun.misc.Launcher$AppClassLoader
         sun.misc.Launcher$ExtClassLoader
    从第一行打印的内容上可以看到:AuxiliaryClass类的类装载器为MainClass。这个结果与我的预期不同,因为按照类加载器的委托机制,MailClass类加载器将先委托其父级类装载器AppClassLoader加载AuxiliaryClass,而AuxiliaryClass所在的目录f:\project已经在第6步中加入到了Classpath环境变量当中,AppClassLoader可以成功加载AuxiliaryClass,所以,第一行打印出来的类装载器应该是AppClassLoader。为了印证我的想法,我改用java.exe来执行上面的程序:
    java cn.itcast.MainClass cn.itcast.AuxiliaryClass cn\itcast
    执行结果如下:
    sun.misc.Launcher$AppClassLoader
    sun.misc.Launcher$ExtClassLoader
    可见,使用java.exe执行上面的程序时,AuxiliaryClass类的类装载器确实是MailClass类加载器的父级类加载器AppClassLoader。这就是我这次问题的内容:为什么在ant环境下运行,MailClass类加载器没有委托其父级类装载器AppClassLoader加载AuxiliaryClass类,而是自己加载了呢?就这个问题,本人向真正的Java高手们请教?请您帮忙解释一下原因。
    8.为了印证类加载器的委托机制,我们重新设置CLASSPATH环境变量,该环境变量不再包含AuxiliaryClass所在的目录f:\project。
    set CLASSPATH=f:\project\classes;
    用cd命令进入f:\目录(避免当前目录的干扰),接着重复执行如下的java命令:
    java cn.itcast.MainClass cn.itcast.AuxiliaryClass project\cn\itcast
    执行结果如下:
    cn.itcast.MainClass
    sun.misc.Launcher$AppClassLoader
    sun.misc.Launcher$ExtClassLoader
    可见,这次AuxiliaryClass类的类装载器是MailClass类,这是因为MailClass类装载器的父级类加载器AppClassLoader找不到AuxiliaryClass类,加载过程又退回到MailClass类装载器,MailClass类装载器从project\cn\itcast目录中成功找到AuxiliaryClass类,所以,这次打印出的类装载器为MailClass。

     

     

    发表于 @ 2006年08月27日 17:33:00|评论(loading...)|编辑

    新一篇: 8月27培训日记 | 旧一篇: 8-26日培训日记

    评论

    #张汉东 发表于2006-08-27 20:26:00  IP: 221.216.15.*
    那些真正的高手哪去了???正是解决问题的时候,人影呢?
    #ai92 发表于2006-08-28 09:04:00  IP: 202.110.224.*
    你确信你的classpath起作用了?
    你可以再试试
    #javadog 发表于2006-08-28 09:27:00  IP: 202.110.224.*
    java.net.URLClassLoader
    sun.misc.Launcher$AppClassLoader
    sun.misc.Launcher$ExtClassLoader

    你确信你的classPath 起作用了?
    确定吗?确定吗?
    #axman 发表于2006-08-28 11:12:00  IP: 210.82.61.*
    这个问题是你的思路出现了问题.
    Class cls = new MainClass(args[1]).loadClass(args[0]);
    这一行得到的cls并不真正一定就是MainClass加载Class.
    就如字符串拘留,如果你String ss = "12345";你得到的12345并不一定是你这一句调用才产生的.有可能以前已经在字符串缓存池中,因为这一句的静态调用的内容与原有的池中的值相等所以返回的是原有的"12345"的值.

    在你调用 Class cls = new MainClass(args[1]).loadClass(args[0]);之前,由于AuxiliaryClass已经在类路径下,比如默认"."下无包的类,以.为根的子目录与包相匹配的类都会自动先被应用加载进来,这时内存中已经有了这个class,你再去用应用程序加载相同的class时,即使加载调用是成功的,但这个class的classLoader并不是你这个应用程序.

    所以你的程序并不能真正反映问题的本质,这就是一象单例模式.

    假如有一个类叫 A.class.属于a包,那么在d:\下建立一个a文件夹,把A的class放到a中,现在我们在d:\ 下执行 java,这里A.class已经在classpath中,你即使再用程序去load A.class,假如load成功,它返回的class因为和已经在内存中的A.class同一对象,所以表面上看是load成功但这个class的classloader并不是你这个load的应用程序而是应用的classloader.

    所以你的"执行结果如下:
    sun.misc.Launcher$AppClassLoader
    sun.misc.Launcher$ExtClassLoader"这一句要看你在哪儿执行或classpath如何配置.并不代表自己的classloader就会"委托"父类的classloader
    #回复javadog与axman 发表于2006-08-28 12:39:00  IP: 162.105.81.*
    javadog:
    你的评论显然毫无意义,我不喜欢这种只会给别人挑刺来炫耀自己的人,要知道给人挑刺是一件很简单的事情.你无非是想说当前的类装载器是URLClassLoader,而不是AppClassLoader,而只有AppClassLoader才去找ClassPath环境变量,这是常识吧!通过这个来炫耀好像没有什么意义吧!问题是现在的实验现象确实CLASSPATH起了作用.如果我要挑你的刺,我还要告诉你应该写成CLASSPATH,而不应该写成classPath呢?是你不知道到,还是笔误啊? 不要回答说Windows下写成classpath也无妨!
    axman:
    你的回答虽然对这个问题没有帮助,但你分析问题的思路对人有启发和帮助.虽然你很有经验,但你对这个问题并不在行,虽然你说没时间,但我知道你是搞不定这个问题而又要面子的托词.
    #axman 发表于2006-08-28 12:48:00  IP: 210.82.61.*
    这种嘴脸故做谦虚地"向人请教"
    #fafa 发表于2006-08-28 13:17:00  IP: 159.226.5.*
    张老师,这个问题我会,但是我在tomcat中关于classLoader的一些说明中,发现classLoader装载class的时候,并不一定是使用委托机制的,原文如下:
    As mentioned above, the web application class loader diverges from the default Java 2 delegation model (in accordance with the recommendations in the Servlet Specification, version 2.3, section 9.7.2 Web Application Classloader). When a request to load a class from the web application's WebappX class loader is processed, this class loader will look in the local repositories first, instead of delegating before looking. There are exceptions. Classes which are part of the JRE base classes cannot be overriden. For some classes (such as the XML parser components in J2SE 1.4+), the J2SE 1.4 endorsed feature can be used (see the common classloader definition above). Last, any JAR containing servlet API classes will be ignored by the classloader. All other class loaders in Tomcat 5 follow the usual delegation pattern.


    不知道这个能不能给出一点启示
    #... ... 发表于2006-08-28 13:26:00  IP: 60.16.91.*
    向真正的java高手们请教。为了便于高手们快速了解我的问题所在,也便于一些中手们学习,我写出了详细的实验步骤,对于java新手,建议不要参与讨论了,免得我耽误了您宝贵时间。

    ____________________________________

    呵呵,被骂急了
    #hehe 发表于2006-08-28 13:33:00  IP: 159.226.64.*
    但你对这个问题并不在行,虽然你说没时间,但我知道你是搞不定这个问题而又要面子的托词.
    _______________

    搞笑了
    #why 发表于2006-08-28 13:36:00  IP: 159.226.64.*
    不要回答说Windows下写成classpath也无妨!
    <-为何他不能这么回答呢?
    #ITPrince 发表于2006-08-28 14:04:00  IP: 218.83.211.*
    这老头的措辞越来越讨人厌了!!!
    #fafa 发表于2006-08-28 14:46:00  IP: 159.226.5.*
    不好意思,打错字了
    张老师,这个问题我会------〉张老师,这个问题我不会
    #回fafa和axman 发表于2006-08-28 15:56:00  IP: 162.105.81.*
    fafa:
    谢谢,关于tomcat的类装载问题,在我的新书和视频中都有介绍.tomcat的webapp类装载器也是采用委托机制,与其文档中介绍的不一样!刚开始我对自己的实验结果也很费解,后来看了rod johnson的j2ee without ejb谈到了各个Servlet容器不一定按照sun的servlet规范来实现他们的类装载器,才去除我心中的疑惑.
    axman:
    我不赞同你没时间的说法,因为从你在我blog发言的积极性和频率上来看,我觉得你是非常有时间的人,这个判断不知对不对?
    #fafa 发表于2006-08-28 23:37:00  IP: 210.77.26.*
    好多天来,看了好几篇张老师发的blog,一直都没有感觉有什么不
    妥的地方,大家何必非要和张老师过不去呢。
    我想大家可能都有一种不服气感觉,也许张老师比起我们可以算是
    公众人物,所以我们心里就默认他必须比我们强很多,牛很多,否则我们不会买他的账的。暂且不论张老师比我们的水平强多少,但是我感觉张老师如果一对一比,我想我们当中可能百分之九十的都不如他的知识全面。另外,之所以称人家为老师,并不意味着他就应该非常非常的牛,相反,老师的职责是传道解疑的。在这方面张老师还是很成功的,因为讲同样的东西,他讲的比别人更清楚,更易懂,这就足够了。另外,还有一点,大家都是从高中,大学而来,现在相比咱们高中的老师的水平,我们应该更高些,可是当这些老师发表篇文章,写本书,我们是不是也会去挑刺呢,挖苦呢,
    我想大家都不会,因为人家不是给你讲的,是讲给不会的人听得。
    我不是什么大牛,我从张老师这儿还是学到很多东西的,尤其是其刨根问底的精神,在此感谢张老师
    #笑了 发表于2006-08-29 02:15:00  IP: 221.233.224.*
    to张:
    发了这帖子,只能说你这么多年都白活了。

    不管有没人可以答出你的问题,失败的都是你。懂不懂我意思?

    发贴的那瞬间,你已经处于失败的位置
    #asklxf 发表于2006-08-29 09:36:00  IP: 221.220.187.*
    另外张老师您的编码也太不规范了,extends ClassLoader的类命名为MainClass我还以为是main的入口呢,换成MyClassLoader, TestClassLoader更容易维护
    #最后一言 发表于2006-08-29 09:26:00  IP: 210.82.61.*
    从上面回复中大家可以看到此人的品格,
    说实话这个问题如果不看源码很难说到底什么原因,可能的原因是10000个那要看ant的代码是如何写的,而当我看了ant的源码,前后不到十分钟就知道问题的所在.和解决方法.其实看过源码后,问题很简单,象张这种"专门研究"这种问题的人,如何不知道去看源码,看了源码而不能解决还有什么脸在这儿乱吠?作为网友提出一些意见竟然让张以如此小人之心来回应,实在恶心!

    ant的Launcher并不是直接以命令行来直接执行java.exe的,当然不可能和真正在命令行下执行的效果一样.而是经过反射又重新调用了一个自己的clder,然后用自己的Main类去执行,这其间默认的clder已经没有"委托"功能,因为已经由ant自己重新加载的特定clder来工作,对于这个特定clder来说,在没有下级clder时也就是没有指定的clder时遵循全盘负责原则,即一个类由这个clder加载,则和它相关的类也由它加载,除非它本身又调用了指定clder.而这个clder本身是动态加载的,不会从boot classpth中去找AuxiliaryClass,所以这个类最终只能由MainClass加载.

    要想解决当然很简单,只要修改Launcher,把对ant的Main的调用改为直接的Runtime.exec调用就行了.
    #asklxf 发表于2006-08-29 09:30:00  IP: 221.220.187.*
    axman是正确的,比如自己写一个MyClassLoader.loadClass("java.util.ArrayList")得到的Class肯定是核心类加载器加载的,而不是MyClassLoader加载的,双亲模型是JVM的规范,不可能违反。

    但是我没有测试过自己写的ClassLoader能不能指定扩展类加载器作为其父类加载器,如果可以,那么就可以替代类路径加载器,这样即使定义了Classpath但是自定义的ClassLoader不受Classpath影响。
    #哈哈 发表于2006-08-29 10:50:00  IP: 210.82.61.*
    哈哈,asklxf,你没有测试说明"你搞不定这个问题而又想要面子的托词",你说你手上的笔记本电脑没装java测试环境,或者说你没有安装ant,没有下载an脚本都是你搞不定又想要面子的托词.

    作为一个程序员,你手头如果不随时准备张某人要的东西,包括为他的测试需要的一切环境,那你就是搞不定又要面子的托词.所以作为一个程序员,你一定要随时准备一切环境用来测试张某人的大作!
    #Shutra 发表于2006-08-29 10:53:00  IP: 222.66.131.*
    第4步时缺少cn.itcast.MyClassLoader类。
    #Shutra 发表于2006-08-29 10:37:00  IP: 222.66.131.*
    这个blog是老师的么?
    怎么字里行间透露着一种让人恼火的恶心呢?
    不要骂我。

    至于“为了便于高手们快速了解我的问题所在,也便于一些中手们学习,我写出了详细的实验步骤,对于java新手,建议不要参与讨论了,免得我耽误了您宝贵时间。”
    那就算我自愿耽误我自己的时间吧。

    正在下载ant中……
    #风 发表于2006-08-29 11:18:00  IP: 222.183.191.*
    同意 Shutra 的观点, 为人师表, 不要像网上二十岁出头的小孩, 这样对你的形象有很大的影响.

    “为了便于高手们快速了解我的问题所在,也便于一些中手们学习,我写出了详细的实验步骤,对于java新手,建议不要参与讨论了,免得我耽误了您宝贵时间。”

    这句话的的确确让人看了反感, 不管你是处于好心, 还是影射某些垃圾, 作为一个老师都不应该这么说. 老师说话就应该光明正大, 一就是一二就是二, 不要含沙射影, 也不要指桑骂槐.

    如果你这句话, 没有含沙射影, 那么就说都不该说. 因为, 三人行必有我师, 尺有所短寸有所长, 在计算机世界里面新手和老手没有这么明显的区别的. 就象 Bruce Eckel 大师, 都说过 "废弃 stop() 方法的原因是它不释放线程获得的锁..." 这样的昏话. 谁没有不昏不时候, 你认为不解的问题很可能就是一个新手才学到的一个小细节出了错, 他就可以给你指出 (我是说可能, 一切皆有可能). 所以说这样的话, 要么是你自以为牛, 要么是含沙射影, 至少, 让别人这么认为你自以为牛, 或者含沙射影.
    #bluedream 发表于2006-08-29 17:04:00  IP: 210.28.131.*
    提出的问题有讨论的价值,不过这人说话怎么这样呢?
    #可笑 发表于2006-08-29 21:35:00  IP: 222.35.77.*
    老张,最近急了。欲证明自己‘高手’的地位。其次‘张老师‘想借此炒作一下,拉拉自己的名气,给自己的培训班提高点知名度,最后无非是多获得利益。


    #李辉 发表于2006-08-29 19:40:00  IP: 220.113.46.*
    路过~~~
    #microrain 发表于2006-08-30 09:19:00  IP: 218.247.0.*
    交流就是交流为什么要多出那么事情来呢。
    #axers 发表于2006-08-30 11:43:00  IP: 221.3.101.*
    不知道的真不敢相信---這是張某人的Blog

    謙虛一點好。。。
    #你们没看出来老张急了吗?真是的 发表于2006-08-30 11:25:00  IP: 222.212.113.*
    你们没看出来老张急了吗?真是的
    #java6 发表于2006-08-30 12:19:00  IP: 61.139.69.*
    张老师是不是曾经受过很严重的BS,意欲借此翻身?这个擂台摆的太失败了。我先承认我不是高手,完全弄不明白张老师的问题。难道张老师眼中“真正的java高手”就是来研究这些的么?研究了一个ant的源码就是高手了么?张老师在文中提到“由于本人才学疏浅,且实在没有精力去研究ant工具的源码,无法了解其类加载内部细节”所以才有此问题,而问题的关键也是“为什么在ant环境下运行,MailClass类加载器没有委托其父级类装载器AppClassLoader加载AuxiliaryClass类,而是自己加载了呢?”可见张老师找的是ant高手而不是java高手,建议张老师先把题目改了。张老师自己没时间来研究ant的源码,反倒误导别人来浪费时间,做些完全无益于生产力发展的事情。是不是有点祸国殃民呢?
    作为一个java的非高手,我深深的BS这种行为!
    #g9 发表于2006-08-30 12:41:00  IP: 74.116.36.*
    我有罪,忍不住跳坑了。这里是部分解答:http://blog.csdn.net/g9yuayon/archive/2006/08/30/1143459.aspx :-)
    #剑神一笑 发表于2006-08-30 13:05:00  IP: 222.212.2.*
    做C++的,不玩JAVA,但楼主的措词真让人恶心

    还培训"精英"呢...
    #回复:g9 发表于2006-08-30 14:15:00  IP: 221.222.77.*
    兄弟,佩服!佩服,心服口服!
    我这人最大的弱点就是爱憎分明,不圆滑!不过,我不怕事,不在意别人的评价,呵呵!所以,我一直自由自在地生活,想干什么就干什么,想说什么就说什么.我这篇文章只要等到你的应答就可以了,其他人的评论我根本没当回事,只要这些人骂完后解气,那多骂几句又何妨,我依然毫发未损!不过,还是想提醒一些自作聪明的人,对对g9兄弟的解答,再想想自己是不是太自以为是了!特别是"最后一言"同志,在这牛了一吧,可惜的是,估计世上没有一个能看懂他在说什么,尽管我很努力地去揣摩这哥们想说什么,但就是看不懂,不知道这哥们是不是觉得他很有表达能力?还有,我写成MainClass又怎样?为了简化例子和与前面的步骤衔接,我何必再去定义一个MyClassLoader(虽然我课堂上的例子确实是MyClassLoader),没想到这也被人挑刺.我说出来,只是想让这些人也反思反思,如果不愿反思,再骂几句也行,我对我以之为朋友的人责难我的心理承受能力极其脆弱,但对其他我懒得理的人责难我的心理承受能力超强.
    另外,这里不少看客都是培训中心的主,最关注我的人是这些培训中心的人,最看我不顺眼的也是这些培训中心的人,骂得最多的也是这些人,不过,我没这些人阴暗,我敞开培训中的一切,向社会展示最真实的情况,而不向其他一些人,把丑恶的东西伪装起来,为了钱财,不择手段,我没有绝对证据说是哪家培训机构的人在骂我,所以我也就不揭露你们培训的黑幕了,但希望你们自重.如果你觉得你的培训好,那就把你的培训情况向社会大众敞开吧!让你们的学员来评价评价你们吧,我敢肯定,没几个敢这么做的!
    #蛇虫 发表于2006-08-30 17:04:00  IP: 220.195.40.*
    我去~
    原来以为只有我最能喷,走到这里才发现还差得远,攒点资源变地刺吧
    #片云 发表于2006-08-30 17:50:00  IP: 61.51.150.*
    本人也是受张老师的视频(下载的)启蒙的,他让我这个非计算机专业的人也可以理解java,能走向编程之路......
    #片云 发表于2006-08-30 17:38:00  IP: 61.51.150.*
    曾经,我以为程序员,it工程师是很了不起的人物,是一群高素质的知识分子.他们聪明,他们谦虚,他们谨慎.他们面对机器,面对代码,没有"人世"的恶俗,有着共同的追求--技术,提高生产力,推动人类进步...

    今天,还想涉足it,程序,只因对它的热爱的我,有些望而却步!!

    我看到的不是技术,而是为了钱的你争我斗,恶意中伤."钱"为何物?生不带来,死不带去,何苦?!!

    中国,IT,程序,我拿什么去爱你......!!!
    #爱好者 发表于2006-08-30 22:28:00  IP: 125.76.184.*
    以前看了你的视频感觉 你这个老师还不错

    还拉了几个朋友准备去上你的培训

    可是现在每次看了你的BLOG 就很气愤

    会点编程 就了不起??

    天天卖弄就罢了 谁没点虚荣心呢

    可搞得自己是JAVA的鼻祖一样 谁都没你牛
    唉 你是什么玩意? 还好没有买你的视频教程
    真是糟蹋钱了
    #回:爱好者 发表于2006-08-31 06:55:00  IP: 221.216.21.*
    幸好你没来,我最怕收到与我合不来的学员,我一直的期望就是只教那些只对我有兴趣和认同我的学员,如果给不认同你的人上课,那对两者都是痛苦.如果有一种识别机制,在没有培训之前就能够识别出哪些是不赞同我的就好了.我很认真,但方式并不适合每个人,如果能提前知道哪些人无法接受我教学和性格,那这些人给多少钱,我都不会收的.事实上,我们这次已经拒绝了十几位特别想学的学员,用的方式仅仅是测试题目,日后,我们不仅用技术测试题,还要对一个人的性格进行测试,合得来就收,合不来,还是请您到别处去转转吧!
    看来.这个blog不是坏事,可以让大家提前了解我,喜欢我这种性格的就来,不喜欢的就不来,正好省去了日后培训期间可能的麻烦!
    #Leefj 发表于2006-08-31 08:39:00  IP: 61.175.133.*
    讨论技术问题就是讨论技术问题,再牛的人也有不懂的东西,为什么卒可以吃掉将,就是这个 道理吧。发个贴问个问题都那么麻烦,我看楼上回复的朋友们是够无聊的。

    #hoho 发表于2006-08-31 11:17:00  IP: 219.133.233.*
    这里的人真无聊,别人发个帖子你觉得值得看就多看两眼,不值得看走人, 还偏要在这里长篇大论一番,就怕别人不知道你很牛似的。真的觉得自己时间多没事情干的牛人最好自己写点东西出来。别在这里瞎折腾,累不累啊你。。
    #有趣 发表于2006-08-31 12:08:00  IP: 60.16.98.*
    he

    喜欢我这种性格的就来,不喜欢的就不来,

    你什么性格? 唯我独尊的性格 可惜了只是YY
    #axman 发表于2006-08-31 20:35:00  IP: 220.207.178.*
    g9兄弟,我无意于与你争论什么,但你的分析确实不能算正确或完整,只是可笑张某人自己根本没有理解还装着以为"然"之状,真是可怜,如果不是其那副嘴脸,我上面已经说得清楚了.一般人如果静下心想一想就可以看出来.

    在运行ant的luncher时,这两类确实已经被系统的clder load进来了.5和6说明了这个问题.其实7时AuxiliaryClass.class同样在内存中,但这时执行MainClass的loadClass(args[0])时,它的parent clder并不是系统默认的clder,如果要说BUG,这不是nat的BUG,而是调用者的BUG,因为你重载了findClass却没有重载definClass,要真正实现委托应该调用真正加载classpath的那个clder,而这里ant事实上在luncher中动态声明一个URLCloader,让它加载Main,而把tag传给Main的去执行的时候把这个动态生成的clder设不null,

    man.startAnt(args,null,null);
    这样MainClass再请求父加载器时已经找不到.但这不能说是实现的BUG.

    比如我有一个方法:
    class A{
    public static void logCaller(){
    System.out.println(Reflection.getCallerClass(2));
    }
    }

    如果你调用的时候
    calss Test{
    void a(){A.logCaller()}
    }

    当然是正确的,但如果
    calss B{
    static void logCaller(){A.logCaller()}
    }

    calss Test{
    void a(){B.logCaller()}
    }
    这当然是调用者的问题而不能说是
    Reflection.getCallerClass(2) 的bug,因为你自己在其它多加了一层调用.
    #wavlet 发表于2006-08-31 20:37:00  IP: 64.86.141.*
    I didn't look into deeply,and let me hand dirty.But I guess the reason is in your build.xml.Pls look your javac section for AuxiliaryClass.java,change destdir to $classdir,then see what will happen
    #wavlet 发表于2006-08-31 20:52:00  IP: 64.86.141.*
    Sorry I meant other dir instead of "."."."is current dir.
    #王者 发表于2006-09-01 11:18:00  IP: 125.76.173.*
    喜欢我这种性格的就来,不喜欢的就不来,

    你什么性格? 还拒绝了十几位....


    真牛.... 最近疯了吧?
    #frank 发表于2006-09-01 12:29:00  IP: 202.130.186.*
    张老师,我非常支持你,在中国这种教育体制下,是需要你这样的人来为学生做点事情的,刚才看了那么多网友的评论,有正面的,也有负面的,我也接触到不少中国所谓的程序员,我个人觉得张老师可以完全不用去理会那些攻击你的人,他们其实才是可怜虫,专心做自己的事情,我觉得才是最重要的!同时我在这里也说一句,其实编程开发这一行确实有高手,但不是你我这样子的,而是那些有天赋的天才,在中国,越低级,越不懂行的人才会在那里牛气冲天的装牛,才会去贬低别人,所以我觉得张老师完全没必要去理会,他们不足与之为谋,还没资格!
    #KAO 发表于2006-09-02 07:25:00  IP: 222.35.235.*
    他们其实才是可怜虫,
    ~~~~~~~~~~~~~

    那你自己呢?恐怕最可怜吧?
    #fans 发表于2006-09-02 09:26:00  IP: 221.218.33.*
    张老师,我就是这次没有通过你们测试的一个求学者,我正在努力学习中,打好基础,争取能参加你的下一个培训班!尽管我被你们拒绝了,但我坚决支持你!
    #frank11 发表于2006-09-02 13:38:00  IP: 202.130.186.*
    那位叫做KAO的仁兄真是语出惊人,这不得不让我真的相信现在中国JAVA开发者真是鱼龙混杂,有真有实力的,也有如KAO这位这样捣乱而搞人身攻击的。这不得不让我怀疑那个叫KAO的,你身后是不是藏着什么不可告人的秘密?
    #哈哈 发表于2006-09-04 15:25:00  IP: 58.38.88.*
    你们再这样搞,老张就要吐血了~~
    #只谈技术细节 发表于2006-09-04 21:34:00  IP: 59.107.12.*
    ANT脚本里似乎这样写要好一些:)增加个删除:)

    <target name="init">
    <delete dir="${classes.dir}"/>
    <mkdir dir="${classes.dir}"/>
    </target>
    #ANT 发表于2006-09-04 21:48:00  IP: 59.107.12.*
    引用:这个实验说明CLASSPATH环境变量对ant起了作用

    因为有CLASSPATH与无CLASSPATH
    ANT是运行不同的命令:

    无CLASSPATH时运行
    "%_JAVACMD%" %ANT_OPTS% -classpath "%ANT_HOME%\lib\ant-launcher.jar" "-Dant.home=%ANT_HOME%" org.apache.tools.ant.launch.Launcher %ANT_ARGS% %ANT_CMD_LINE_ARGS%

    有CLASSPATH时运行
    "%_JAVACMD%" %ANT_OPTS% -classpath "%ANT_HOME%\lib\ant-launcher.jar" "-Dant.home=%ANT_HOME%" org.apache.tools.ant.launch.Launcher %ANT_ARGS% -cp "%CLASSPATH%" %ANT_CMD_LINE_ARGS%
    可以看到:增加了-cp "%CLASSPATH%",就起作用了:)
    #非典型大飞猪 发表于2006-09-06 17:04:00  IP: 218.12.56.*
    #刘德华 发表于2006-09-08 12:56:00  IP: 210.22.176.*
    同意axman的观点


    #无名过客 发表于2006-10-16 17:10:00  IP: 221.174.18.*
    我也看过张老师的JAVA视频讲座
    讲的很好 很喜欢
    可是今天第一次来到这里
    看了张老师BLOG 就这一篇
    我觉得 张才师的话确实有些过火了呢
    尽管 回帖的网友也有说话难听的地方
    但张老师的有些措辞也是让人看了不舒服的

    学高为师 身正为范
    张老师可不可以更加大度一点
    这样 我想喜欢您的人会更多一些
    #剑客狼心 发表于2006-10-16 22:50:00  IP: 222.91.105.*
    自己会不会,先骂别人解解心头的闷气,这就是当前某些人的管理方式,还以为中国是愚民啊
    有些人,人家之所以高培训就要求人家这个那个的,这个责任是谁定的,人家只是挣钱吃饭,别那样了
    如果讨论技术,我们就应该只针对他的技术观点进行攻击挑刺,不要搞其他人身攻击,请问,又有谁能够做到这一点,借别人技术上的缺点而攻击人家其他方面,是不是有些卑鄙呢,就事论事就行了呗。骂人的有本事先搞清楚问题本身让人家服了你的本事再说,上来第一局就指三道四的而与问题本身不顾,目的何在呢,如果说是看不惯某人的什么而骂,是不是为了满足自己的某些私欲呢,在现实中得不到满足来这里YY,可悲,我认为争论的气氛是对的,但借着这个机会攻击人身,发泄私愤的才是中国的耻辱!
    #new舰影 发表于2006-10-21 13:21:00  IP: 220.168.77.*
    首先我说声抱歉,因为我机器里那十多G的张老师视频是免费下载的。我从大二接触java时就喜欢上了这种语言,我现在正在一家专门的java培训机构培训。
    培训中心陈老师也说过类似张老师在视频里的话,我觉得走前面的人们是应该给我们这些学生多做些实在的事。
    选择培训,不是我想去。而是中国的专本教育让我去的。学校开的课程只是为了完成那个课程表。有几个学校会开struts、spring、hibernate以及ejb。估计没几个老师能够教吧,虽然这些都没想象种那么难。
    就像我们大部分企业的软件文档一样,走的是捷径,培训也是捷径。起码来培训的人都是有这爱好的,比起一寝室的人在游戏狂热中,你独自一人coding来的好。
    为了中国软件业的未来,请有些人学学张老师以及类似他的人
    #卷毛 发表于2006-11-02 12:34:00  IP: 219.133.75.*
    "....
    axman:
    你的回答虽然对这个问题没有帮助,但你分析问题的思路对人有启发和帮助.虽然你很有经验,但你对这个问题并不在行,虽然你说没时间,但我知道你是搞不定这个问题而又要面子的托词...."
    从张先生的回答来看,一点都不谦虚啊.
    #hulizhong 发表于2008-04-16 01:48:23  IP: 218.28.133.*
    路过
    发表评论  


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