java.lang.NoSuchMethodException Java
java.lang.NoSuchMethodException Java
我正在尝试在顶级 Main class
中调用同一依赖库 (jars
) 的 2 个不同版本。所以我创建了一个具有 2 个实现的接口 classes,两个 classes 都有一个 运行 方法,它使用通用的 api,一个将使用 somejar-1.0.0-SNAPSHOT.jar
,另一个将使用 somejar-2.0.0-SNAPSHOT.jar
通过显式调用 ClassLoader。
public static void main(String[] args) throws MalformedURLException, ClassNotFoundException, InstantiationException, IllegalAccessException {
ClassLoader loader1 = new URLClassLoader( new URL[] { new File("/Users/haddad/.m2/repository/com/company/somejar-1.0.0-SNAPSHOT.jar").toURL() });
ClassLoader loader2 = new URLClassLoader( new URL[] { new File("/Users/haddad/.m2/repository/com/company/somejar-2.0.0-SNAPSHOT.jar").toURL() });
Class<?> c1 = loader1.loadClass("com.engine.na.EngineV1");
Class<?> c2 = loader2.loadClass("com.engine.na.EngineV2");
IEngine app1 = (IEngine) c1.newInstance();
IEngine app2 = (IEngine) c2.newInstance();
Integer s1 = app1.run();
Integer s2 = app2.run();
Assert.equals(s1,s2,"Outputs from somejar-1.0 and somejar-2.0 did not match, perhaps somejar-2.0 has regressed?");
}
以下是带有接口的 EngineV1 和 V2:
public Interface IEngine {
Integer run();
}
public class EngineV1 implements IEngine {
private File content;
private File en;
public EngineV1(args) {
this.content = new File("/some/path");
this.en = new File("/some/path");
}
public static void main(String[] args) {
new EngineV1(args).run();
}
public Integer run() {
// some logic...
somejar.evaluateSpeed();
}
}
public class EngineV2 implements IEngine {
private File content;
private File en;
public EngineV2(args) {
this.content = new File("/some/path");
this.en = new File("/some/path");
}
public static void main(String[] args) {
new EngineV2(args).run();
}
public Integer run() {
// some logic...
somejar.evaluateSpeed();
}
}
当我转到 运行 主 class 我得到:
Exception in thread "main" java.lang.InstantiationException: com.engine.na.EngineV1
at java.lang.Class.newInstance(Class.java:427)
at com.engine.na.MainClass.main(MainClass.java:23)
Caused by: java.lang.NoSuchMethodException: com.engine.na.EngineV1.<init>()
at java.lang.Class.getConstructor0(Class.java:3082)
at java.lang.Class.newInstance(Class.java:412)
... 1 more
为什么会出现此错误?如何解决这个问题?
当您在 class 中声明构造函数时,编译时不会生成不带参数的默认构造函数。
你有两种方法:
显式添加不带参数的构造函数。
通过反射调用带有参数的构造函数。
第一种方法是简单的技巧,是一种非常通用的方法,但如果在创建实例时对状态或实例的一部分进行估值很重要,则它不一定是最佳方法。
对于第一种情况,它是不言自明的。
对于第二种情况,想法是您必须从 class 中检索带有参数的构造函数,并在使用它时指定参数。
例如这个构造函数:
public EngineV1(String value) {
...
}
你可以这样调用它:
Class<EngineV1> c1 = (Class<EngineV1>)loader1.loadClass("com.engine.na.EngineV1");
Constructor<EngineV1> constructor = c1.getConstructor(String.class);
EngineV1 instance = ctor.newInstance("myString");
如果 class 中没有定义构造函数,那么只有编译器会为您的 class 创建一个 no-arg 构造函数。
但是在您的情况下,您正在定义一个参数化构造函数,在这种情况下,您需要为反射提供一个 no-arg 构造函数以通过调用它来创建实例。
或者您可以通过调用 getConstructor() 方法检查 class 的可用构造函数,然后调用 newInstance()
关注下方 link 了解更多信息:
http://docs.oracle.com/javase/tutorial/reflect/member/ctorInstance.html
我正在尝试在顶级 Main class
中调用同一依赖库 (jars
) 的 2 个不同版本。所以我创建了一个具有 2 个实现的接口 classes,两个 classes 都有一个 运行 方法,它使用通用的 api,一个将使用 somejar-1.0.0-SNAPSHOT.jar
,另一个将使用 somejar-2.0.0-SNAPSHOT.jar
通过显式调用 ClassLoader。
public static void main(String[] args) throws MalformedURLException, ClassNotFoundException, InstantiationException, IllegalAccessException {
ClassLoader loader1 = new URLClassLoader( new URL[] { new File("/Users/haddad/.m2/repository/com/company/somejar-1.0.0-SNAPSHOT.jar").toURL() });
ClassLoader loader2 = new URLClassLoader( new URL[] { new File("/Users/haddad/.m2/repository/com/company/somejar-2.0.0-SNAPSHOT.jar").toURL() });
Class<?> c1 = loader1.loadClass("com.engine.na.EngineV1");
Class<?> c2 = loader2.loadClass("com.engine.na.EngineV2");
IEngine app1 = (IEngine) c1.newInstance();
IEngine app2 = (IEngine) c2.newInstance();
Integer s1 = app1.run();
Integer s2 = app2.run();
Assert.equals(s1,s2,"Outputs from somejar-1.0 and somejar-2.0 did not match, perhaps somejar-2.0 has regressed?");
}
以下是带有接口的 EngineV1 和 V2:
public Interface IEngine {
Integer run();
}
public class EngineV1 implements IEngine {
private File content;
private File en;
public EngineV1(args) {
this.content = new File("/some/path");
this.en = new File("/some/path");
}
public static void main(String[] args) {
new EngineV1(args).run();
}
public Integer run() {
// some logic...
somejar.evaluateSpeed();
}
}
public class EngineV2 implements IEngine {
private File content;
private File en;
public EngineV2(args) {
this.content = new File("/some/path");
this.en = new File("/some/path");
}
public static void main(String[] args) {
new EngineV2(args).run();
}
public Integer run() {
// some logic...
somejar.evaluateSpeed();
}
}
当我转到 运行 主 class 我得到:
Exception in thread "main" java.lang.InstantiationException: com.engine.na.EngineV1
at java.lang.Class.newInstance(Class.java:427)
at com.engine.na.MainClass.main(MainClass.java:23)
Caused by: java.lang.NoSuchMethodException: com.engine.na.EngineV1.<init>()
at java.lang.Class.getConstructor0(Class.java:3082)
at java.lang.Class.newInstance(Class.java:412)
... 1 more
为什么会出现此错误?如何解决这个问题?
当您在 class 中声明构造函数时,编译时不会生成不带参数的默认构造函数。
你有两种方法:
显式添加不带参数的构造函数。
通过反射调用带有参数的构造函数。
第一种方法是简单的技巧,是一种非常通用的方法,但如果在创建实例时对状态或实例的一部分进行估值很重要,则它不一定是最佳方法。
对于第一种情况,它是不言自明的。
对于第二种情况,想法是您必须从 class 中检索带有参数的构造函数,并在使用它时指定参数。
例如这个构造函数:
public EngineV1(String value) {
...
}
你可以这样调用它:
Class<EngineV1> c1 = (Class<EngineV1>)loader1.loadClass("com.engine.na.EngineV1");
Constructor<EngineV1> constructor = c1.getConstructor(String.class);
EngineV1 instance = ctor.newInstance("myString");
如果 class 中没有定义构造函数,那么只有编译器会为您的 class 创建一个 no-arg 构造函数。
但是在您的情况下,您正在定义一个参数化构造函数,在这种情况下,您需要为反射提供一个 no-arg 构造函数以通过调用它来创建实例。
或者您可以通过调用 getConstructor() 方法检查 class 的可用构造函数,然后调用 newInstance()
关注下方 link 了解更多信息: http://docs.oracle.com/javase/tutorial/reflect/member/ctorInstance.html