- - PR -
クラスローダについて。
投稿者 | 投稿内容 | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
投稿日時: 2005-03-30 15:30
ClassLoaderクラスのdefineClassメソッドを使い、
他の場所にあるクラスファイルを読み込み、 そのクラスを操作するコードを作成しています。 行おうとしている手順は、以下の通りです。 1.クラスローダのあるディレクトリとは、別のディレクトリにあるクラスファイルを指定する。 2.そのクラスファイルを、バイナリデータとして値を取得する。 3.そのバイナリデータを、defineClassメソッドを使って、Classに変換する。 4.その変換したClassのメソッドを使用し、値を取得する。 import java.io.ByteArrayOutputStream; import java.io.FileInputStream; public class NetworkClassLoaderSample extends ClassLoader { private static byte[] byteArray = null; public static void main (String argv[]){ try { // ファイルの読み込み // 今回は同一ディレクトリの「UserCount.class」を指定 FileInputStream in = new FileInputStream("./UserCount.class"); ByteArrayOutputStream out = new ByteArrayOutputStream(); byte buff[] = new byte[1024] ; int len ; // バイナリの抽出 while((len = in.read(buff, 0, 1024)) != -1 ){ out.write(buff, 0, len); } // byte[]型に変換 byteArray = out.toByteArray(); // Classに変換 Class userClass = new NetworkClassLoaderSample(). defineClass("UserCount", byteArray, 0 ,byteArray.length); // ↓「UserCount」と表示されます System.out.println(userClass.getName()); ↓ここでClassCastExceptionが発生 // UserCountクラス型を生成 UserCount user = (UserCount) userClass.newInstance(); // UserCountクラスのgetUserメソッドの呼び出し System.out.println(user.getUser()); } catch (Exception e ){ System.err.println("Exception :" + e); } } } バイナリデータを抽出し、Classに変換することはできていると思いますが、 そのClassを使用する場合は、どのようにすれば良いのでしょうか? よろしくお願い致します。 | ||||||||||||
|
投稿日時: 2005-03-30 15:56
この時点で、userClassには、UserCountのインスタンスが格納されているはずではないのでしょうか。 「instanceof UserCount」で、結果はtrueになります? だとしたら、
ここは、
じゃダメなのでしょうか。 ちなみに、Class#newInstance()のAPIドキュメントには、 「new 式に空の引数リストを指定した場合と同じように、クラスのインスタンスが生成されます。」 とあります。 [ メッセージ編集済み 編集者: Edosson 編集日時 2005-03-30 15:57 ] | ||||||||||||
|
投稿日時: 2005-03-30 16:10
クラスローダとかネットワーククラスローダとか使ったことないのでアレなんですが
ちょっと疑問に思ったので。 そもそもネットワーククラスローダを使用するということは クラスパスの通っていないクラスに対してメソッドをコールしたい ってのが目的ではないんでしょうか? # 簡単すぎますか・・ 上記前提で、まずUserCountにクラスパスが通っていること自体 おかしいという考えにはならないんでしょうか? クラスパスが通っているならクラスローダなんか使わず、そのまま 使えばいいですよね? 何が言いたいかというと、キャストではなくリフレクションでメソッド をコールするのが通常の手法だったりしませんか? かなり乏しい知識で言っているので間違いあれば指摘欲しいです・・。 | ||||||||||||
|
投稿日時: 2005-03-30 16:19
クラスローダが違うと同じクラスでもキャスト可能な関係にはなりません。
クラスはパッケージという名前空間がありますが、 さらにその上位にクラスローダという名前空間が存在しますので、 サンプルのクラスローダでロードしたクラスは そのクラスローダでロードしたクラスにしかキャストはできません。 サンプルの例ではサンプルのクラスローダでロードしたクラスから カレントスレッドのクラスローダでロードしたクラスに キャストしようとしてClassCastExceptionが発生していると思います。 試していないですが、コンストラクタにカレントスレッドのクラスローダを 渡してあげればいいような気がします。外していたらゴメンナサイ・・・。 java.net.URLClassLoaderのソースを参考にしてみては如何でしょうか。 似たような事をやっていますので、参考になると思います。 | ||||||||||||
|
投稿日時: 2005-03-30 16:27
>(株)ぽちさん
ネットワーククラスローダを使用するときに 対象のクラスのクラスパスが不明な状態でも キャストを行うケースがあります。 どういうケースかというと サーバ側 HogeImplクラス(Hogeインターフェイスの実装クラス) クライアント側 Hogeインターフェイス が存在していて、ネットワークでHogeImplを取得し、 リフレクションでHogeImplのインスタンスを生成して、 Hogeインターフェイスにキャストして メソッドコールを行うという場合等に使用できます。 ネットワークの他に、バイトコード操作系のAPIなどを使用したときにも有用です。 | ||||||||||||
|
投稿日時: 2005-03-30 17:17
以前に、HTTP経由でクラスをロードするコードを書いたことがあります。
これでいけると思います。 // クライアントアプリを、HttpClassLoaderを介して読み込み、実行する。 Class entry_class = Class.forName(entry_classname, true, httpClassLoader); KandataClient client = (KandataClient) entry_class.newInstance(); | ||||||||||||
|
投稿日時: 2005-03-30 17:21
Edossonさん、(株)ぽちさん、かつのりさん、ご返信ありがとうございます。
引用:__________________________________________________________ // Classに変換 Class userClass = new NetworkClassLoaderSample(). defineClass("UserCount", byteArray, 0 ,byteArray.length); // ↓「UserCount」と表示されます System.out.println(userClass.getName()); この時点で、userClassには、UserCountのインスタンスが格納されているはずではないのでしょうか。 「instanceof UserCount」で、結果はtrueになります? instanceof演算子で比較をしてみようと思いましたが、 Class userClassとUserCountクラスは、 非互換性がない型と、コンパイル段階でエラーになりました。 引用:_______________________________________________________ ↓ここでClassCastExceptionが発生 // UserCountクラス型を生成 UserCount user = (UserCount) userClass.newInstance(); ここは、 引用: // そのままキャストしちゃえば? UserCount user = (UserCount) userClass; そのままキャストを行いますと、こちらも同様に ClassクラスからUserCountクラスにキャストできませんと、 コンパイルエラーになりました。 引用:_________________________________________ サンプルの例ではサンプルのクラスローダでロードしたクラスから カレントスレッドのクラスローダでロードしたクラスに キャストしようとしてClassCastExceptionが発生していると思います。 試していないですが、コンストラクタにカレントスレッドのクラスローダを 渡してあげればいいような気がします。外していたらゴメンナサイ・・・。 java.net.URLClassLoaderのソースを参考にしてみては如何でしょうか。 似たような事をやっていますので、参考になると思います。 java.net.URLClassLoaderクラスのソースを見ながら、 もう少し頑張ってみます。 | ||||||||||||
|
投稿日時: 2005-03-30 17:22
情報ありがとうございます。 なるほど。まさにEJBのようなケースですね。 質問で出てたケースはもろクラスパスのクラスを使っていたので 視野が狭くなっていました。 確かに有用ですが、EJBやDIContainerとか色々ある現状 そこまで根っこから作るケースってあるんですかね? # また話しをそらしてますが・・ |