繁体   English   中英

动态Java编译和反射加载类的AbstractMethodError

[英]AbstractMethodError with dynamic java compilation and class loading with reflection

我正在尝试以下wrt Refleciton,让我知道是否可能

public class A {
    void start(){
       execute();
     }

}

public class B extends A {
    void execute()
    {
       doWork();
    }
    public abstract void doWork();
}

我将上述类打包在一个jar中,并使其在JVM上运行。 现在,我试图在运行时创建另一个类,在运行时对其进行编译,并尝试使用反射来调用B类的execute function()。

public class C extends B {
     @Override
     public void doWork()
     {
       //Implementation
     }
}

反射代码:

Classloader =应用程序jar的URL和C.class的URL,在运行时进行编译。 父加载器-Thread.currentThread()。getContextClassLoader()我还将当前线程的上下文类加载器设置为上面创建的类加载器。

Class<? extends B> cls = (Class<? extends B>) Class.forName("className", true, clsLoader);

Object obj = cls.newInstance();
Method method = obj.getClass().getSuperclass().getMethod("start", new Class[0]);
method.invoke(obj, new Object[0]);   

我能够获取该方法,并且调用也会被调用。 但是,当调用类B的execute时,它试图调用doWork(),然后遇到AbstractMethodError。 在查找异常后,我发现异常发生在错误的类加载器/ jar中。 但是我不确定如何解决这个问题。

有人可以协助吗?

首先,让我们澄清一个关于Thread的上下文类加载器的神话:除非代码通过Thread.getContextClassLoader()明确地要求该加载器(并使用它),否则它根本与类加载无关。

每个类都有一个初始类加载器,该加载器定义了该类,并且始终通过该初始类加载器解析对该类中其他类的引用。 这甚至适用于通过Class.forName(String)反射性加载(没有显式的ClassLoader ); 它将使用调用者的初始化类加载器。

如果要通过需要访问B的自定义类加载器加载C ,因为C它的子类,那么确定父加载器以创建新加载器的最佳方法是B.class.getClassLoader() 但是,在您的简单设置中,它是与ClassLoader.getSystemClassLoader()返回的ClassLoader.getSystemClassLoader()相同,这也是Thread.getContextClassLoader()返回的默认类加载器,这就是它起作用的原因。

您知道它起作用是因为您可以成功加载C 虽然其他引用可能会延迟解析,但直接超类必须立即解析,因此B属于C的加载器范围。

假设没有声明的execute()Aabstract的修饰class B只是疏忽张贴的问题做出的,为什么调用方法不起作用的原因就简单多了:该方法abstract void doWork(); 不是public

由于BC由不同的类加载器加载,因此无论它们的限定名称如何,它们都被视为驻留在不同的程序包中。 因此,该方法doWork()C不会覆盖该方法doWork()B 在编译时尚未检测到此情况,因为在编译时没有类加载器层次结构。 因此,编译器根据BC的限定名称(或显式包声明)将其驻留在同一包中。 因此,编译器假定C.doWork()实现B.doWork()并且C可以声明为非abstract

如果在B中将方法doWork()声明为public ,则它应该可以工作。 它应该更简单地工作:

try(URLClassLoader l = new URLClassLoader(new URL[]{/* url pointing to C */})) {
    l.loadClass("C").asSubclass(B.class).newInstance().execute();
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM