- てま
- 会議室デビュー日: 2007/06/15
- 投稿数: 2
|
投稿日時: 2007-06-15 05:59
URLClassLoaderとgetMethodの関連について
教えていただけませんでしょうか?
コード: |
|
package loader;
import java.lang.reflect.*;
import java.net.URL;
import java.net.URLClassLoader;
import java.io.*;
public class ScreenControl extends Thread {
public void run(){
URL baseURL = null;
File baseDir = null;
try{
baseDir = (new File( "D:\\My Program\\classLoad\\classes\\" )).getCanonicalFile();
baseURL = baseDir.toURI().toURL();
} catch (Exception e){
e.printStackTrace();
}
URLClassLoader loader = new URLClassLoader( new URL[]{baseURL} );
Class<?> clazz;
try {
clazz = loader.loadClass("loader.OptionClass");
} catch (ClassNotFoundException e) {
e.printStackTrace();
return;
}
Method calc1;
Method calc2;
Method calc3;
Object object = null;
try{
object = clazz.newInstance();
} catch (Exception e){
e.printStackTrace();return;
}
try {
calc1 = clazz.getMethod("calc", new Class[]{int.class});
calc2 = clazz.getMethod("calc", new Class[]{String.class});
calc3 = clazz.getMethod("calc", new Class[]{DummyViews.class});
} catch (SecurityException e2) {
e2.printStackTrace();return;
} catch (NoSuchMethodException e2) {
e2.printStackTrace();return;
}
Object ret1 = null; //戻り値
Object ret2 = null; //戻り値
Object ret3 = null; //戻り値
try {
ret1 = calc1.invoke(object, new Object[]{ 3 });
ret2 = calc2.invoke(object, new Object[]{ "3" });
ret3 = calc3.invoke(object, new Object[]{ new DummyViews(3) });
// = object.メソッド((int)1); と同じ
} catch (IllegalArgumentException e3) {
e3.printStackTrace();return;
} catch (IllegalAccessException e3) {
e3.printStackTrace();return;
} catch (InvocationTargetException e3) {
e3.getCause().printStackTrace();return;
}
System.out.println("ret1="+ret1);
System.out.println("ret2="+ret2);
System.out.println("ret3="+ret3);
}
}
|
コード: |
|
package loader;
public class OptionClass{
public int calc( int p ){
return p*4;
}
public int calc( String p ){
return Integer.parseInt(p) * 4;
}
public int calc( DummyViews p ){
return p.calc(4);
}
}
|
コード: |
|
package loader;
public class DummyViews{
int b;
public DummyViews(int f){
b = f;
}
public int calc( int p ){
return p*b;
}
}
|
コード: |
|
package loader;
public class TestMain {
public static void main(String[] args) {
ScreenControl thread = new ScreenControl();
thread.start();
}
}
|
クラスローダーで取ってきたクラスからメソッドを取得しようとしています
実行すると
D:\\My Program\\classLoad\\classes>java loader.TestMain
ret1=12
ret2=12
ret3=12
と出ます。
今度はこれをswingで実行させようと次のクラスを書きました。
コード: |
|
package loader;
import javax.swing.*;
public class JFrameTest {
public static void main(String[] args){
JFrame frame = new JFrame("フレームのタイトル");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setBounds( 10, 10, 300, 200);
frame.setVisible(true);
ScreenControl sc = new ScreenControl();
sc.run();
}
}
|
実行します。
D:\\My Program\\classLoad\\classes>java loader.JFrameTest
ret1=12
ret2=12
ret3=12
これも問題ないです。
ところがIEのプラグインで実行させるとエラーが起きました。
コード: |
|
package loader;
import javax.swing.*;
public class RootInit extends JApplet {
public void init() {
ScreenControl sc = new ScreenControl();
sc.run();
}
}
|
コード: |
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<HTML>
<HEAD>
<TITLE>index.html</TITLE>
</HEAD>
<BODY>
<OBJECT classid="clsid:8AD9C840-044E-11D1-B3E9-00805F499D93"
width="800" height="600" align="baseline"
codebase="http://java.sun.com/products/plugin/1.4/jinstall-14-win32.cab#Version=1,4,0,mn">
<PARAM NAME="code" VALUE="loader/RootInit">
<PARAM NAME="codebase" VALUE="classes">
</OBJECT>
</BODY>
</HTML>
|
index.htmlをIEで開きます
ava.lang.NoSuchMethodException: loader.OptionClass.calc(loader.DummyViews)
at java.lang.Class.getMethod(Unknown Source)
at loader.ScreenControl.run(ScreenControl.java:49)
at loader.RootInit.init(RootInit.java:12)
at sun.applet.AppletPanel.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
とJavaコンソールにでました
どうやらメソッドが見つからなかったようです
おなじプログラムなのにどうして動きがちがうのでしょうか?
<動作環境>
WindowsXPsp2
Java 1.6.0_01-b06
IE 6.0.29
Java Plug-in 1.6.0_01
|
- 朝日奈ありす
- 大ベテラン
- 会議室デビュー日: 2007/05/02
- 投稿数: 189
- お住まい・勤務地: 最北の地
|
投稿日時: 2007-06-15 07:22
[ メッセージ編集済み 編集者: 仙堂ありす 編集日時 2007-06-16 20:41 ]
|
- 未記入
- ぬし
- 会議室デビュー日: 2004/09/17
- 投稿数: 667
|
投稿日時: 2007-06-15 09:43
引用: |
|
どのクラスLvで実行されているか、メソッドに渡している引数は正確か考えればミスに気づくでしょう。
|
通りすがりの第三者ですが・・・どこに問題があるのか分かりません。メソッドに渡している引数が正しくないということですか?
|
- かつのり
- ぬし
- 会議室デビュー日: 2004/03/18
- 投稿数: 2015
- お住まい・勤務地: 札幌
|
投稿日時: 2007-06-15 09:50
まずは、Classa#getMethodsでどんなメソッドがあるかダンプしてみては?
|
- sawat
- 大ベテラン
- 会議室デビュー日: 2006/08/02
- 投稿数: 112
|
投稿日時: 2007-06-15 10:31
ちゃんと意図したクラスファイルが読み込まれているのか確認してみては?
コード: |
|
System.out.println(loader.getResource("loader/OptionClass.class"));
|
|
- nagise
- ぬし
- 会議室デビュー日: 2006/05/19
- 投稿数: 1141
|
投稿日時: 2007-06-15 10:39
違うClassLoaderで読み込まれたclassは別物ですから、それでオーバーロードがうまく認識していないんじゃないですかね?
引用: |
|
calc3 = clazz.getMethod("calc", new Class[]{DummyViews.class});
|
で引数に渡しているDummyViewsはAppletのクラスローダによってブラウザ経由で読み込まれたDummyViewsで、
"D:\My Program\classLoad\classes\"を基準としたURLClassLoaderで読み込んだ
loader.OptionClass#calc(DummyViews)のDummyViewsはURLClassLoaderで読み込まれたDummyViewsなのではないですか?
|
- nagise
- ぬし
- 会議室デビュー日: 2006/05/19
- 投稿数: 1141
|
投稿日時: 2007-06-15 16:34
追試。
コード: |
|
/** 読み込み対象のクラス。classファイルにして2箇所に配備 */
public class Hoge {
public void hoge(Hoge hoge) {}
}
/** 読み込みテスト */
public class ClassLoaderTest {
public static void main(String[] args) throws Exception {
// クラスローダ1
File baseDir1 = (new File( "C:\\eclipse\\workspace\\TestA\\bin\\" )).getCanonicalFile();
URL baseURL1 = baseDir1.toURI().toURL();
ClassLoader c1 = new URLClassLoader(new URL[]{baseURL1});
// クラスローダ2。1とはURLが違う
File baseDir2 = (new File( "C:\\eclipse\\workspace\\TestB\\bin\\" )).getCanonicalFile();
URL baseURL2 = baseDir2.toURI().toURL();
ClassLoader c2 = new URLClassLoader(new URL[]{baseURL2});
System.out.println("ClassLoader 1 : " + c1);
System.out.println("ClassLoader 2 : " + c2);
Class clazz1 = c1.loadClass("test.Hoge");
Class clazz2 = c2.loadClass("test.Hoge");
System.out.println("class 1 : " + clazz1.getCanonicalName() + " - " + clazz1.getClassLoader());
System.out.println("class 2 : " + clazz2.getCanonicalName() + " - " + clazz2.getClassLoader());
Object obj1 = clazz1.newInstance();
System.out.println(obj1);
Object obj2 = clazz2.newInstance();
System.out.println(obj2);
// クラスローダの違うClassを引数に渡している
Method method1 = clazz1.getMethod("hoge", clazz2);
}
}
|
とするとjava.lang.NoSuchMethodExceptionとなります。
各所のオブジェクトのClass.getClassLoader()でどのクラスローダからロードされたのか確認して見てください。
# ClassLoaderのテストって面倒だ…
[ メッセージ編集済み 編集者: nagise 編集日時 2007-06-15 16:35 ]
|
- nagise
- ぬし
- 会議室デビュー日: 2006/05/19
- 投稿数: 1141
|
投稿日時: 2007-06-15 17:04
補足。
ローカル実行だと動く理由は、ClassLoaderの委譲の仕組みのせいではないでしょうか。
ClassLoaderは自身の親のClassLoaderを用いてまずclassのロードを試みます。
そのため、ローカル実行の場合は通常のClassLoaderによって対象classがロードされ、
実際にはURLClassLoaderは動いていません。
これは、通常のクラスパスの通ったclassをURLClassLoaderでロードし、
class.getClassLoader()でClassLoaderを確認すると分かります。
本件の場合"loader.OptionClass"がローカル実行時にはクラスパスが通っており、
かつApplet起動時のAppletClassLoaderには見えない場所にあるのではないでしょうか?
|