ClassCastException是如何产生的(2)

时间:2022-05-01 22:22:14
--------------------------
如何产生ClassCastException:
--------------------------
AntClassLoader加载HelloWorld.class(它在1.jar),然后new Instance 为HelloWorld1,
URLClassLoader再加载相同的HelloWorld.class(它在2.jar),然后new Instance 为HelloWorld2,
AppClassLoader把HelloWorld1传入到URLClassLoader 加载的ForceConversion.class的instance中,
在ForceConversion的instance中做强制转换 : 将HelloWorld1转换到HelloWorld2.此时出现ClassCastException。

原因:同包名同类名的class被不同的classloader加载,注意这两个classloader不存在parent关系,属于平等地位。
如果将某个classloader的一个class强制转换到另外一个classloader的同名class时候,就会发生ClassCastException。

------------------------
如何制造这个case:
------------------------
1.制作一个HelloWorld.class,打包到c:/1.jar;
2.制作一个ForceConversion.class,将HellWorld和ForceConversion打包到c:/2.jar;
3.此时更改HelloWorld--->HelloWorld1,ForceConversion--->ForceConversion1
4.运行DifferentClassLoader,就会导致ClassCastException。


参考代码:
package com.tools.classloader.data;


public class HelloWorld {
    private String name = null;
   
    public HelloWorld(){
        System.out.println( this.getClass().getClassLoader()+ " is loading "+ this.getClass().getName()+".class ("+this+")");
    }
   
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}



package com.tools.classloader.data;


public class ForceConversion {
    HelloWorld helloWorld2= new HelloWorld();
   
    public void setHelloWorld(Object helloWorld1){
       
        //ForceConversion's classloader
        System.out.println(this.getClass().getName() + "(" + this + ")" + "'s classloader is " + this.getClass().getClassLoader());
       
        //helloWorld1's classloader
        System.out.println("helloWorld1: "+helloWorld1.getClass().getName() + "(" + helloWorld1 + ")" + "'s classloader is " + helloWorld1.getClass().getClassLoader());
       
        //helloWorld2's classloader
        System.out.println("helloWorld2: "+helloWorld2.getClass().getName() + "(" + helloWorld2 + ")" + "'s classloader is " + helloWorld2.getClass().getClassLoader());
        helloWorld2 = (HelloWorld) helloWorld1;
    }

}


package com.tools.classloader;

import java.lang.reflect.Method;

import junit.framework.TestCase;


public class DifferentClassLoader extends TestCase {

    public DifferentClassLoader(String name) {
        super(name);
    }

    protected void setUp() throws Exception {
        super.setUp();
    }

    protected void tearDown() throws Exception {
        super.tearDown();
    }

    public void testClassLoader() throws Exception {
       
        //--------------------------------------
        //         AntClassLoader
        //--------------------------------------
        String[] jars=new String[]{"C:/1.jar"};
       
        AntClassLoaderUtil util=new AntClassLoaderUtil();
        ClassLoader antClassLoader=util.getAntClassLoaderFromJars(jars);
       
        String HelloWorldName = "com.tools.classloader.data.HelloWorld";
        Class HelloWorld1Clazz = null;
        try {
            HelloWorld1Clazz=antClassLoader.loadClass(HelloWorldName);
        } catch (ClassNotFoundException e) {
            System.out.println("class not found");
        }
       
        // new HelloWorld1 instance
        Object HelloWorld1=HelloWorld1Clazz.newInstance();
        Method method1 = HelloWorld1Clazz.getMethod("setName", new Class[]{String.class});
        method1.invoke(HelloWorld1, "HelloWorld1");
       
        method1 = HelloWorld1Clazz.getMethod("getName", new Class[]{});
        Object value1 = method1.invoke(HelloWorld1,null);
       
        //check which classloader is used.
        System.out.println("HelloWorld1's name:"+value1);
        System.out.println("HelloWorld1's classLoader:"+HelloWorld1.getClass().getClassLoader());
       
        //--------------------------------------
        //         URLClassLoader
        //--------------------------------------
        String[] jarsLocation= new String[] {"C:/2.jar"};
        String className="com.tools.classloader.data.ForceConversion";
        Object forceConversion = URLClassLoaderUtil.getInstance(jarsLocation,className);
       
        //将HelloWorld1传入到另外一个classloader的class中去。
        Method method2 = forceConversion.getClass().getMethod("setHelloWorld", new Class[]{Object.class});
        method2.invoke(forceConversion, HelloWorld1);
       
    }
}


package com.tools.classloader;

import java.io.File;
import java.io.FilenameFilter;

import org.apache.tools.ant.AntClassLoader;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.types.Path;

public class AntClassLoaderUtil
{
    public ClassLoader getAntClassLoaderFromDir(String[] directory)
    {
        Project project = new Project();
        project.init();
        Path path = new Path(project, null);
       
        for (int i = 0; i < directory.length; i++) {
          
            File dir = new File(directory[i]);
            String[] filePaths = null;
            if (dir.isDirectory()&& dir.exists()) {
                File[] files = dir.listFiles(new FilenameFilter ()
                    {
                    public boolean accept (File file, String name)
                    {
                      return name.endsWith (".jar") || name.endsWith (".zip");
                    }
                  });
                filePaths = new String[files.length];
                for (int j = 0; j < files.length; j++) {
                    filePaths[j] = files[j].getAbsolutePath();
                    path.setPath(filePaths[j]);
                }
            }
        }

        String[] paths=path.list();
        for (int i = 0; i < paths.length; i++) {
//            System.out.println(paths[i]);
        }
       
        AntClassLoader loader = new AntClassLoader(project, path);
        return loader;
    }
   
    public ClassLoader getAntClassLoaderFromJars(String[] jarspath)
    {
        Project project = new Project();
        project.init();
       
        Path path = new Path(project, null);
       
        for (int i = 0; i < jarspath.length; i++) {
            File jar = new File(jarspath[i]);
            if (jar.isFile()&& jar.exists()&& (jar.getName().indexOf(".jar")>0)) {
               path.setPath(jar.getAbsolutePath());
            }
        }

        String[] paths=path.list();
        for (int i = 0; i < paths.length; i++) {
//            System.out.println(paths[i]);
        }
       
        AntClassLoader loader = new AntClassLoader(project, path);
        return loader;
    }

    public static void main(String[] args) throws Exception
    {
        String[] directorys=new String[2];
        directorys[0]="C:/wasx/lib/";
        directorys[1]="C:/wasx/plugins";
       
        AntClassLoaderUtil util=new AntClassLoaderUtil();
        ClassLoader antClassLoader=util.getAntClassLoaderFromDir(directorys);
       
        System.out.println(AntClassLoader.class.getClassLoader());
        System.out.println(antClassLoader.getParent());
        System.out.println(antClassLoader.getParent().getParent());
        System.out.println(antClassLoader.getParent().getParent().getParent());
       
       
        String RecoveryDataContainerName = "com.ibm.wbiserver.manualrecovery.RecoveryDataContainer";
        try {
            antClassLoader.loadClass(RecoveryDataContainerName);
        } catch (ClassNotFoundException e) {
            System.out.println("class not found");
        }
    }
}


package com.tools.classloader;

import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.sql.Connection;
import java.sql.Driver;
import java.util.Properties;

public class URLClassLoaderUtil {
   
    public static Object getInstance(String[] jarsLocation,String fullClassName ){
        URL[] urls = new URL[jarsLocation.length];
        for (int i = 0; i < jarsLocation.length; i++) {
            try {
                urls[i]= new URL("file:"+jarsLocation[i]);
            } catch (MalformedURLException e) {
                e.printStackTrace();
            }
        }
       
        URLClassLoader ucl = new URLClassLoader(urls);
        Class clazz=null;
        try {
            clazz = ucl.loadClass(fullClassName);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
       
        Object instance=null;
        try {
            instance= clazz.newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
       
        return instance;
    }
 
}