2017-05-16 48 views
0

我試圖在頂級Main class內調用2個不同版本的相同依賴庫(jars)。所以我創建了一個具有2個實現類的接口,兩個類都有一個使用普通API的運行方法,一個將使用somejar-1.0.0-SNAPSHOT.jar,另一個將通過顯式調用ClassLoader使用somejar-2.0.0-SNAPSHOT.jarjava.lang.NoSuchMethodException Java

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 

爲什麼我得到這個錯誤?如何解決這個問題?

+1

給你一個類的默認構造函數。 – pvg

+0

不是java隱式地爲EngineV1和EngineV2創建一個無參數構造函數? – mosawi

+0

是Java在編譯時爲您生成它,但我認爲您在EngineV1中聲明瞭一個無參數構造函數。 – davidxxx

回答

3

當您在類中聲明構造函數時,不會在編譯時生成不帶參數的默認構造函數。

有兩種方式:

  • 明確添加不帶參數的構造函數。

  • 通過反射調用具有參數的構造函數。

第一種方式是最簡單的竅門,是一個非常通用的方式,但它不一定是最好的方式,如果它的事項創建時看重的實例的部分國家或一個。

對於第一種情況,這是不言自明的。
對於第二種情況,這個想法是你必須從類中檢索帶有參數的構造函數,並在使用它時指定參數。

例如使用此構造函數:

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

這工作,並感謝您的解釋。 – mosawi

+0

@mosawi歡迎您:) – davidxxx

0

如果沒有在類中定義構造函數則只有編譯器將創建一個NO- arg你的類的構造函數。

但在你的情況下,你正在定義一個參數化構造函數,在這種情況下,你需要提供一個反射的構造函數來通過調用它來創建實例。

或者您也可以通過調用getConstructor()方法,然後調用的newInstance()對檢查類可用的構造函數。

按照以下鏈接瞭解更多信息: http://docs.oracle.com/javase/tutorial/reflect/member/ctorInstance.html

相關問題