Java 动态类加载器抛出 ClassNotFoundException

Java Dynamic classloader throws ClassNotFoundException

我有一个项目有自己的 classloader。 但是我在加载一些 classes 时遇到了一个奇怪的问题。

基本上是这样的:

@Override
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException
{
    // do some magic
    return myBrandNewClas;
}

但是发生的是,即使返回 class,Class.forName(...) 仍然抛出 ClassNotFoundException (示例可在 here 中找到)。

另一个信息:返回的 class' 名称与请求的 class 名称不同。

我开始怀疑它是不是JVM的安全锁(在Oracle JVM中测试过)。

谢谢!

forName 的代码是原生的,因此很难看到,但是我会说名称已经过检查,因为传递正确的名称是有效的:

public class BBB
{
public static class a {

}

private static class MyCL extends ClassLoader
{
    @Override
    protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException
    {
        System.out.println("Hi, " + a.class.getName());
        return a.class;
    }
}

public static void main(String[] args) throws ClassNotFoundException
{
    MyCL cl = new MyCL();

    System.out.println(Class.forName("com.asg.util.BBB$a", true, cl));

}

我可以通过将 class 重命名为所需的 class 名称来解决问题。

import javassist.ClassPool;
import javassist.CtClass;


public class AAA
{
    public static class B
    {
        @Override
        public String toString()
        {
            return "B";
        }
    }

    private static class X extends ClassLoader
    {
        @Override
        protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException
        {
            try
            {
                if ("A".equals(name))
                {
                    ClassPool cp = ClassPool.getDefault();
                    CtClass clazz = cp.get("AAA$B");

                    clazz.setName("A");
                    return clazz.toClass();
                }

                return super.loadClass(name, resolve);
            }
            catch (Exception e)
            {
                throw new RuntimeException(e);
            }
        }
    }

    public static void main(String[] args) throws Exception
    {
        X x = new X();
        System.out.println(Class.forName("A", true, x).newInstance().toString());
    }
}

目前为止效果很好。现在我将这段代码放入我的项目中。