2003/02/23
今回は、とっても便利な機能、リフレクションを使ってみたいと
思います。リフレクションってのは、主にjava.lang.reflectパッケージ
のことを指すんですけど、この機能ってのがすごい!!普通プログラム
ってプログラミング言語の構文通りに1行1行打ってくもんですけど
リフレクションを使うとプログラム自体をプログラムの中で生み出して
実行していくようなことが出来ます。(出来ることは限定されますが)
それでは、サンプルプログラムいってみよー!!
このプログラムは、ValueObject(値を入れておくオブジェクト、C言語の
構造体のような物)を引数に渡すと自動的にget〜で始まるメソッドを
ずべて実行して標準出力に出力するものです。
package reflect;
class MethodInvoke {
public static void main(String[] args) throws Exception {
Fighter obj = new Fighter(); // (1)
obj.setName("ピーターアーツ"); // (2)
obj.setTall(193); // (3)
printGetMethods(obj); // (4)
} // (5)
// (6)
private static void printGetMethods(Object obj) { // (7)
String methodName = null; // (8)
java.lang.reflect.Method[] methods // (9)
= obj.getClass().getMethods(); // (10)
for (int i=0; i < methods.length; i++) { // (11)
try { // (12)
methodName = methods[i].getName(); // (13)
if (methodName.indexOf("get") == 0) { // (14)
if (methodName.indexOf("getClass") == -1) { // (15)
Object[] args = null; // (16)
Object ret = methods[i].invoke(obj, args); // (17)
System.out.println( // (18)
methodName + "=" + ret); // (19)
} // (20)
} // (21)
} catch (Exception ex) { // (22)
System.out.println(methodName // (23)
+ "で呼び出しエラー\n理由 "+ ex.getMessage());
}
}
}
}
class Fighter {
private String name;
private int tall;
private String[] waza = {"ハイキック","ストレート","ひざ蹴り"};
public String getName() {
return this.name;
}
public int getTall() {
return this.tall;
}
public String getWaza(int index) {
return this.waza[index];
}
public void setName(String name) {
this.name = name;
}
public void setTall(int tall) {
this.tall = tall;
}
}
(1)から(3)でValueObjectを生成して値を設定。
(4)でメソッドを自動呼出しするメソッドを呼んでる。
(10)で引数で渡されたオブジェクトの全メソッドを取得している。
つまりはget〜やら、set〜やら全てのメソッドが返る。その中から
(14)でメソッド名がget〜で始まるものに絞り、
(15)でObjectクラスから継承したgetClass()メソッドを実行対象外にし、
(17)でメソッドを実行している。
で、その戻り値を標準出力に出力してるってわけ。
それでは、実行しましょう!
このメルマガをMethodInvoke.javaという名前で保存してください。
そして、上の方で出てきたXMLをpeopleData.xmlという名前でソースと
同じフォルダに保存します。
javac -d . *.java
java reflect.MethodInvoke
出力結果
getTall=193
getWazaで呼び出しエラー
理由 wrong number of arguments
ここで”getWazaで呼び出しエラー”という所に注目しましょう。
”理由 wrong number of arguments”
つまり、引数が間違った番号ですぜと言ってます。
なんでかっていうと(17)行目で method[i].invoke(obj, args)と
してるでしょ?(16)行目でargsにnullを入れてあるので
invokeの2番目の引数にnullを指定している。
この2番目の引数が実際にメソッドに渡される引数なのです。
getName等は引数がないからいいけど、getWazaは引数にint型を
とるからエラーが起きたってわけです。
(16)行目を
Object[] args = new Object[1];
args[0] = new Integer(1);
に置き換えると、getWazaはうまくいく、しかーし、getNameでこける。
ってなわけです。
どうでしたか、リフレクション。僕はとてもショッキングでした!!
プログラムの概念自体を変えちゃうようなすごい機能だなぁと
感じました。うまく使えば、書くのが面倒な単純処理を
スマートに片付けられるんじゃないかなーと。
例えばフレームワークのStrutsでは、画面で入力された内容を自動的に
ValueObjectに格納してくれるんですが、おそらくリフレクション
を使って実現してるんじゃないかなぁと思います。
それじゃ、リフレクションの便利な使い方が見つかったら、
またメルマガで報告するぜ!!
んじゃぁねぇーーーーーー!!