[???] / [Java FAQ] / [S031]
S031: リフレクション - reflection

[Q1]
Back
Class.forName()で発生する例外は典型的にはどう処理すべきでしょうか? [S031 A-1] 例外時に何も対処のしようがない(するつもりがない)ケースでは、 Component newComponent(String className) { try { return (Component) Class.forName(className).newInstance() ; } catch (ClassNotFoundException e) { throw new NoClassDefFoundError(e.getMessage()); } catch (InstantiationException e) { throw new InstantiationError(e.getMessage()); } catch (IllegalAccessException e) { throw new IllegalAccessError(e.getMessage()); } } などとするのがよいでしょう。 他にも NoSuchFieldException -> NoSuchFieldErorr NoSuchMethodException -> NoSuchMethodError があります。
[Q2]
Back
リフレクション API で public でないフィールドにアクセスできますか? [S031 A-2] Class クラスの getDeclaredField, getDeclaredFields メソッドで Field オブ ジェクトの取得はできます。ただし、そのフィールドへ値の設定/取得ができる かどうかは Java 言語仕様上のアクセス制限で決まります。
[Q3]
Back
getDeclaredFields で private なフィールドを得られるがその値は得られない のですが? [S031 A-3] getDeclaredFields では private のフィールドも返しますが、 そのフィールドに対してアクセスができるかどうかは Java の通常の言語仕様上 のアクセス制限によります。例えば、実行しているコードとは別のパッケージの クラスのオブジェクトの private なフィールドの値を通常の方法で取得するこ とはできません。 [コメント] AccessController と PrivilegedAction を使用すればできますが...。
[Q4]
Back
Method オブジェクトの invoke で発生した Exception を InvocationTargetException から取り出すにはどうしたらよいですか? [S031 A-4] InvocationTargetException#getTargetException() を使用してください。
[Q5]
Back
InvocationTargetException では、invoke した先で新たに走らされたスレッド 発生した例外を catch できないのですが? [S031 A-5] InvocationTargetException に限らず、スレッド A から別のスレッド B を 起動して、B で発生した例外を A で調べるには、普通の try-catch では できませんので、仕掛けが必要です。 たとえば、 -- public abstract class ThrowableThread extends Thread { private Exception th; private boolean finished; protected abstract void throwableRun() throws Exception; public void run() { try { myRun(); } catch (Exception th) { this.th = th; } finally { this.finished = true; } } public boolean isFinished() throws Exception { if (finished) { if (th != null) { throw th; } else { return true; } } return false; } } -- というクラスを作成して、新スレッドの処理は ThrowableThread を継承した クラスの throwableRun() メソッドに実装します。 このスレッドを起動したスレッドからは isFinished メソッドで終了したか どうか、例外が発生しているかどうかをチェックできます。
[Q6]
Back
配列オブジェクトに対する getClass().getName() が返す文字列の意味はなんですか? [S031 A-6] Type Signature Java Type Z boolean B byte C char S short I int J long F float D double L fully-qualified-class ; fully-qualified-class [ type type[] ( arg-types ) ret-type method type となっています。具体的には、 "[Z" なら boolean[] "[[I" なら int[][] "[Ljava.lang.Object;" なら Object[] などとなります。また、 int[] a = new int[1]; であるとき、 Class.forName("[I") == a.getClass() です。
[Q7]
Back
primitive type のクラスオブジェクトを得るにはどうしたらいいのでしょうか? [S031 A-7] primitive type クラスオブジェクト boolean boolean.class または Boolean.TYPE byte byte.class または Byte.TYPE char char.class または Character.TYPE short short.class または Short.TYPE int int.class または Integer.TYPE long long.class または Long.TYPE float float.class または Float.TYPE double double.class または Double.TYPE となります。
[Q8]
Back
Class.getMethod(String, Class[])でプリミティブ型配列の引数を指定するには どうしたらいいのでしょうか? [S031 A-8] "int[].class" などとします。 例えば、 Class cls = StringBuffer.class; Method method = cls.getMethod("append", new Class[] { char[].class }); などとすれば、 StringBuffer#append(char[] str) メソッドを取得できます。
[Q9]
Back
Class.forName(classname)で配列オブジェクトのクラスを得るにはどうしたらい いのでしょうか? [S031 A-9] int[].class, Object[].class などとします。 または、 int[] array = new int[0]; Class clazz = array.getClass(); でも ok です。 [S031 A-6][S031 A-8]も参照してください。
[Q10]
Back
あるプリミティブ型に対応するwrapperクラスを取得するには? [S031 A-10] 以下のメソッドでできます。 static Class getWrapper(Class clazz) { Object array = Array.newInstance(clazz, 1); //配列を作り Object wrapper = Array.get(array,0); //その要素を得て return wrapper.getClass(); //そのクラスを得る } [j-h-b:17767]
[Q11]
Back
パッケージ名を得る目的で「getClass().getPackage().getName()」は使えない のでしょうか? [S031 A-11] getClass().getPackage() で返されるパッケージオブジェクトは、 このクラスのクラスローダがパッケージオブジェクトを作成したときのみ 返します。 パッケージが jar コマンドの "-m" オプションなどでマニフェストで情報が定 義され、さらにクラスローダがパッケージオブジェクトを作成したときのみ パッケージがバージョンと仕様に関する属性を持ちます。
[Q12]
Back
「コールバック関数」を実現するために java.lang.reflect.Method を使うのは? [S031 A-12] まず、インタフェースを使用してできるかどうかを考えた方が良いでしょう。 コールバックされるメソッドをインタフェースで定義して、そのインタフェース を実装したオブジェクトをコールバックするメソッドに対して渡せば 実現できます。 このやり方でどうしてもうまく行かない(本質的にメソッドを文字列で指定する、 任意のメソッド呼出しに対して proxy のように機能させるなど)場合にのみ Method#invoke を使用することを検討しましょう。 なお、J2SE v1.3 からはプロキシクラス構築用に java.lang.reflect.Proxy クラスが追加されています。
[Q13]
Back
mainメソッドがあるクラスを探したいのですが? [S031 A-13] クラスが分っているなら、次のようなメソッドで判定できます。 指定したクラスまたはそのスーパークラスが public static void main(String arg[]) というシグネチャを持つメソッドを 持っていれば true を返します。 public static boolean hasMain(Class clazz) { try { Method method = clazz.getMethod("main", new Class[] { String[].class }); if (Modifier.isStatic(method.getModifiers())) { return method.getReturnType().equals(void.class); } return false; } catch (NoSuchMethodException e) { return false; } }
[Q14]
Back
ロードしたクラスの一覧を得る native メソッドはあるでしょうか? [S031 A-14] [コメント] 回答[j-h-b: 13918]が JNI ではないのですぐには書けません。
[Q15]
Back
そもそも reflection とはなんですか? [S031 A-15] 日本語ではそのまま「リフレクション」、または「自己反映計算」とも 呼ばれます。 簡単に言うと、プログラムを実行中に、そのプログラム自身についての情報を得 たり、その内容を変更したりすることのできる言語や計算モデルです。 Java では、reflection API によりこれが可能になっていて、 プログラムについての情報(クラス、フィールド、メソッドなど) を得たり、その情報に基づいてメソッドを実行したりすることができます。 この機能を利用すると、JavaBean のように実行するまでどんなクラスの どんなメソッドを扱うか分からない(プロパティ取得メソッドなどはプロパティ 名が分らないと決められない)ときなどに威力を発揮します。

Back
contributor: markn
コメントの送り先 Java FAQ BBS