2017-05-16 16 views
0

トップレベルMain class内の同じ依存関係ライブラリ(jars)の2つの異なるバージョンを呼び出そうとしています。そこで私は2つの実装クラスを持つインターフェイスを作成しました。どちらのクラスも共通のAPIを使用するrunメソッドを持っています。somejar-1.0.0-SNAPSHOT.jarを使用し、もう一方は明示的にClassLoaderを呼び出してsomejar-2.0.0-SNAPSHOT.jarを使用します。ここでjava.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

クラスにコンストラクタを宣言すると、引数のないデフォルトのコンストラクタはコンパイル時に生成されません。明示的に引数なしのコンストラクタを追加


  • 次の2つの方法があります。

  • 引数でコンストラクタをリフレクションすることによって呼び出されます。

最初の方法は簡単なトリックであり、非常に一般的な方法ですが、それは必ずしも最良の方法は、それが作成されたときに、インスタンスの一部の状態または1つの評価に重要ならば。

この最初のケースでは、それは自明です。
2番目のケースでは、コンストラクタをクラスから取得し、それを使用するときに引数を指定する必要があります。
このコンストラクタを持つ例えば

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

クラスで定義されたコンストラクターが存在しない場合のみ、コンパイラは無を作成します。あなたのクラスのコンストラクタarg

あなたのケースでは、パラメータ化されたコンストラクタを定義しています。その場合は、no-argコンストラクタをReflectionに指定する必要があります。

それとも、その後、()メソッドとのnewInstance()その上を呼び出すgetConstructorを呼び出すことによって、あなたのクラスで利用可能なコンストラクタを確認することができます。

詳細については、リンクの下のフォロー: http://docs.oracle.com/javase/tutorial/reflect/member/ctorInstance.html

関連する問題