如何在运行时从外部jar访问方法?

时间:2009-08-23 21:47:01

标签: java jar runtime classloader

这是在How to load a jar file at runtime

中发布的问题的延续

我不确定如何继续方法调用级别。根据我的理解, 从clazz对象,我将使用getMethod或getDeclaredMethod来获取一个Method对象,我将从该对象调用invoke。当然,调用需要一个实例。那么在示例代码中那会是什么叫做doRun?

我是否需要执行doRun.run()方法调用,即使我想执行一个不同于main的方法(假设它是使用运行调用调用的doRun对象的主要方法)?

为了进一步澄清原帖,我问: doRun.run()是否启动一个新线程来执行clazz类型的类对象的实例?

感谢您帮我解决此问题。

我确实看过“how-should-i-load-jars-dynamic-at-runtime”(抱歉,只允许一个超链接),但这看起来违反了我引用的第一篇文章中的Class.newInstance邪恶警告

3 个答案:

答案 0 :(得分:3)

这是一些不会转换为接口的反射代码:

public class ReflectionDemo {

  public void print(String str, int value) {
    System.out.println(str);
    System.out.println(value);
  }

  public static int getNumber() { return 42; }

  public static void main(String[] args) throws Exception {
    Class<?> clazz = ReflectionDemo.class;
    // static call
    Method getNumber = clazz.getMethod("getNumber");
    int i = (Integer) getNumber.invoke(null /* static */);
    // instance call
    Constructor<?> ctor = clazz.getConstructor();
    Object instance = ctor.newInstance();
    Method print = clazz.getMethod("print", String.class, Integer.TYPE);
    print.invoke(instance, "Hello, World!", i);
  }
}

将反射类写入消费者代码(as in the example)已知的接口通常更好,因为它允许您避免反射并利用Java类型系统。只有在你别无选择时才能使用反思。

答案 1 :(得分:2)

代码示例

ClassLoader loader = URLClassLoader.newInstance(
    new URL[] { yourURL },
    getClass().getClassLoader()
);
Class<?> clazz = Class.forName("mypackage.MyClass", true, loader);
Class<? extends Runnable> runClass = clazz.asSubclass(Runnable.class);
// Avoid Class.newInstance, for it is evil.
Constructor<? extends Runnable> ctor = runClass.getConstructor();
Runnable doRun = ctor.newInstance();
doRun.run();

假设您要加载的类实现了特定的接口Runnable,因此使用asSubclass()强制转换为该类型并调用run()。

您对正在加载的课程了解多少?你能否假设他们实现了一个特殊的界面?如果是这样,请调整asSubClass()行以引用您喜欢的交互。

然后,是的,如果您正在使用实例方法,请使用构造函数创建一个实例,示例中为 ctor

示例中没有启动线程。创建一个新线程只需要几行代码

Thread myThread = new Thread(doRun);
myThread.start();

答案 2 :(得分:1)

示例程序:

项目打印机:

public class Printer {

    public void display(String printtext)
    {
        System.out.println(printtext);
    }

}

此项目导出为Printer.jar。

Printer Class有方法display(),它将字符串作为输入。

调用代码:

       URL url = new URL("file:Printer.jar"); 
       URLClassLoader loader = new URLClassLoader (new URL[] {url});
       Class<?> cl = Class.forName ("Printer", true, loader);
       String printString = "Print this";
       Method printit = cl.getMethod("display", String.class);
       Constructor<?> ctor = cl.getConstructor(); //One has to pass arguments if constructor takes input arguments.
       Object instance = ctor.newInstance();
       printit.invoke(instance, printString);
       loader.close ();

输出: Print this