• ベストアンサー

ClassLoaderを作成してみたいのですが

クラスから別の場所のクラスを呼び出す構造を作りたくて、ClassLoaderを勉強しています。 まず、ClassLoaderを継承したLoaderを作成しなくてはいけないというのがわかり、その中で抽象メソッドloadClassと、関係するdefine,resolve,findSystemなどを記述してやるらしいというのまでは、あやふやながら理解できました。 それで、呼び出す側では、Loader.loadClassを呼んでクラスをロードし、newInstanceメソッドを呼べば、その実体ができる"らしい"まで解読して頭がパンクしてしまいました。 疑問は、以下の通りです。 ・「Loaderは自分で作らないといけない」とあったのですが、ClassLoaderを継承させたLoaderを自前で書かないといけないのでしょうか。単にオブジェクトを生成するだけでいいんでしょうか。簡単なサンプルがあれば嬉しいのですが・・・。 ・ ひとまず、簡単な計算を行うクラスを作って呼び出してみたいのですが、newInstanceを実行するとインスタンスが生成されて即中身が実行される、という説明文を読んだのですが、値の受け渡しはどうすればできるのでしょうか。 以上、よろしくご教示お願いいたします。

  • Java
  • 回答数3
  • ありがとう数4

質問者が選んだベストアンサー

  • ベストアンサー
  • Harry_
  • ベストアンサー率55% (36/65)
回答No.1

大抵は URLClassLoader をインスタンス化するだけで用が足ると思います。 たとえば C:/classes からクラスを読込むのであれば、 URLClassLoader loader =  new URLClassLoader( new URL[ ]{ new File("c:/classes").toURL() } ); でロードするクラスを完全限定名で指定して、 Class clazz = Class.forName("sample.Hoge", true, loader); そしてインスタンス化。 Object obj = clazz.newInstance(); ただここからが問題で、 このオブジェクトは sample.Hoge 型に キャストできません。 このオブジェクト特有のメソッドを実行したいのなら、 リフレクションを使います。 Method method =  clazz.getMethod( "メソッド名", new Class[0] ); // 引数なし method.invoke( obj, new Object[0] );

pythian
質問者

お礼

コメントありがとうございます。ClassLoaderが直接生成できないワケがどうしてもわからなかったので、URLClassLoaderでサンプルを作成してみました。結果は上手くいったのですが、ここで作ったオブジェクト(中身はロードしたクラスの実体、でいいんでしょうか)の触り方がいまいちわからないんです。生成した瞬間にクラスが実行されるようですが、呼び出し元とは関係ない空間で動いているのでしょうか。 リフレクションというのがあるらしい、は分かるのですが、いまいちパッとしなくて・・・すみません; (method.invokeで引数を渡して、同時に戻ったオブジェクトを取り出せるのでしょうか)

その他の回答 (2)

  • mojimojio
  • ベストアンサー率51% (14/27)
回答No.3

1コ前の者です。 投稿した後に気づいたのですが、「多くの場合は問題になりません」はウソで、けっこう引っかかりやすい部分だと思ったので補足を。 public class Main { public static void main(String[] args) { ClassLoader loader = new MyClassLoader(); Class clazz = Class.forName("hoge.Hoge", true, loader); HogeInterface hoge = (HogeInterface)clazz.newInstance(); hoge.start(); } } この例の場合、Mainクラス(のクラスローダ)はhoge.Hogeクラスを知らないので、hoge.Hogeにキャストすることはできません。(もし起動クラスパスにhoge.Hogeがあったとしても、MyClassLoaderがロードすれば別のクラスになります) このような場合、Mainクラスが知っているクラスなりインタフェースにキャストしてやるようにすると良いと思います。hoge.HogeはHogeInterfaceをimplementsする。 もちろん、#1の方の回答のようにリフレクション経由でのメソッド呼び出しも可能です。 Hogeクラスやその中の呼び出しではクラスローダがMyClassLoaderなので、いくらでもHogeクラスを使用することができます。

pythian
質問者

お礼

あれからちょっと考えまして、リフレクションでメソッドを呼んだり試行錯誤して、少しずつわかってきました。 ひとまず簡単なものを書いてみて、参照ができるということが確認できましたので、徐々に理解を深めてみようと思います。ありがとうございました。

  • mojimojio
  • ベストアンサー率51% (14/27)
回答No.2

以下、私の理解の範囲で。 ・自前クラスローダからロードした場合であっても、Class#newInstanceで作ったオブジェクトをキャストすることはできます。 ただし、他でシステムクラスローダがhoge.Hogeをロードした場合、自前クラスローダのhoge.Hogeクラスとは同じ名前の別のクラスになります。(キャストしたときにはClassCastExceptionが発生する) しかし、クラスのロードには、その参照元クラスのクラスローダが使われますので、多くの場合は問題になりません。 class Hoge { static Hige hige; } となっていた場合、HigeクラスのロードはHogeをロードしたクラスローダが行います。 ・クラスロードの処理に何かを噛ませることが目的でしたら、URLClassLoaderを継承することができます。 また、そもそもURLで表せないものからクラスをロードしたい場合は、ClassLoaderを継承するのが良いと思います。 一度ロードしたクラスのキャッシュ処理などはClassLoaderの中にありますので、自前クラスローダはfindClassをオーバーライドするだけで済みます。 (リソースのロードにも対応するためには、他にも実装が必要になりますが) ・Class#newInstanceは引数なしのコンストラクタを呼びます。引数を渡したい場合には、java.lang.reflect.Constructorを使います。

pythian
質問者

お礼

ありがとうございます。クラスローダを自前で作る理由というのがわからなかったので、URLClassLoaderを生成してみました。 ロードしたクラスに引数を渡せるというのはなんとなく理解できたのですが、具体的な方法(必死にリファレンスを読んではいるのですが、サンプルが少なくて・・・)やロードしたクラスから呼び出し元と同じ場所に配置してあるクラスを呼べるのかといったことが結局まだわからないので・・・もっと勉強してみます。

関連するQ&A

  • 外部jarの標準出力を取得できますか?

    ClassLoaderで外部jarのクラスをロードし、実行するプログラムを作りました。 SimpleOutputは、単に渡された引数を標準出力に出すだけのものです。 この値を取得してGUI上に表示させたいのですが、取得する方法をご教授ください。 System.out.println("Load class"); URL[] urls = { file.toURI().toURL() }; ClassLoader loader = URLClassLoader.newInstance(urls); Class<?> cls = loader.loadClass("SimpleOutput"); System.out.println(cls); Object obj = cls.newInstance(); Method method = cls.getMethod("main", String[].class); String[] av = {"test"}; method.invoke(obj, new Object[]{av});

    • ベストアンサー
    • Java
  • privateのメソッドをリフレクションで呼び出す方法

    privateのメソッドをリフレクションで呼び出す方法 private のメソッドをリフレクションで呼び出す方法 privateのメソッドもリフレクションというもので呼び出せると聞きましたが、やり方がよく分かりません。 aaaやbbbクラスのインスタンスを生成したいのですが、privateやpackage privateのため、そのままだとインスタンスが生成できません。 forNameメソッドやnewInstanceメソッドでどうにかできないかと試してみたのですが、イリーガル例外が発生してしまいます。 何かよい方法がないでしょうか? aaa, bbbのクラスを継承してモックを作成する方法もあるのですが、今回はそういった方法ではなく、privateやpackage privateメソッド(特にコンストラクタ)を外部から呼び出す方法がよいです。 public aaa { private aaa() { } private func() { } } public bbb { aaa() { } private func() { } }

    • ベストアンサー
    • Java
  • 同一クラスインスタンス名で別クラスのインスタンス作成方法(C++)

    下記ソース(Java)の処理をするような、C++の実装方法を教えていただきたいです。 【処理内容】 クラスBのインスタンスを保持しており、クラスBのインスタンス名と同一であるクラスAのインスタンス生成 ClassA A_Instance = (ClassA)Class.forName(B_instance.name).newInstance(); 要はクラスインスタンスの名前の求め方がわからないのです。それさえわかれば、newしてクラスポインタを返すメソッドを用意すれば何とかなると考えていますが。 ※C++のAPI一覧はどこにあるのだろうか・・・

  • 継承について

    みなさま、どうかお知恵を貸して下さい。 javaを勉強中で、本を読みながら試しに動かしています。 現在、実現したい動作が実現可能かどうかを調べているところです。 そのため、環境やバージョン等は決まっておりません。 むしろ、実現可能な環境やバージョンがあれば、教えてください。 実現したい機能ーーーーーーーーーーーー 親クラスAにメンバーとメソッドを定義します。 Aを継承する子クラスBを定義します。 プログラム中で、A、Bのインスタンスを生成します。 そして、A、Bを継承するCのインスタンスを生成したいのです。 Cのメンバーやメソッドは、Bと同様のものです。 この場合、BのクラスからCのようなインスタンスを作成することは、可能なのでしょうか? ・・・Cを定義していないので、おそらく不可能かと思います。 やはりこういった場合、Aを継承しているBを継承するCクラスを定義しておく必要があると考えています。 では、Cを継承するD,Dを継承するE・・・というように、いくつ必要になるかわからない場合、最大数分継承したクラスを用意すべきでしょうか。 なぜ、そうしたいかというと、組織図のようなものを作成したいのですが、組織図を構成する人数は、ユーザーの任意としたいのです。 継承したクラスを用いれば、そのまま組織図の体系を表現できる気がしました。 質問が大雑把になってしまい、申し訳ないのですが、お力を貸していただければ幸いです。

    • ベストアンサー
    • Java
  • Ruby 特異メソッドのnewが先に実行?

    Rubyのインスタンス生成について質問があります。 通常クラスを定義する場合は class Hoge ; def hello(); pirnt "hello"; end であると思います。 ただ Hoge = Class.new(); でもクラスは定義できるとききました。 ただこの場合Hogeクラスに定義できるのは HogeというClassクラスから作られた特異クラスとしてのHogeに 特異メソッドのみを定義できるということですよね? 通常のインスタンスメソッドは定義できませんよね? ではでは、 hoge = Class.new(); とした場合はどうなるのでしょうか? この場合は Classクラスの純粋なインスタンスとなるのでしょうか? 前者の定義とおなじ仕方ですが代入先が、通常の変数です。 この場合は、クラスオブジェクトとして生成されるのですか? オンラインマニュアルをみたところ 「新しく名前の付いていない superclass のサブクラスを生成します。 superclass が省略された時にはObject のサブクラスを生成します。 名前のないクラスは、最初に名前を求める際に代入されている定数名を検索し、見つかった定数名をクラス名とします。」 とあります。 上記内容は Classクラスの特異クラスとして定義されている特異メソッド(new)です。 これは Class.new()で作られたインスタンスを代入する先が定数であればその定数名と同じクラスを定義しつつそのClassクラスのクラスオブジェクトを生成するという意味合いでまちがいないでしょうか? 上記のとおりであれば hoge =Class.new()の場合は、やはりhogeというクラスを定義することになるのでしょうか? クラス定義は定数でなければならないはずですよね。 ただ実際、 p hoge;として出力すると#とひょうじされています。これはhogeがクラスオブジェクトではなく ただのインスタンスであるということでしょうか? であるならばこの hoge = Class.new()の式のnewはClassクラスオブジェクトに定義された特異メソッドではなく Classクラスに定義されたnewメソッド・・・・・つまりClassクラスに定義されたインスタンスメソッドの方のnewメソッドだとおもうのですが・・・・・・。 つまりこちらのメソッドですね。 「new( ... ) クラスのインスタンスを生成して返します。このメソッドの引数はブロック引数も含め initialize に渡されます。」 ※オンラインリファレンスから参照しました。 しかし 通常メソッドの検索は特異メソッドからはじまりその後クラスのインスタンスメソッド->親クラスのメソッドと 検索して行くとあります。 必ず先に、特異メソッドを実行しているはずだと思うのですが・・・。 やはり特異メソッドnewを実行しているのでしょうか? 長々すみませんが、ご教授ください。

    • ベストアンサー
    • Ruby
  • 継承について

    下の質問の回答、間違ってませんか? -------------------------------------------- 親クラスのフィールドをメソッドを全て継承することになります。よって、サブクラス2は、サブクラス1とスーパークラスのメンバーを全て持つことになります。サブクラス2をインスタンス化すると、サブクラス1とスーパークラスが全てインスタンス化(コンピューターのメモリ上等に配置)されます。 ただ、可視性というものがあり、サブクラスから親クラスのメンバーを直接取り扱えない場合があります。privateや可視性修飾子無しの場合、サブクラスから直接取り扱えません。ただ、継承はされているので、インスタンスとしては存在します。例えば、 class スーパークラス{ private int abc; public int getAbc(){ return this.abc; } というクラスがあり、これを継承したサブクラスがあったとします。 サブクラスからは、privateなメンバー変数abcは直接取り扱うことができません。ただ、publicなgetAbcメソッドはサブクラスから取り扱えます。これで何が分かるかといいますと、privateなメンバーでもサブクラスに継承されるのです。単に可視性の問題で直接取り扱えないだけなのです。 また、オーバーライドされたメソッドがあったとしても、super.メソッド()で親のメソッドも呼べますので、これも継承されているのです。

  • AWT Frameを利用するプログラムのmainメソッドを含むクラスについて

    AWTのFrameを継承してWindowプログラムを作成する際に、どんな書籍のサンプルプログラムを見ても、メインクラスがFrameを継承し、その中にmainメソッドが有って、そのmainメソッド内で自分自身のクラスのインスタンスを作成してshowする、といった事を定石のように行っています。 しかし私が思うに、mainメソッドなど含まずFrameを継承してWindow周りの処理を純粋に行うクラスを作成し、プログラムのメインとなるクラス内のmainメソッドからFrameを継承した別クラスのインスタンスを作成・showする方が、よほどスッキリして理解し易いような気がするのですが、どうなんでしょ? そういったサンプルプログラムを作成してみましたが問題なく動作します。ただそういう事をやっている他のサンプルソースが見当たらないので、何となく不安です(笑)

    • ベストアンサー
    • Java
  • Cake2系のコントローラでセッション情報取得

    CakePHP2を使用して、開発を行っているのですが、 AppControllerを継承したControllerのあるメソッドで、 別のコントロー(AppController継承)をnewでインスタンスを生成し、 自前のコントローラのあるメソッドを呼び出しているのですが、 自前のコントローラのメソッド内で、セッション情報取得しようとすると 「Call to a member function load() on a non-object」 となりエラーになります。 AppControllerには、コンポーネントの呼び出しを行っています。 public $components = array('Common','Session'); newして使わないコントローラだと、セッション情報を取得できるのですが、 newしたコントローラでは、セッション情報にセットした情報を取得することができません。 newしたコントローラへ必要な情報を渡すには引数以外はないのでしょうか。 セッション情報をnewしたコントロールで取得したいのですが、 可能でしょか。

    • ベストアンサー
    • PHP
  • 指定されたクラスの継承元の確認方法

    Class cls = Class.forName("extendsClass"); Object obj = cls.newInstance(); if (obj instanceof AbstractClass) {   System.out.println("継承してた");   ((AbstractClass)obj).method(); } こんなことをして、objのクラスがAbstractClassを継承しているという ことは確認することが出来たのですが、これはやはり継承しているか どうかを確認する為にインスタンス化を行っています。 指定された名称のクラスが、特定のクラスを継承していた場合に限り、 その名称のクラスをインスタンス化する、 という流れは行えないのでしょうか?

    • ベストアンサー
    • Java
  • [Obj-c]元クラスからサブクラスのメソッド

    Objective-Cの勉強をしています。 ClassAは元クラス(スーパークラス)です、 ClassB1、B2はClassAを継承(サブクラス)しています。 ClassAとClassB1にはiMethodというメソッドが存在します。 最下部にソースと実行結果があります。 ●そこで質問なのですが、  ClassAのインスタンスにClassB1のインスタンスをセットすると、  同じ名前のメソッドがあるだけでなぜClassB1のメソッドが呼ばれるのでしょうか?  (下記ソースの[bangai iMethod]; の部分です。)  ClassB1のインスタンスを渡すとClassAのインスタンスが  ClassB1のメソッドを使用できる理由がわかりません、  継承しているとはいえ型が違うものを参照渡しできる理由も今ひとつわからないです。  またこれはどういう機能を言うのでしょうか?  (例えば ポリモーフィズム、動的バインディングなど) ★ソース ------------------------------------------------------------------------------ #import <Foundation/Foundation.h> // ClassA @interface ClassA : NSObject { } @end @implementation ClassA -(void) iMethod { NSLog(@"スーパークラスのインスタンスメソッドです。\n"); return; } @end // ClassB1 @interface ClassB1 : ClassA @end @implementation ClassB1 -(void) iMethod { NSLog(@"サブクラスのインスタンスメソッドです。\n"); return; } @end // ClassB2 @interface ClassB2 : ClassA @end @implementation ClassB2 @end int main(int argc, const char * argv[]) { @autoreleasepool { // insert code here... ClassB1 *instance_B1 = [[ClassB1 alloc]init]; ClassB2 *instance_B2 = [[ClassB2 alloc]init]; [instance_B1 iMethod]; [instance_B2 iMethod]; // 親には子のクラスが入れられる ClassA *bangai = instance_B1; [bangai iMethod]; } return 0; } ------------------------------------------------------------------------------ ★実行結果 サブクラスのインスタンスメソッドです。 スーパークラスのインスタンスメソッドです。 サブクラスのインスタンスメソッドです。

専門家に質問してみよう