• ベストアンサー

実行時に確定するメソッドを呼び出す方法について

invoke()メソッドや、Methodクラスを 使用するなど。以前に小耳にはさんだ。記憶があります。 以下の3つの引数から 動的に該当メソッドを呼び出す。 処理を実装コードがすぐだせる方がいると 助かります。 Object foo(Object obj, String methodName, Collection param) (1)該当オブジェクト getClass()などで、該当クラスを動的に  特定。 (2)、(1)が保有しているメソッドのうち、 発行したいメソッドの名前 (3) parmには1要素ごとに2要素のObject[]型を   を格納して、 Object[0]の要素にかんしてはが引数の型についての完全修飾クラス名をあらわすString型。   Object[1]については実際に入っている値。 上記3つの引数をうけとって内部で getClass()とかつかって 必要な情報はすべて実行時に動的に 取得して objの該当オブジェクトを 発行し、foo()メソッド自体の 返却値はそのメソッドの返却値とする という ロジックの実装のサンプルがあると。 とても、うれしいです。 じゃ、void型が返却の時どうすんねん。 とか、staticの時どうすんねん。 とか、その変のアイデア持ってる 人がいるととてもうれしい。 以上

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

  • ベストアンサー
  • nontatta
  • ベストアンサー率34% (18/52)
回答No.1

こんにちは(^ー^) 即席のソースですので細かいところはさておき、 だいたいのイメージがつかめていただければと思います。 (以下サンプル) --------------------------------------- public Object invoke(Object instance, String methodName, Collection param)             throws Exception {   Object ret = null;   Class paramType[] = null;   Object paramValue[] = null;   if(param != null && !param.isEmpty()){     int paramNum = param.size();     paramType = new Class[paramNum];     paramValue = new Object[paramNum];     Iterator it = param.iterator();     int i=0;     while(it.hasNext()){       Object elem[] = (Object[])it.next();       if(elem[0] != null){         paramType[i] = elem[0].getClass();       }else{         paramType[i] = null;       }       Object value = new Object();       paramValue[i++] = elem[1];     }   }   try{    Class classType = instance.getClass();    Method method = classType.getMethod(methodName, paramType);    ret = method.invoke(instance, paramValue);   }catch(Exception e){    throw e;   }   return ret; } 1.戻り値がvoidの場合はnullが返ります。 実行エラーの場合もnullが返ります。 その区別のため、上記サンプルでは、エラーの場合、例外を投げるようにしています。 2.staticメソッドの場合も特に意識する必要はないと思います。第1引数のオブジェクトが無視されるだけです。 ご参考になれば幸いです。

lawson
質問者

お礼

どうも、ありがとう。 JSPに埋め込むカスタムタグクラスを開発する必要があって 月曜日か火曜日あたりに着手するんですけど。 カスタムタグに引数として "スコープにおける名前.フィールド名" を渡すのですが。 "スコープにおける名前" のインスタンスのクラス名を 動的に取得して、 "フィールド名" の頭文字を大文字にして get~() を呼んで、 値を取得したあと。 自分のやりたいロジックを 組みたかったんです。 nontatta さんの回答のおかげで できそうです。 これがないと、 引数でもらうデータの種類だけ 条件分岐したり、 メンテナンスが発生しそうで やりたくなかったんです。 ただ、ひとつ疑問があるのですが。 paramType[i] = elem[0].getClass(); ↑これです。 メソッドの第3引数の Collection param の各要素には Object[2]がつまっており、 Object[0]は完全クラス名のString型です。 "jp.co.hoge.Zoo".getClass() はString型のClassクラスが返却されるのでは? それともZooクラスの Classクラスが返却されるのでしょうか? あれれ?

全文を見る
すると、全ての回答が全文表示されます。

その他の回答 (4)

  • ngsvx
  • ベストアンサー率49% (157/315)
回答No.5

Object foo(Object obj, String methodName, List params)    throw XXXXException {  Class cls = obj.getClass();  //findMethod用のパラメータを作る  String[] paramTypeNames = new String[params.size()];  for(int i = 0 ; i < param.size() ; i++){   Object[] param = (Object[])params.get(i);   paramTypeNames[i] = (String)param[0];  }  //該当メソッドの取得  Method method = findMethod(cls, methodName, paramTypeNames);  if(method == null){   throw new XXXXException();  }  //Method#invoke用のパラメータを作成  Object[] values = new Object[param.size()];  for(int i = 0 ; i < param.size() ; i++){   Object[] param = params.get(i);   values[i] = param[1];  }  Object rtn = null;  try{   rtn = method.invoke(obj, values);   return rtn;  }catch(Excetion e){   e.printStackTrace();  } } /** クラスから条件に合うメソッドを探す */ protected Method findMethod(Class cls, String methodName, String[] paramTypeNames) {  Method[] methods = cls.getMethods();  for(int i = 0 ; i < methids.length ; i++){   //違うメソッド名をはじく   if( ! methods[i].getName().equals(methodName) ){    continue;   }   //パラメータの数ではじく   Class[] params = methods[i].getParameterTypes();   if(params.length != paramTypeNames.length){    continue;   }   //パラメータをチェック   if( !checkParam(params, paramTypeNames) ){    continue;   }   //一致したときの処理   return methods[i];  }  return null; } /**引数の型が同じかチェックする */ protected boolean checkParam(Class[] params, String[] params){  for(int i = 0 ; i < params.length ; i++){   Object[] param = (Object[])params.get(i);   if( !params[i].getName().equals(param[i]) ){    return false;   }  }  return true; } Collectionインターフェースでは、順序が保証されていないため、 Listインターフェースを使うのがいいと思います。 また、プリミティブ型のClassオブジェクトは、Class.forNameでは取得できないので、 Class#getMethods() でMethodの一覧を取得し、その中から対象となるものを選択しています。 例外処理は、適当なものを作ってください。

lawson
質問者

お礼

プリミティブ型は Collection型の問題点の 指摘まで、 いただいて大変参考になります。 危うく、「なんでじゃー!!」 ってはまってしまうところでした。 本当に助かります。

全文を見る
すると、全ての回答が全文表示されます。
  • nontatta
  • ベストアンサー率34% (18/52)
回答No.4

たびたびすみません。 先の私の投稿に誤りがありましたので、訂正します。 ×:【また、先のサンプルでは、戻り値がvoidの場合(恐らくセッターの場合?)は、第3引数のparamにnullが渡されることを前提としています。ClassクラスのgetMethodメソッド呼び出し時や、Methodクラスのinvokeメソッド呼び出し時に、戻り値がvoidの場合は第2引数にnullを渡さなくてはならないので、ソース簡略化のため?そうしています。つまり、先のサンプルメソッドを利用してvoidメソッドを呼び出す場合、第3引数のparamに、Collectionそのものがnullでなく、nullもしくは空の要素をもったCollectionが渡されると例外が発生しています。】 の部分ですが、戻り値がvoidでなく、引数がないメソッド呼び出しの場合についての記述です。 よって、 ○:【また、先のサンプルでは、引数がないメソッドの場合(恐らくゲッターの場合?)は、第3引数のparamにnullが渡されることを前提としています。 ClassクラスのgetMethodメソッド呼び出し時や、Methodクラスのinvokeメソッド呼び出し時に、引数がないメソッドの場合は第2引数にnullを渡さなくてはならないので、ソース簡略化のため?そうしています。つまり、先のサンプルメソッドを利用して引数がないメソッドを呼び出す場合、第3引数のparamに、Collectionそのものがnullでなく、nullもしくは空の要素をもったCollectionが渡されると例外が発生しています。】 が正しい文章です。 すみませんが、下の文章に読み替えてくださいm(__)m

全文を見る
すると、全ての回答が全文表示されます。
  • nontatta
  • ベストアンサー率34% (18/52)
回答No.3

こんにちは(^ー^) あぁぁ... >Object[0]の要素にかんしてはが引数の型についての完全修飾クラス名をあらわすString型 でしたね。すみません。 よって、 paramType[i] = elem[0].getClass();     ↓ paramType[i] = Class.forName(elem[0]); です。 ただ、Class.forName("xxxxx")は例外発生時、例外を投げるので、 このステップもtryブロック内に入れなくてはならないでしょう。 また、先のサンプルでは、戻り値がvoidの場合(恐らくセッターの場合?)は、第3引数のparamにnullが渡されることを前提としています。 ClassクラスのgetMethodメソッド呼び出し時や、Methodクラスのinvokeメソッド呼び出し時に、戻り値がvoidの場合は第2引数にnullを渡さなくてはならないので、ソース簡略化のため?そうしています。つまり、先のサンプルメソッドを利用してvoidメソッドを呼び出す場合、第3引数のparamに、Collectionそのものがnullでなく、nullもしくは空の要素をもったCollectionが渡されると例外が発生しています。 すでにお気づきだったかもしれませんが、分かりづらい日本語ですみませんm(__)m

全文を見る
すると、全ての回答が全文表示されます。
  • kacchann
  • ベストアンサー率58% (347/594)
回答No.2

import java.lang.reflect.*; class Sample { public static void main(String[] args) { out("Math#pow(double, double)"); Object[] argList = new Object[]{new Double(3), new Double(4)}; Object res = call(null, "java.lang.Math", argList, "pow"); out(res+"\n"); out("StringBuffer#insert(int, char[]);"); char[] charArr = new char[]{'x','y','z'}; argList = new Object[]{new Integer(2), charArr}; res = call(new StringBuffer("aaaa"), null, argList, "insert"); out(res+"\n"); } public static Object call(Object o, String n, Object[] args, String methodName) { Object r = null; Class c = null; if (null == (c=getClass(o,n))) {return null;} Class[] typs = null; if (null != args) { int l = args.length; typs = new Class[l]; for (int i = 0; i < l; i++) { typs[i] = getClass(args[i]); } } try { r = c.getMethod(methodName, typs).invoke(o, args); } catch (Exception e) { e.printStackTrace(); } return r; } private static Class getClass(Object o, String name) { Class c = null; if (null != o) { c= o.getClass(); } else { try { c = Class.forName(name); }catch (ClassNotFoundException e) { e.printStackTrace(System.err); } } return c; } private static Class getClass(Object o) { if (null == o) {return null;} Class prmtv; Class c = o.getClass(); if ( null != (prmtv=getPrmtv(o.getClass().getName()))){ c = prmtv; } return c; } public static Class getPrmtv(String name) { Class r = null; if (name.equals("java.lang.Double")) { r = Double.TYPE; } else if (name.equals("java.lang.Integer")) { r = Integer.TYPE; } return r; } private static void out(String s) { System.out.println(s); } }

全文を見る
すると、全ての回答が全文表示されます。

関連するQ&A

  • Stringの値で型キャストしたい(Java)

    最近OKWaveでお世話になっています。 表現がおかしいかもしれませんが、Stringの変数の値を使って、型キャストしたいです。 様々なオブジェクトが入る配列(Vector)を使用しているため、VectorをObject型にして使用しています。 配列のある要素をget()したのち、getClass().getSimpleName()でクラス名を取得し、そのクラス名を、 Object obj = array.get(i); String name = obj.getClass().getSimpleName(); if(name.equal("Integer")) {  method((Integer)obj);   ・   ・   ・ のような形で、場合分けして、メソッドを呼び出しています。 ですが、この方法だと、条件分岐が増えて、見づらいです。 そこで、クラス名を取得したnameをうまく使ってobjを型キャストしたいです。 これを解決させる方法もしくはヒントを教えてください!

    • ベストアンサー
    • Java
  • メソッドの中に、作ったメソッドを呼び込みたいんですが

    メソッドの中に、作ったメソッドを呼び込みたいんですが シグネチャを int argCheck(String args[]) に指定して、 引数のチェック処理メソッドというものを作成してるんですが、 よくわからないんです。 内容は (1) 引数の数が1個でない場合、1を返却 (2) 引数が『aaa』でも『ZZZ』でもない場合、99を返却 (3) 以外は、0を返却 public class Test { public static void main(String args[]) { Test test = new Test(); int result = test.argCheck(args); test.argCheck(); //メソッドを呼び込み } private int argCheck(String args[]) { if(args[0].length != 1) // 引数の数が1以外の場合 { return 1; // 1を返す } else if (!args[0].equalsIgnoreCase("aaa") && !args[0].equalsIgnoreCase("ZZZ")) //引数が aaa でも ZZZ でもない場合(大/小文字区別せず) { return 99; // 99を返す } else // それ以外の場合 { return 0; // 0を返す } } }

    • ベストアンサー
    • Java
  • C#の動的キャスト

    いつもお世話になっています。 C#の動的キャストに関する質問です。 C#のメソッドにobjectの引数を渡して動的にキャストする場合 void Hoge(object obj) { Type t = Type.GetType(obj); objの型 obj2 = (objの型)Convert.ChangeType(obj, t); //(1) ................................. } のようにされています。 しかし多様性をもつobjcetを引数にする多くの場合は「objの型」は不定です。 逆に言えば「objの型」がわかっている場合はわざわざobjectを引数にする必要はないわけです。 そこで質問ですが、何とかType t から「objの型」を取得して(1)記法による動的キャストを行う方法はないでしょうか? GetMethod, GetPropertyでメソッド,プロパティを取得し、Invoke, GetValue, SetValueすることは可能ですが、できればドット記法(.)が使える (1) のような動的キャストを行いたいと考えています。 よろしくお願いします。

  • c# Equalsメソッドについて

     こんにちは、c#初心者です。  以前まで「Object」型から継承される「Equals」メソッドをオーバーライドするときは public bool override Equals(object obj) {   if ( obj is 現在の型 または 任意の親クラスの型 や インターフェイスの型 )     {     //判断処理     }   else     return false; }  または、クラス限定で public bool override Equals(object obj) {   var temp = obj as 現在の型 または 任意の親クラスの型 や インターフェイスの型;   if ( temp != null )     {     //判断処理     }   else     return false; }  のようにしていたのですが、「is演算子なんて封印してしまえばいいのに」と仰る方がいらしたので、「is演算子を使わない方がよいのか?」と、「現在のメソッドの形式に不備はないのだろうか?」ということが気になり質問させていただきました。  is演算子を使わないとなると、もう「typeof演算子」を利用する事くらいしか思いつきません。  主に「is演算子」を使っているのは「Equals」メソッドなので、とりあえず「Equal」メソッドだけで。上記メソッドに不備、改善点があればご指摘願います。

  • return new使用時

    いつもお世話になっています。 return返却時に、newインスタンスを使用する場合、 newクラス名()、newクラス名().メソッド名()での返却が可能だと思うのですが、このような場合の実装方法はどうなるのでしょうか? 考えているのは、実装すると、 (1)、return new クラス名().メソッド名()で行う場合 public クラス名 method1() { return クラス名; //実現できない return このクラスに存在するメソッド名(); //OK return null; //OK } といった形になり、クラス名()が実装できない (2)、return new クラス名()で行う場合 public クラス名 method2() { return クラス名; //OK return null; //OK } となり、 (1)で返却された場合、返却されたメソッドの機能を持つことができると同時に、クラス自体の機能も持つ(この場合、クラスオブジェクトは持てず単にそのメソッドのみ使用可だと思っていたのですが...) (2)で返却された場合、返却されたクラスオブジェクトを持つことができる といった感じになります。 実際に、試したところ(1)と(2)でさほど変化がありません。 言いたいことは、 return時に、クラス名()で返却された場合、とクラス名().メソッド名()で返却された場合の違いと、 実際に使用されるのはどういったときかを教えて頂きたいのですが。 また、メソッドがつくのとつかない場合の違いはあったりするのでしょうか? 説明が不十分で申し訳ありません。 宜しくお願いします。

    • ベストアンサー
    • Java
  • VBのクラスの利用

    VBの初心者ですが、FormにTextBoxとコマンドボタンを配置して、ボタンクリックでTextBoxに"ABC"と表示させるものをクラスを使ってやろうと思っています。WriteAクラスを作り、その中にkakikomiメソッドを作り、引数を(TextA AS TextBox)とし、メソッド内部でTextA.Text="ABC"としました。 コマンドボタンクリックメソッド内部で、  Dim obj As WriteA  Set obj=New WriteA  obj.kakikomi(Text1)//Text1はTextBoxのオブジェクト名 とすると、[引数の型が違う]でコンパイル出来ません。どうしたら良いのでしょうか?

  • voidの性質や使い方、showメソッドについて

    1ファイル1クラスの原則に反しますが、敢えて1ファイルに2クラスあるプログラムにおいて、voidの性質や使い方、showメソッド等について教えてほしいです。 ファイル名はStart.javaです。 --------------------------------- package sample; class Cat { String name; int age; void show(String name,int age) { System.out.println("名前は" + name + "です"); System.out.println("年齢は" + age + "歳です"); } } public class Start { public static void main(String[] args) { Cat cat1 = new Cat(); cat1.name = "太郎"; cat1.age = 28; cat1.show(); } } --------------------------------- 「cat1.show();」のところでエラーが出ていますが、Eclipseでそのまま実行してみますと。 ~~~~~~~~~~~~~~~~~~~ Exception in thread "main" java.lang.Error: Unresolved compilation problem: 型 Cat のメソッド show(String, int) は引数 () に適用できません at sample.Start.main(Start.java:16) ~~~~~~~~~~~~~~~~~~~ といったエラーが出てきます。しかし、Catクラスの「void show(String name,int age) 」の箇所を「void show() 」のように、Startクラスと同じく引数の中身を空にしますと。 |||||||| 名前は太郎です 年齢は28歳です |||||||| と、正しい結果が出力されたのです。 最初のプログラムは、Catクラスのshowメソッドには引数があり、Startメソッドのshowメソッドには引数が無い状態でした。 修正したプログラムでは、どちらのクラスのshowメソッドにも引数はありませんでした。 最初のプログラムでも、mainメソッドを実行して、nameとageに値を格納して、showメソッドでCatクラスの方で定義したshowメソッドを呼び出すといった流れで、正しい値は出るはずだと自分は考えたのですが。 なぜエラーになってしまったのか、どうして2つのクラスのshowメソッドの引数が空だとうまく結果が出力されたかにつきまして、お教えいただけないでしょうか。 よろしくお願い致します。 ※OKWAVEより補足:「Webシステム開発」についての質問です。

    • ベストアンサー
    • Java
  • c#のToString()メソッド

    http://msdn.microsoft.com/ja-jp/library/ms173154(v=vs.90).aspx のページによると C# では、すべてのオブジェクトが ToString メソッドを継承します。このメソッドは、該当するオブジェクトの文字列形式を返します。たとえば、int 型の変数はすべて ToString メソッドを持ち、次のようにその変数の内容を文字列として返すことができます ↑と書いてあるのですが、C言語しか知らない自分にとってint型の変数が関数、メソッドを持つ、 という概念が理解できません。これはオブジェクト指向の話なのでしょうか?クラスを理解すると わかるようになりますか? どなたかよろしくお願いします。

  • arraycopyメソッド

    ある問題集なのですが・ String a = "String"; String b = "copy"; System.arraycopy(a,0,b,4,6); でaとbがどうなるかというのですが、 プログラムが実行できません。 コンパイルは出来るのですが、 ArrayStoreExceptionの例外が出ます。 型違い、ということなんですけれど・・・ リファレンスを見ると >以下のどれかの場合は、ArrayStoreException をスローし、転送先を修正しません。 >引数 src が、配列でないオブジェクトである >引数 dest が、配列でないオブジェクトである とあります。 aとbがStringだから悪いのでしょうか?? 問題自体が間違っているのでしょうか??? どうやったら実行できるようになりますか??? ちなみに答えは a="String" b="copyString" だそうです。

    • ベストアンサー
    • Java
  • 配列の型判定の仕方

    メソッドの引数をObjectにして、その引数の型を判定しようとしています。 たとえば以下のような感じです。 String hoge(Object para) { if(para.equals(java.lang.Integer.class)) { return "intです"; } return "わかりません" } 上記は、int型なら判定できるメソッドですが、int[]やString[]を判定するためにはどうしたらよいのでしょうか? paraにint[]型の値が入ってきた場合、 para.equals(java.lang.Integer[].class) としてもtrueにはなりませんでした。 どうすればできるのか、ご教授いただけると幸いです。 手段がなければ、para.getClass().toString()をして出力される文字列で判定しようかと思っています。

    • ベストアンサー
    • Java