「Java」同名クラス ( 同名パッケージ) が存在する場合にどのクラスが使用されるか / URLClassLoader について
例えば、以下みたいに同名パッケージで同名のクラスが存在する場合にどのクラスが使用されるのかというのをちょっとみてみました。結論を言うと、クラスパスでより前に指定したものが使われるという感じみたいです ( 該当するクラスが見つかった時点でそいつが使われるという感じですかね。たぶん )。
■ test1.jar としてパッケージング
package test; public class Test { public String test() { return "11111"; } }
■ test2.jar としてパッケージング
package test; public class Test { public String test() { return "22222"; } }
■ jar にはパッケージングせず
package test; public class Test { public String test() { return "33333"; } }
■ Main クラス
import test.*; class Main { public static void main(String[] args) { System.out.println(new Test().test()); } }
※ 一応ディレクトリ構成
[root@centos62 jarLoad]# ls -R .: Main.class Main.java test test1.jar test2.jar ./test: Test.class Test.java
■ 実行結果
[root@centos62 jarLoad]# java -cp .:test1.jar:test2.jar Main 33333 [root@centos62 jarLoad]# java -cp test1.jar:test2.jar:. Main 11111 [root@centos62 jarLoad]# java -cp test2.jar:.:test1.jar Main 22222
verbose:class でロードされたクラスを見てみる。以下の場合は "33333" 返す Test.java のみがロードされてることがわかる。
[root@centos62 jarLoad]# java -cp .:test1.jar:test2.jar -verbose:class Main | grep Test [Loaded test.Test from file:/usr/local/tmp/java/jarLoad/]
クラスパスに指定した順に関係なく、任意のクラス使いたいって場合は URLClassLoader が使えるみたいです。
・URLClassLoader (Java Platform SE 8 )
http://docs.oracle.com/javase/jp/8/api/java/net/URLClassLoader.html
こんな感じです。
■ test1.jar 内の Test.java を使いたい場合
import test.*; import java.net.*; import java.lang.reflect.*; class Main { public static void main(String[] args) throws Exception { URLClassLoader ucl = new URLClassLoader(new URL[] { new URL("file:///usr/local/tmp/java/jarLoad/test1.jar") }, null); Class c = ucl.loadClass("test.Test"); Method m = c.getMethod("test"); System.out.println(m.invoke(c.newInstance())); } }
■ 実行結果
[root@centos62 jarLoad]# java -cp .:test1.jar:test2.jar Main 11111
ちゃんと "33333" 返す Test.java ではなく、"11111" 返す Test.java ( test1.jar ) の test() が呼ばれてますね。ちなみに URLClassLoader の第二引数を指定しないと、おそらく親クラスローダに委譲されるっぽく "33333" 返す Test.java が呼ばれちゃいます。
こっちも verbose:class でロードされたクラスを見てみる。
■ URLClassLoader の第二引数を null に指定する
[root@centos62 jarLoad]# java -cp .:test1.jar:test2.jar -verbose:class Main | grep Test [Loaded test.Test from file:/usr/local/tmp/java/jarLoad/test1.jar]
■ URLClassLoader の第二引数を指定しない
[root@centos62 jarLoad]# java -cp .:test1.jar:test2.jar -verbose:class Main | grep Test [Loaded test.Test from file:/usr/local/tmp/java/jarLoad/]
以上です。