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

Java 如何在运行时从外部jar访问方法?,java,jar,runtime,classloader,Java,Jar,Runtime,Classloader,这是问题的延续,发布在: 我不确定如何继续到方法调用级别。据我了解,, 从clazz对象中,我将使用getMethod或getDeclaredMethod获取一个方法对象,从中调用invoke。当然,invoke需要一个实例。那么,在示例代码中,这就是所谓的doRun吗 我是否需要执行doRun.run()方法调用,即使我想执行与main不同的方法(假设它是通过run调用调用的doRun对象上的main) 为了进一步澄清原帖,我问: doRun.run()是否启动一个新线程来执行clazz类型的

这是问题的延续,发布在:

我不确定如何继续到方法调用级别。据我了解,, 从clazz对象中,我将使用getMethod或getDeclaredMethod获取一个方法对象,从中调用invoke。当然,invoke需要一个实例。那么,在示例代码中,这就是所谓的doRun吗

我是否需要执行doRun.run()方法调用,即使我想执行与main不同的方法(假设它是通过run调用调用的doRun对象上的main)

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

谢谢你帮我把这件事弄清楚

我确实看过“how-should-I-load-jars-dynamicy-at-runtime”(抱歉,只允许一个超链接),但是这似乎违反了我在第一篇文章中提到的Class.newInstance邪恶警告。

代码示例

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();

以下是一些不会强制转换到接口的反射代码:

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);
  }
}
公共类ReflectionDemo{
公共空打印(字符串str,int值){
系统输出打印项次(str);
系统输出打印项次(值);
}
公共静态int getNumber(){return 42;}
公共静态void main(字符串[]args)引发异常{
clazz类=ReflectionDemo.Class;
//静态呼叫
方法getNumber=clazz.getMethod(“getNumber”);
inti=(整数)getNumber.invoke(null/*static*/);
//实例调用
Constructor=clazz.getConstructor();
对象实例=ctor.newInstance();
方法print=clazz.getMethod(“print”,String.class,Integer.TYPE);
调用(实例“Hello,World!”,i);
}
}
将反射类写入使用者代码()已知的接口通常更好,因为它允许您避免反射并利用Java类型系统。只有在没有选择的情况下才应使用反射。

示例程序:

项目打印机:

public class Printer {

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

}
此项目导出为Printer.jar

Printer类具有方法
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 ();
URL=newurl(“文件:Printer.jar”);
URLClassLoader=新URLClassLoader(新URL[]{URL});
Class cl=Class.forName(“打印机”,true,加载器);
String printString=“打印此”;
方法printit=cl.getMethod(“display”,String.class);
Constructor=cl.getConstructor()//如果构造函数接受输入参数,则必须传递参数。
对象实例=ctor.newInstance();
invoke(实例,printString);
loader.close();
输出:
打印此

djna-感谢您的回复。不幸的是,我不能假设我知道我可能正在加载的类的任何信息。我有一个示例案例,它可能并不表示实际使用情况。目前,我没有子类化,从构造函数中获取一个实例,然后继续使用getDeclaredMethod,类似于下面的文章。感谢其他的澄清,我对运行调用感到困惑,认为这意味着要启动一个新线程-我的错。因此,如果我理解您在代码后面的注释,使用接口,我知道哪些方法可用,并且可以在适当地转换实例对象后直接编写调用该方法的代码。这是真的吗?当然,这假设原始代码是使用接口编译的,而不是我稍后创建并试图将实例强制转换到的接口。@Todd-是的,您已经找到了。接口(或其他一些强类型实现)方法通常与插件一起使用,在插件中,代码被编写为动态实例化。如果您正在对任意类进行内省和调用,则这不是一个选项。@McDowell-我的代码变体不成功。我在主方法中添加了以下方法:public void print2(String[]strings){for(final String:strings){System.out.println(String);}}},方法print2=clazz.getDeclaredMethod(“print2”,新类[]{String[].Class});invoke(实例,新字符串[]{“test1”,“test2”});这导致:线程“main”java.lang.IllegalArgumentException中出现异常:参数数量错误您有什么想法吗?最后一篇文章太乱了,无法阅读,我将生成一篇新文章。
       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 ();