リフレクションとは何ですか?なぜそれが役立つのですか?


2124

リフレクションとは何ですか?なぜそれが役立つのですか?

私は特にJavaに興味がありますが、原則はどの言語でも同じだと思います。


9
私にとっては、実行時にクラス名を取得し、そのクラスのオブジェクトを作成する方法です。
Nabin、2016年

65
これはよくある質問なので、リフレクション(アノテーションなし)は、問題を解決するときに最後に使用するツールであることを指摘したいと思います。私はそれを使用して大好きですが、Javaの静的型付けのすべての利点を打ち消します。必要な場合は、できるだけ小さな領域(1つのメソッドまたは1つのクラス)に分離してください。本番コードよりもテストで使用する方が受け入れられます。アノテーションがあれば問題ありません-回避できる可能性がある場合は、クラスまたはメソッド名を「文字列」として指定しないことが重要です。
Bill K


4
@BillKのコメントに加えて:リフレクションは非常に強力です。私はそれを魔法と呼びます。大きな力には大きな責任が伴います。自分が何をしているかわかっている場合にのみ使用してください。
MC皇帝

マニホールドを使用すると、リフレクションに関連する多くの落とし穴を回避でき@Jailbreakます。プライベートフィールドやメソッドなどへの直接のタイプセーフなアクセスを提供します。Javaコンパイラにコードを安全に検証させ、Manifoldに基になる反射アクセスを生成させます。詳細:Manifold.systems/docs.html#type-safe-reflection
Scott

回答:


1716

リフレクションという名前は、同じシステム(またはそれ自体)内の他のコードを検査できるコードを記述するために使用されます。

たとえば、Javaに不明なタイプのオブジェクトがあり、存在する場合はそのオブジェクトに対して「doSomething」メソッドを呼び出したいとします。Javaの静的型付けシステムは、オブジェクトが既知のインターフェースに準拠していない限り、これをサポートするように実際に設計されていませんが、リフレクションを使用して、コードはオブジェクトを調べ、「doSomething」というメソッドがあるかどうかを確認し、をしたい。

したがって、Javaでこれのコード例を提供するには(問題のオブジェクトがfooであると想像してください):

Method method = foo.getClass().getMethod("doSomething", null);
method.invoke(foo, null);

Javaでの非常に一般的な使用例の1つは、注釈の使用です。たとえば、JUnit 4はリフレクションを使用して、@ Testアノテーションが付けられたメソッドのクラスを調べ、ユニットテストの実行時にそれらを呼び出します。

http://docs.oracle.com/javase/tutorial/reflect/index.htmlから始めるための良いリフレクションの例がいくつかあります。

そして最後に、はい、概念はリフレクションをサポートする他の静的に型付けされた言語(C#など)とほとんど同じです。動的に型付けされた言語では、上記のユースケースはそれほど必要ではありません(コンパイラーは任意のオブジェクトで任意のメソッドを呼び出すことができるため、存在しない場合は実行時に失敗します)。特定の方法で作業することはまだ一般的です。

コメントから更新:

システム内のコードを検査してオブジェクトタイプを確認する機能は、リフレクションではなく、タイプイントロスペクションです。リフレクションは、イントロスペクションを利用して実行時に変更を加える機能です。一部の言語はイントロスペクションをサポートしていますが、リフレクションをサポートしていないため、ここでは区別が必要です。そのような例の1つはC ++です。


32
この行のnullパラメータの重要性を説明してください。Method method = foo.getClass()。getMethod( "doSomething"、null);
Krsna Chaitanya

54
nullは、fooメソッドに渡されるパラメーターがないことを示します。詳細については、docs.oracle.com / javase / 6 / docs / api / java / lang / reflect /…、java.lang.Object ...)を参照してください。
Matt Sheppard、2012年

791
これは非常に多くの賛成投票があるので、片付けます。システム内のコードを検査してオブジェクトタイプを確認する機能は、リフレクションではなく、タイプイントロスペクションです。リフレクションは、イントロスペクションを利用して実行時に変更を加える機能です。一部の言語はイントロスペクションをサポートしていますが、リフレクションをサポートしていないため、ここでは区別が必要です。そのような例の1つがC ++です。
bigtunacan 2013年

39
リフレクションは大好きですが、コードを制御できる場合は、この回答で指定されているリフレクションを使用することは必須ではないため、不正使用です。タイプイントロスペクション(instanceof)と強力なタイプを使用する必要があります。何かをするための反射以外の方法がある場合は、それを行う必要があります。静的に型付けされた言語を使用する利点をすべて失うため、リフレクションは深刻な心痛を引き起こします。それが必要な場合は必要ですが、それでも、Springなどの事前にパッケージ化されたソリューション、または必要な反射を完全にカプセル化するソリューションを検討します。
Bill K

6
@bigtunacanその情報はどこから入手しましたか?実行時に変更を加える機能だけでなく、オブジェクトのタイプを確認する機能についても説明するために、Oracleの公式Javaドキュメントで使用されている「リフレクション」という用語を見ています。そのほとんどは、いわゆる「タイプのイントロスペクション」関連クラスを言及しないように(例:MethodConstructorModifierFieldMember、基本的には明らか除くすべてClass)内にあるjava.lang.*reflect*パッケージ。おそらく、「リフレクション」という概念には、「型の内省」と実行時の変更の両方が包括的に含まれているのでしょうか。
RestInPeace

246

リフレクションは、実行時にクラス、メソッド、属性などを検査して動的に呼び出す言語の機能です。

たとえば、JavaのすべてのオブジェクトにはメソッドgetClass()があります。これは、コンパイル時にオブジェクトのクラスがわからない場合でも(たとえば、それをとして宣言した場合Object)、簡単に見えるかもしれませんが、そのようなリフレクションは不可能です。以下のような少ないダイナミックな言語でC++。より高度な使用法では、メソッドやコンストラクターなどをリストして呼び出すことができます。

リフレクションを使用すると、コンパイル時にすべてを「知る」必要がないプログラムを作成できるため、リフレクションが重要になります。リフレクションは、実行時に結合できるため、より動的になります。コードは既知のインターフェースに対して作成できますが、使用される実際のクラスは、構成ファイルからのリフレクションを使用してインスタンス化できます。

最新のフレームワークの多くは、まさにこの理由でリフレクションを広範囲に使用しています。他のほとんどの最近の言語もリフレクションを使用しており、スクリプト言語(Pythonなど)では、それらの言語の一般的なプログラミングモデル内でより自然に感じられるため、より緊密に統合されています。


2
つまり、言い換えると、修飾名からインスタンスを作成することができ、コンパイラはそれについて文句を言うことはありません(クラス名にStringのみを使用しているため)。次に、実行時に、そのクラスが存在しない場合は例外が発生します。この場合は、コンパイラをバイパスしました。これの具体的な使用例を教えていただけますか?いつ選ぶか想像できません。
フェルナンドガブリエリ2018

3
@FernandoGabrieliリフレクションで実行時エラーを作成するのは簡単ですが、実行時例外を発生させることなくリフレクションを使用することも完全に可能です。私の回答でほのめかしたように、リフレクションの一般的な使用法はライブラリまたはフレームワークであり、アプリケーションとは別にコンパイルされるため、コンパイル時にアプリケーションの構造を明示的に知ることができません。「規約によるコード」を使用するライブラリはリフレクションを使用する可能性がありますが、必ずしもマジックストリングを使用するわけではありません。
リードマン

1
C++実行時タイプ情報はありません。RTTI
Ayxan

114

リフレクションの私のお気に入りの使用法の1つは、以下のJavaダンプメソッドです。パラメータとして任意のオブジェクトを取り、JavaリフレクションAPIを使用してすべてのフィールド名と値を出力します。

import java.lang.reflect.Array;
import java.lang.reflect.Field;

public static String dump(Object o, int callCount) {
    callCount++;
    StringBuffer tabs = new StringBuffer();
    for (int k = 0; k < callCount; k++) {
        tabs.append("\t");
    }
    StringBuffer buffer = new StringBuffer();
    Class oClass = o.getClass();
    if (oClass.isArray()) {
        buffer.append("\n");
        buffer.append(tabs.toString());
        buffer.append("[");
        for (int i = 0; i < Array.getLength(o); i++) {
            if (i < 0)
                buffer.append(",");
            Object value = Array.get(o, i);
            if (value.getClass().isPrimitive() ||
                    value.getClass() == java.lang.Long.class ||
                    value.getClass() == java.lang.String.class ||
                    value.getClass() == java.lang.Integer.class ||
                    value.getClass() == java.lang.Boolean.class
                    ) {
                buffer.append(value);
            } else {
                buffer.append(dump(value, callCount));
            }
        }
        buffer.append(tabs.toString());
        buffer.append("]\n");
    } else {
        buffer.append("\n");
        buffer.append(tabs.toString());
        buffer.append("{\n");
        while (oClass != null) {
            Field[] fields = oClass.getDeclaredFields();
            for (int i = 0; i < fields.length; i++) {
                buffer.append(tabs.toString());
                fields[i].setAccessible(true);
                buffer.append(fields[i].getName());
                buffer.append("=");
                try {
                    Object value = fields[i].get(o);
                    if (value != null) {
                        if (value.getClass().isPrimitive() ||
                                value.getClass() == java.lang.Long.class ||
                                value.getClass() == java.lang.String.class ||
                                value.getClass() == java.lang.Integer.class ||
                                value.getClass() == java.lang.Boolean.class
                                ) {
                            buffer.append(value);
                        } else {
                            buffer.append(dump(value, callCount));
                        }
                    }
                } catch (IllegalAccessException e) {
                    buffer.append(e.getMessage());
                }
                buffer.append("\n");
            }
            oClass = oClass.getSuperclass();
        }
        buffer.append(tabs.toString());
        buffer.append("}\n");
    }
    return buffer.toString();
}

8
Callcountは何に設定する必要がありますか?
トム

8
これを実行すると、スレッド "AWT-EventQueue-0" java.lang.StackOverflowErrorで例外が発生しました。
トム

3
@Tom callCountはゼロに設定する必要があります。その値は、出力の各行の前にいくつのタブを置くかを決定するために使用されます。ダンプが「サブオブジェクト」をダンプする必要があるたびに、出力は親にネストされたものとして印刷されます。その方法は、別の方法でラップすると便利です。考えてくださいprintDump(Object obj){ System.out.println(dump(obj, 0)); }
2012年

1
循環参照の場合、未チェックの再帰が原因でjava.lang.StackOverflowErrorが作成される可能性があります:buffer.append(dump(value、callCount))
Arnaud P

4
コードをパブリックドメインにリリースできますか?
stolsvik 2013年

84

リフレクションの使用

リフレクションは、Java仮想マシンで実行されているアプリケーションの実行時の動作を検査または変更する機能を必要とするプログラムで一般的に使用されます。これは比較的高度な機能であり、言語の基本をよく理解している開発者のみが使用する必要があります。その警告を念頭に置いて、リフレクションは強力な手法であり、アプリケーションが他の方法では不可能な操作を実行できるようにすることができます。

拡張機能

アプリケーションは、完全修飾名を使用して拡張性オブジェクトのインスタンスを作成することにより、外部のユーザー定義クラスを利用できます。クラスブラウザーとビジュアル開発環境クラスブラウザーは、クラスのメンバーを列挙できる必要があります。ビジュアル開発環境では、型情報をリフレクションで利用できるため、開発者が正しいコードを作成するのに役立ちます。デバッガーとテストツールデバッガーは、クラスのプライベートメンバーを検査できる必要があります。テストハーネスはリフレクションを利用して、クラスで定義された検出可能なセットAPIを体系的に呼び出し、テストスイートで高レベルのコードカバレッジを確保できます。

リフレクションの欠点

リフレクションは強力ですが、無差別に使用しないでください。リフレクションを使用せずに操作を実行できる場合は、使用しないことをお勧めします。リフレクションを介してコードにアクセスする場合は、次の点に注意してください。

  • パフォーマンスのオーバーヘッド

リフレクションには動的に解決されるタイプが含まれるため、特定のJava仮想マシンの最適化は実行できません。したがって、リフレクティブ操作は非リフレクティブ操作よりもパフォーマンスが遅いため、パフォーマンスに敏感なアプリケーションで頻繁に呼び出されるコードのセクションでは避けてください。

  • セキュリティ制限

リフレクションにはランタイムパーミッションが必要ですが、セキュリティマネージャーで実行している場合は、このパーミッションが存在しない可能性があります。これは、アプレットなどの制限されたセキュリティコンテキストで実行する必要があるコードの重要な考慮事項です。

  • 内部の暴露

リフレクションを使用すると、プライベートフィールドやメソッドへのアクセスなど、非リフレクトコードでは違法となる操作をコードで実行できるため、リフレクションを使用すると予期しない副作用が発生し、コードが機能しなくなり、移植性が損なわれる可能性があります。リフレクティブコードは抽象化を壊すため、プラットフォームのアップグレードにより動作が変わる可能性があります。

ソース:リフレクションAPI


44

リフレクションは、アプリケーションまたはフレームワークがまだ作成されていないコードを処理できるようにするための重要なメカニズムです。

たとえば、典型的なweb.xmlファイルを見てみましょう。これには、ネストされたサーブレットクラス要素を含むサーブレット要素のリストが含まれます。サーブレットコンテナはweb.xmlファイルを処理し、リフレクションによって各サーブレットクラスの新しい新しいインスタンスを作成します。

もう1つの例は、Java API for XML Parsing (JAXP)です。XMLパーサープロバイダーが、リフレクションを通じて新しいインスタンスを構築するために使用される既知のシステムプロパティを介して「プラグイン」されている場合。

そして最後に、最も包括的な例は、リフレクションを使用してBeanを作成し、プロキシを多用するSpringです


36

すべての言語がリフレクションをサポートするわけではありませんが、原則は通常、リフレクションをサポートする言語で同じです。

リフレクションとは、プログラムの構造を「反映」する機能です。またはもっと具体的に。所有しているオブジェクトとクラスを確認し、それらが実装するメソッド、フィールド、およびインターフェースに関する情報をプログラムで取得します。アノテーションなども確認できます。

多くの状況で役に立ちます。クラスをコードに動的にプラグインできるようにしたいすべての場所。多くのオブジェクトリレーショナルマッパーはリフレクションを使用して、使用するオブジェクトを事前に知らなくても、データベースからオブジェクトをインスタンス化できます。プラグインアーキテクチャは、リフレクションが役立つ別の場所です。これらの状況では、コードを動的にロードして、プラグインとして使用する適切なインターフェースを実装するタイプがあるかどうかを判別できることが重要です。


DBに存在するデータに基づいてオブジェクトをインスタンス化する必要があります。これがあなたの言っていることだと思います。サンプルコードはとても役に立ちます。前もって感謝します。
Atom

34

リフレクションを使用すると、新しいオブジェクトのインスタンス化、メソッドの呼び出し、実行時に動的にクラス変数のget / set操作を行うことができ、その実装に関する事前の知識は必要ありません。

Class myObjectClass = MyObject.class;
Method[] method = myObjectClass.getMethods();

//Here the method takes a string parameter if there is no param, put null.
Method method = aClass.getMethod("method_name", String.class); 

Object returnValue = method.invoke(null, "parameter-value1");

上記の例では、nullパラメータは、メソッドを呼び出すオブジェクトです。メソッドが静的な場合はnullを指定します。メソッドが静的でない場合、呼び出し中にnullではなく有効なMyObjectインスタンスを提供する必要があります。

リフレクションでは、クラスのプライベートメンバー/メソッドにアクセスすることもできます。

public class A{

  private String str= null;

  public A(String str) {
  this.str= str;
  }
}

A obj= new A("Some value");

Field privateStringField = A.class.getDeclaredField("privateString");

//Turn off access check for this field
privateStringField.setAccessible(true);

String fieldValue = (String) privateStringField.get(obj);
System.out.println("fieldValue = " + fieldValue);
  • クラスのインスペクション(イントロスペクションとも呼ばれます)では、リフレクションパッケージ(java.lang.reflect)をインポートする必要はありません。クラスメタデータには、からアクセスできますjava.lang.Class

リフレクションは非常に強力なAPIですが、実行時にすべてのタイプを解決するため、過度に使用するとアプリケーションの速度が低下する可能性があります。


21

Javaリフレクションは非常に強力で、非常に便利です。Javaリフレクションを使用すると、コンパイル時にクラス、メソッドなどの名前を知らなくても、実行時にクラス、インターフェース、フィールド、およびメソッドを検査できますリフレクションを使用して、新しいオブジェクトインスタンス化し、メソッドを呼び出し、フィールド値を取得/設定することもできます。

リフレクションの使用がどのように見えるかを示す簡単なJavaリフレクションの例:

Method[] methods = MyObject.class.getMethods();

    for(Method method : methods){
        System.out.println("method = " + method.getName());
    }

この例では、MyObjectというクラスからClassオブジェクトを取得します。この例では、クラスオブジェクトを使用して、そのクラスのメソッドのリストを取得し、メソッドを反復処理して名前を出力します。

これがどのように機能するかを正確に説明します

編集:ほぼ1年後、Reflectionについて読んでいる間、Re​​flectionの使用例がほとんどないため、この回答を編集しています。

  • Springは次のようなBean構成を使用します。


<bean id="someID" class="com.example.Foo">
    <property name="someField" value="someValue" />
</bean>

Springコンテキストがこの<bean>要素を処理するとき、引数「com.example.Foo」を指定してClass.forName(String)を使用し、そのクラスをインスタンス化します。

次に、リフレクションを使用して<property>要素の適切なセッターを取得し、その値を指定された値に設定します。

  • Junitは、特にPrivate / ProtectedメソッドのテストにReflectionを使用します。

プライベートメソッドの場合

Method method = targetClass.getDeclaredMethod(methodName, argClasses);
method.setAccessible(true);
return method.invoke(targetObject, argObjects);

プライベートフィールドの場合

Field field = targetClass.getDeclaredField(fieldName);
field.setAccessible(true);
field.set(object, value);

21

例:

たとえば、APIメソッドを使用して取得したオブジェクトをアプリケーションに提供するリモートアプリケーションを考えてみましょう。オブジェクトに基づいて、何らかの計算を実行する必要があるかもしれません。

プロバイダーは、オブジェクトが3つのタイプであることを保証し、オブジェクトのタイプに基づいて計算を実行する必要があります。

したがって、それぞれが異なるロジックを含む3つのクラスで実装する可能性があります。当然、オブジェクト情報は実行時に利用できるため、静的に計算を実行するようにコーディングできないため、リフレクションを使用して、プロバイダーから受信したオブジェクト。


私は..私は反射コンセプトに新しいですと...例は私をたくさん助ける似た何かが必要
アトム

2
混乱しています:instanceof実行時にオブジェクトタイプを判別するために使用できませんか?
ndm13

19

反射の簡単な例。チェスのゲームでは、実行時にユーザーが何を動かすかはわかりません。リフレクションは、実行時に既に実装されているメソッドを呼び出すために使用できます。

public class Test {

    public void firstMoveChoice(){
        System.out.println("First Move");
    } 
    public void secondMOveChoice(){
        System.out.println("Second Move");
    }
    public void thirdMoveChoice(){
        System.out.println("Third Move");
    }

    public static void main(String[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { 
        Test test = new Test();
        Method[] method = test.getClass().getMethods();
        //firstMoveChoice
        method[0].invoke(test, null);
        //secondMoveChoice
        method[1].invoke(test, null);
        //thirdMoveChoice
        method[2].invoke(test, null);
    }

}

18

リフレクションは、実行時にメソッド、クラス、インターフェースの動作を検査または変更するために使用されるAPI です。

  1. リフレクションに必要なクラスは、にありjava.lang.reflect packageます。
  2. リフレクションは、オブジェクトが属するクラスに関する情報と、オブジェクトを使用して実行できるそのクラスのメソッドも提供します。
  3. リフレクションを通じて、使用されるアクセス指定子に関係なく、実行時にメソッドを呼び出すことができます。

java.langそしてjava.lang.reflectパッケージはJavaのリフレクションのためのクラスを提供します。

リフレクションは、についての情報を取得するために使用できます–

  1. クラスこのgetClass()メソッドは、オブジェクトが属するクラスの名前を取得するために使用されます。

  2. コンストラクタこのgetConstructors()メソッドは、オブジェクトが属するクラスのパブリックコンストラクターを取得するために使用されます。

  3. メソッドザ・getMethods()メソッドは、オブジェクトが属するクラスのpublicメソッドを取得するために使用されます。

リフレクションAPIは、主に使用されます。

IDE(統合開発環境)例:Eclipse、MyEclipse、NetBeansなど。
デバッガやテストツールなど。

リフレクションを使用する利点:

拡張機能:アプリケーションは、完全修飾名を使用して拡張オブジェクトのインスタンスを作成することにより、外部のユーザー定義クラスを利用できます。

デバッグおよびテストツール:デバッガーはリフレクションのプロパティを使用して、クラスのプライベートメンバーを調べます。

欠点:

パフォーマンスのオーバーヘッド:リフレクティブ操作は、非リフレクティブ操作よりもパフォーマンスが遅いため、パフォーマンスに敏感なアプリケーションで頻繁に呼び出されるコードのセクションでは避けてください。

内部の露出:リフレクティブコードは抽象化を壊すため、プラットフォームのアップグレードにより動作が変わる可能性があります。

参照:Javaリフレクション javarevisited.blogspot.in


4
私は「リファクタリングを壊す」という欠点を付け加えます。私にとって、それは反射をできるだけ避ける主な理由です。
SantiBailors 2017

それで、(たとえば)私たちが持っているクラスを検査することができます(それらのインスタンスがあるかどうかにかかわらず)、正しいですか?つまり、それらのメソッドまたはコンストラクターを取得し、それらを使用して新しいインスタンスの作成/呼び出しを行います。動作がすでに存在しているがコードが異なる場合、なぜ「プログラムの動作を変更する」と言うのですか?なぜ「リフレクション」と呼ばれるのですか?ありがとう
フェルナンドガブリエリ2018

15

私の理解に従って:

リフレクションを使用すると、プログラマはプログラム内のエンティティに動的にアクセスできます。つまり、プログラマーがクラスやそのメソッドについて知らない場合にアプリケーションをコーディングするときに、リフレクションを使用することにより、そのようなクラスを動的に(実行時に)利用できます。

これは、クラス名が頻繁に変更されるシナリオで頻繁に使用されます。このような状況が発生した場合、プログラマーがアプリケーションを書き直してクラスの名前を何度も変更するのは複雑です。

代わりに、リフレクションを使用することで、クラス名が変更される可能性を心配する必要があります。


15

リフレクションは、プログラムのランタイム情報にアクセスし、その動作を(いくつかの制限付きで)変更できるようにする一連の関数です。

プログラムのメタ情報に応じて実行時の動作を変更できるため、つまり、関数の戻り値の型を確認し、状況の処理方法を変更できるため、便利です。

たとえばC#では、実行時にアセンブリ(.dll)を読み込み、それを調べて、クラスを移動し、見つけたものに従ってアクションを実行できます。また、実行時にクラスのインスタンスを作成したり、そのメソッドを呼び出したりすることもできます。

どこで役に立ちますか?毎回役立つわけではありませんが、具体的な状況で役立ちます。たとえば、ロギングの目的でクラスの名前を取得したり、構成ファイルでの指定に従ってイベントのハンドラーを動的に作成したりするために使用できます。


11

記載されているすべてにポイントを追加したいだけです。

リフレクションAPIあなたは、ユニバーサル書くことができますtoString()任意のオブジェクトのための方法を。

デバッグ時に役立ちます。

ここにいくつかの例があります:

class ObjectAnalyzer {

   private ArrayList<Object> visited = new ArrayList<Object>();

   /**
    * Converts an object to a string representation that lists all fields.
    * @param obj an object
    * @return a string with the object's class name and all field names and
    * values
    */
   public String toString(Object obj) {
      if (obj == null) return "null";
      if (visited.contains(obj)) return "...";
      visited.add(obj);
      Class cl = obj.getClass();
      if (cl == String.class) return (String) obj;
      if (cl.isArray()) {
         String r = cl.getComponentType() + "[]{";
         for (int i = 0; i < Array.getLength(obj); i++) {
            if (i > 0) r += ",";
            Object val = Array.get(obj, i);
            if (cl.getComponentType().isPrimitive()) r += val;
            else r += toString(val);
         }
         return r + "}";
      }

      String r = cl.getName();
      // inspect the fields of this class and all superclasses
      do {
         r += "[";
         Field[] fields = cl.getDeclaredFields();
         AccessibleObject.setAccessible(fields, true);
         // get the names and values of all fields
         for (Field f : fields) {
            if (!Modifier.isStatic(f.getModifiers())) {
               if (!r.endsWith("[")) r += ",";
               r += f.getName() + "=";
               try {
                  Class t = f.getType();
                  Object val = f.get(obj);
                  if (t.isPrimitive()) r += val;
                  else r += toString(val);
               } catch (Exception e) {
                  e.printStackTrace();
               }
            }
         }
         r += "]";
         cl = cl.getSuperclass();
      } while (cl != null);

      return r;
   }    
}

11

反射は、オブジェクトにその外観を表示させることです。この議論は反射とは何の関係もないようです。実際、これは「自己識別」能力です。

リフレクション自体は、JavaやC#のような自己認識と自己検知の機能に欠ける言語を表す言葉です。彼らは自己認識の能力を持っていないので、それがどのように見えるかを観察したいとき、それがどのように見えるかを反映するために別のものが必要です。RubyやPythonなどの優れた動的言語は、他の人の助けを借りずに、自分の言語の反映を認識することができます。Javaのオブジェクトは、リフレクションクラスのオブジェクトであるミラーなしではどのように見えるかを認識できませんが、Pythonのオブジェクトでは、ミラーなしでオブジェクトを認識できます。そのため、Javaでのリフレクションが必要です。


type()、isinstance()、callable()、dir()、getattr()。....これらはPythonicリフレクションコールです
AnthonyJClink

9

Javaドキュメントページから

java.lang.reflectパッケージは、クラスとオブジェクトに関する反映情報を取得するためのクラスとインターフェースを提供します。リフレクションを使用すると、ロードされたクラスのフィールド、メソッド、コンストラクターに関する情報にプログラムでアクセスでき、リフレクトされたフィールド、メソッド、コンストラクターを使用して、セキュリティ制限内で対応するフィールドを操作できます。

AccessibleObject必要に応じてアクセスチェックを抑制ReflectPermissionできます。

一緒に、このパッケージのクラス、java.lang.Classなどなど、デバッガ、インタプリタ、オブジェクトインスペクタ、クラスブラウザ、およびサービスなどのアプリケーションに対応Object SerializationしてしJavaBeans(実行時のクラスに基づく)ターゲットオブジェクトのパブリックメンバーまたはメンバーのいずれかにその必要性へのアクセスがによって宣言与えられたクラス

次の機能が含まれています。

  1. Classオブジェクトの取得
  2. クラス(フィールド、メソッド、コンストラクター)のプロパティを調べる
  3. フィールド値の設定と取得、
  4. メソッドの呼び出し
  5. オブジェクトの新しいインスタンスを作成します。

によって公開されているメソッドについては、このドキュメントのリンクをご覧ください。Classクラス。

この記事(Sosnoski Software Solutions、Inc、社長、Dennis Sosnoski)とこの記事から(security-explorations pdf)から:

Reflectionを使用するよりもかなりの欠点があることがわかります

リフレクションのユーザー:

  1. プログラムコンポーネントを動的にリンクする非常に用途の広い方法を提供します
  2. 非常に一般的な方法でオブジェクトを操作するライブラリを作成するのに役立ちます

リフレクションの欠点:

  1. リフレクションは、フィールドおよびメソッドアクセスに使用すると、直接コードよりもはるかに遅くなります。
  2. それはあなたのコードの中で実際に起こっていることを不明瞭にすることができます
  3. ソースコードをバイパスしてメンテナンスの問題を引き起こす可能性があります
  4. リフレクションコードは、対応する直接コードよりも複雑です
  5. データアクセス保護やタイプセーフなどの主要なJavaセキュリティ制約の違反を許可します

一般的な虐待:

  1. 制限されたクラスの読み込み、
  2. 制限されたクラスのコンストラクター、メソッドまたはフィールドへの参照を取得する、
  3. 新しいオブジェクトインスタンスの作成、メソッドの呼び出し、制限されたクラスのフィールド値の取得または設定。

リフレクション機能の悪用に関するこのSEの質問をご覧ください。

Javaでプライベートフィールドを読み取るにはどうすればよいですか?

概要:

システムコード内からその機能を安全に使用しないと、Javaセキュリティモードの侵害につながる可能性がありますしたがって、この機能は慎重に使用してください


場合によっては、Reflectionのパフォーマンスの問題を回避する方法としてWoozle、起動時にクラスに他のクラスを調べて、静的RegisterAsWoozleHelper()メソッドがあるクラスを確認し、見つかったすべてのメソッドを、Woozle自分自身に知らせるために使用できるコールバックで呼び出すことを避けます。たとえば、データをデシリアライズするときにReflectionを使用する必要があります。
スーパーキャット

9

名前自体が示唆するように、実行時に動的にインスタンスを作成するメソッドを呼び出す機能を提供することを除いて、それは例のクラスメソッドなどが持つ内容を反映しています。

実際にコードを知らなくてもサービスを呼び出すために、多くのフレームワークや木の下のアプリケーションで使用されています。


7

リフレクションを使用すると、より一般的なコードを記述できます。実行時にオブジェクトを作成し、実行時にそのメソッドを呼び出すことができます。したがって、プログラムを高度にパラメーター化することができます。また、オブジェクトとクラスをイントロスペクトして、外部の世界に公開されている変数とメソッドを検出することもできます。


6

Reflection多くの用途があります。私がよく知っているのは、オンザフライでコードを作成できることです。

IE:動的クラス、関数、コンストラクター-任意のデータに基づく(xml / array / sql results / hardcoded / etc。)


1
あなたがなどSQLの結果から、またはXMLファイルのいずれかに生成されたコードのひとつ珍しい例を与えた場合には、この答えは、多くの方が良いだろう
ThisClark

問題ない。データベースから取得したXMLに基づいてインターフェイスを動的に生成するWindowsアプリケーションでリフレクションを使用しました。
Ess Kay

基本的に、ユーザーにレポートを表示するために作成したクラスがあります。このレポートには、Date(from)IDなどのパラメーターがあります。この情報はxmlに保存されます。したがって、最初にレポートを選択します。選択したレポートに基づいて、フォームはXMLを取得します。xmlが取得されると、リフレクションを使用して、リフレクトされたタイプに基づくフィールドを持つクラスが作成されます。別のレポートに変更すると、スレートが完全に消去され、xmlに基づいて新しいフィールドが生成されます。つまり、本質的には反射に基づく動的なフォームです。私は他の方法でも使用が、これは役立ちますsuffecient希望する必要があります
エス・ケイ

3

この質問に例を挙げて回答したいと思います。最初に、HibernateプロジェクトはステートメントReflection APIを生成するために使用してCRUD、実行中のアプリケーションと永続ストアの間の裂け目を橋渡しします。ドメインで状況が変化した場合、はHibernateそれらを認識して、それらをデータストアに永続化する必要があります。

代わりに動作しLombok Projectます。コンパイル時にコードを挿入するだけで、ドメインクラスにコードが挿入されます。(ゲッターとセッターは問題ないと思います)

Hibernatereflectionこれは、アプリケーションのビルドプロセスへの影響が最小限であるために選択しました。

そしてJava 7 MethodHandles以降、として機能しReflection APIます。プロジェクトでは、ロガーを操作するために、次のコードをコピーして貼り付けます。

Logger LOGGER = Logger.getLogger(MethodHandles.lookup().lookupClass().getName());

この場合、タイプミスをするのは難しいからです。


3

私は例で説明するのが最善であり、答えのどれもそれを行うようには見えないので...

リフレクションを使用する実用的な例は、Javaで記述されたJava言語サーバーまたはPHPで記述されたPHP言語サーバーなどです。言語サーバーは、オートコンプリート、定義へのジャンプ、コンテキストヘルプ、ヒントタイプなどのIDE機能を提供します。入力時にすべての可能な一致を表示するためにすべてのタグ名(オートコンプリート可能な単語)を表示するには、Language Serverがdocブロックとプライベートメンバーを含むクラスに関するすべてを検査する必要があります。そのためには、このクラスの反映が必要です。

別の例は、プライベートメソッドの単体テストです。そのための1つの方法は、リフレクションを作成し、テストのセットアップフェーズでメソッドのスコープをpublicに変更することです。もちろん、プライベートメソッドを直接テストすべきではないと主張することもできますが、それは重要ではありません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.