java.lang.NoSuchMethodException Java

时间:2017-05-16 07:02:46

标签: java reflection classloader

我试图在顶级jars内调用相同依赖库(Main class)的2个不同版本。所以我创建了一个包含2个实现类的接口,这两个类都有一个run方法,它使用公共apis,一个将使用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();
    }
}

当我去主要课程时,我得到了:

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

为什么会出现此错误?怎么解决这个?

2 个答案:

答案 0 :(得分:4)

在类中声明构造函数时,编译时不会生成不带参数的默认构造函数。

您有两种方式:

  • 显式添加没有参数的构造函数。

  • 通过反射调用带有参数的构造函数。

第一种方法是简单的技巧,是一种非常通用的方法,但如果在创建实例时重视状态或部分实例,则不一定是最好的方法。

对于第一种情况,它是自我解释的 对于第二种情况,我们的想法是你必须从类中检索带有参数的构造函数,并在使用它时指定参数。

例如,使用此构造函数:

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

答案 1 :(得分:1)

如果类中没有定义构造函数,那么只有编译器才会为您的类创建 no-arg 构造函数。

但是在你的情况下,你正在定义一个参数化的构造函数,在这种情况下,你需要为Reflection提供一个 no-arg 构造函数来通过调用它来创建实例。

或者您可以通过调用 getConstructor()方法检查您班级的可用构造函数,然后在其上调用 newInstance()

请点击以下链接获取更多信息: http://docs.oracle.com/javase/tutorial/reflect/member/ctorInstance.html