Java 如何在运行时从外部jar访问方法?
这是问题的延续,发布在: 我不确定如何继续到方法调用级别。据我了解,, 从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邪恶警告。代码示例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类型的
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 ();