public void testLoaderDiffJar() throws ClassNotFoundException, MalformedURLException, InstantiationException, IllegalAccessException {  ClassA orgA = new ClassA();
  orgA.print();  File classesDir = new File("C:\\ClassA.jar");  ClassLoader parentLoader = ClassA.class.getClassLoader();
  URLClassLoader loader1 = new URLClassLoader(
    new URL[] { classesDir.toURL() }, parentLoader);
  Class cls1 = loader1.loadClass("com.my.test.loader.ClassA");
  ClassA a = (ClassA) cls1.newInstance();
  a.print();
}----------------
问题:ClassLoader上来的类并没有替换原先的类。a.print();出来的信息还是旧的,请问这是为什么?

解决方案 »

  1.   

    想跟JVM玩花招,死了这条心吧!要是在主程序运行的当前目录下有一个没有包名限制的ClassA.class文件,
    同时在C:\\ClassA.jar文件中又有一个有包名com.my.test.loader的ClassA.class,
    同时在主程序运行的当前目录下又有com\my\test\loader\目录,该目录下又有一个ClassA.class,您说JVM或javac该怎么办???
    ClassA a = (ClassA) cls1.newInstance()会发生什么???
    要么编译通不过,要么ClassCastException,要么ClassA都是上面三者中的同一个ClassA,
    这种安全问题不需要您挖空心思去想了。
      

  2.   

    你没有明白 ClassLoader的 运行机制ClassLoader在加载类的时候回首先把请求委托给它的父loader(也就是 你代码中的parentLoader ) 去加载所以你的URLClassLoader在加载 ClassA的时候 会调用自己的父Loader 去加载而这是 ClassA 已经被记载了,因为你前面的代码有ClassA 的操作所以就出现了这种情况要达到你的目的,要将 URLClassLoader 的机制改写一下 不让它委托加载在defineClass(方法名我记不清出了)里面可以改写 你自己试试 不明白再交流
      

  3.   

    当父类 classloader 查找失败时,当前 classloader 的 findClass 才被调用。
      

  4.   

    /*
    JDK版本:jdk1.4.2与jdk1.6.0目录文件位置:
    F:\csdn\20070129\ClassA.class
    F:\csdn\20070129\ClassA.java
    F:\csdn\20070129\ClassA.jar
    F:\csdn\20070129\my\ClassA.class
    F:\csdn\20070129\my\ClassA.javaF:\csdn\20070129\ClassA.jar文件内容:
    my\ClassA.class
    my\ClassA.java
    编译: F:\csdn\20070129>javac ClassA.java my\ClassA.java
    打包: F:\csdn\20070129>jar -cvf ClassA.jar my
    运行: F:\csdn\20070129>java ClassA
    结果: 请猜一下????????能用双亲委派的原理分析出正确结果吗?????????最后: 试试在getClassLoader()后加“.getParent()”看看结果如何?????????
      试试在ClassA前加“my.”看看结果又是如何?????????
    */
    //F:\csdn\20070129\my\ClassA.java源码
    package my;
    public class ClassA{
    public void print() {
    System.out.println("my HACK ClassA");
    }
    }//F:\csdn\20070129\ClassA.java源码
    import java.net.*;
    import java.io.*;
    public class ClassA extends ClassLoader {
    public void print() {
    System.out.println("my ClassA");
    }

    public static void main(String[] args) {
    System.out.println("第一种方式:");
    System.out.println("-----------------------------------");
    ClassA orgA = new ClassA();
    orgA.print();
    System.out.println("ClassLoader name: "+ClassA.class.getClassLoader());

    File classesDir = new File("ClassA.jar"); try {
    System.out.println("\r\n第二种方式:");
    System.out.println("-----------------------------------");
    ClassLoader parentLoader = ClassA.class.getClassLoader();
    URLClassLoader loader = new URLClassLoader(
    new URL[] { classesDir.toURL() }, parentLoader);
    Class c = loader.loadClass("my.ClassA");
    System.out.println("ClassLoader name: "+c.getClassLoader());
    ClassA a = (ClassA) c.newInstance();
    a.print();
    } catch (Throwable e) {
                e.printStackTrace();
            }
            
            try {
    System.out.println("\r\n第三种方式:");
    System.out.println("-----------------------------------");
    Class c = new ClassA().findClass("my.ClassA");
    System.out.println("ClassLoader name: "+c.getClassLoader());
    my.ClassA a = (my.ClassA) c.newInstance();
    a.print();
    } catch (Throwable e) {
                e.printStackTrace();
            }
            
            try {
    System.out.println("\r\n第四种方式:");
    System.out.println("-----------------------------------");
    URLClassLoader loader = new URLClassLoader(
    new URL[] { classesDir.toURL() }, new ClassA());
    Class c = loader.loadClass("my.ClassA");
    System.out.println("ClassLoader name: "+c.getClassLoader());
    my.ClassA a = (my.ClassA) c.newInstance();
    a.print();
    } catch (Throwable e) {
                e.printStackTrace();
            }
        }
        
        protected Class findClass(String className) throws ClassNotFoundException {
         byte classData[]=null;
         try {
         String fileName=className.replace('.',File.separatorChar)+".class";
         System.out.println("fileName: "+fileName);
         FileInputStream fis = new FileInputStream(fileName);
        BufferedInputStream bis = new BufferedInputStream(fis);
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int c = bis.read();
    while (c != -1) {
    out.write(c);
    c = bis.read();
        }
        classData=out.toByteArray();
        fis.close();bis.close();out.close();
    } catch (Exception e) {
                e.printStackTrace();
                throw new ClassNotFoundException();
            }
            return defineClass(className, classData, 0, classData.length);
    }
    }
      

  5.   

    KRplusSRequalGOD(狂人+善人=神) 说得对。如果
        Class cls1 = loader1.loadClass("com.my.test.loader.ClassA");
    载入的真是 "C:\ClassA.jar" 里的那个 class
        ClassA a = (ClassA) cls1.newInstance();
    就会发生 ClassCastException 了,因为它们虽然名字一样,却不是同一个东西。
      

  6.   

    上面的解释很全面啊,那我就说说楼主的代码怎么改吧(有骗分嫌疑^_^):
     ClassLoader parentLoader = ClassA.class.getClassLoader();
      URLClassLoader loader1 = new URLClassLoader(
        new URL[] { classesDir.toURL() }, parentLoader);
    首先:parentLoader不用设,直接给个null强制让自己加载,而不是通过父loader加载。
      Class cls1 = loader1.loadClass("com.my.test.loader.ClassA");
      ClassA a = (ClassA) cls1.newInstance();
    不能强制转换,因为转换的类不是你从URL中加载的类。所以这两行代码可以改为:
    Method method = cls1.getMethod("print", null);
    method.invoke(this, null); //this换成你自己的对象就可以了。
      

  7.   

    借宝地保存一下测试代码,以后遇到类似问题方便查看:
    Test.javapackage test;import java.io.File;
    import java.lang.reflect.Method;
    import java.net.URL;
    import java.net.URLClassLoader;public class Test {    public static void main(String[] args) throws Exception {        ClassA.print();
            
            File file = new File("C:/");        URL url = file.toURL();
            URLClassLoader loader1 = new URLClassLoader(new URL[] { url }, null);
            Class cls1 = loader1.loadClass("ClassA");
            Method method = cls1.getMethod("print", null);
            method.invoke(cls1.newInstance(), null);
        }}ClassA.java(有包)package test;public class ClassA {
        
        public static void print() {
            System.out.println("This class is ClassA with pakage test.");
        }
    }ClassA.java(无包)public class ClassA {
           
        public static void print() {
          System.out.println("This class is ClassA that hasn't pakage.");
        }
    }
    输出:
    This class is ClassA with pakage test.
    This class is ClassA that hasn't pakage.