[Java] Reflection

9799 ワード

反射とは?


これはjava APIであり、ユーザーが特定のクラスタイプを知らずにそのクラスの情報(メソッド、タイプ、変数など)にアクセスできるようにします.
public class Car {
    private final String name;
    private int position;

    public Car(String name, int position) {
        this.name = name;
        this.position = position;
    }

    public void move() {
        this.position++;
    }

    public int getPosition() {
        return position;
    }
}
上記のように、Car類があります.
public static void main(String[] args) {
    Object obj = new Car("foo", 0);
    obj.move();    // 컴파일 에러 발생 java: cannot find symbol
}
Javaの多形性により、CarオブジェクトをObjectタイプに代入できます.
ただし,objというオブジェクトではCarクラスのmoveメソッドは使用できない.
Javaはコンパイル時にタイプを決定するので、objオブジェクトはオブジェクトによってタイプを決定するので、Objectクラスのインスタンス変数とメソッドのみ使用できます.
生成されたobjオブジェクトはObjectクラスしか知らず,Carクラスの具体的なタイプは知らない.最終的に、コンパイラが存在するJavaでは、特定のクラスが分からないと、そのクラスの情報にアクセスできないことがわかります.
この問題はReflection APIを使用して解決できます.
public static void main(String[] args) throws Exception {
    Object obj = new Car("foo", 0);
    Class carClass = Car.class;
    Method move = carClass.getMethod("move");

    // move 메서드 실행, invoke(메서드를 실행시킬 객체, 해당 메서드에 넘길 인자)
    move.invoke(obj, null);

    Method getPosition = carClass.getMethod("getPosition");
    int position = (int)getPosition.invoke(obj, null);
    System.out.println(position);
    // 출력 결과: 1
}
moveメソッドを実行し、0に初期化したCarクラスインスタンス変数position出力を1と決定することができる.
Reflection APIでは、特定のクラスカードタイプが分からなくてもmoveメソッドにアクセスできます.
Class carClass2 = Class.forName("Car");
上記の例に示すように、クラスの情報はクラス名のみで取得できます.
すなわち、Reflection APIは、クラス名のみを使用して、コンストラクション関数、フィールド、メソッドなど、クラスに関するほとんどの情報を取得できる魔法のようなAPIである.

どうしてそんなことができるの?


Javaでは、JVMが実行されると、ユーザーが作成したjavaコードがコンパイラを介してバイトコードに変換され、静的領域に格納されます.Reflection APIはこれらの情報を利用する.したがって,クラス名さえ分かれば,静的領域を随時検索して情報を取得することができる.

どこで使えますか?


上記のサンプルコードから、完全なCarオブジェクトがオブジェクトタイプで生成されていることがわかります.実際,コードを記述する場合,例のように記述するわけではない.したがって,我々はコードを記述する際に反射を利用することは少ない.具体的な等級を知らないことはほとんどないからだ.
アプリケーション開発に比べて、反射はフレームワークやライブラリに多く使用されます.フレームワークまたはライブラリでは、ユーザーが作成するクラスを予測できないため、反射を使用して問題を動的に解決します.
実際には、intellijの自動完了、Jacksonライブラリ、Hibernateなど、多くのフレームワークやライブラリでReflectionが使用されています.
Spring FrameworkもReflection APIを使用しており、代表的なのはSpring ContainerのBenFactoryである.beanは、アプリケーションの実行後に実行時にオブジェクトを呼び出すときに動的にオブジェクトインスタンスを作成し、Spring ContainerのBeanFactoryで使用します.
Spring Data JPAでEntityがデフォルトの作成者を必要とする理由も、オブジェクトを動的に作成するときに反射APIを使用するためです.反射APIで取得できない情報の1つは作成者のパラメータ情報である.オブジェクトを生成するには、デフォルトのジェネレータが必要です.デフォルトジェネレータを使用してオブジェクトを作成するだけで、フィールド値などをReflection APIに入れることができます.

反射の注意点と欠点


反射は強力なツールですが、盲目的に使用することはできません.反射を使わなくてもいいなら、使わないほうがいいです.アクセスコードを反射する場合は、次の点に注意してください.
パフォーマンスオーバーヘッド:反射には動的解析タイプが含まれているため、特定のJVMを最適化できません.したがって、反射は非反射よりもパフォーマンスが悪く、パフォーマンスに敏感なアプリケーションで頻繁に呼び出されるコードには使用されません.
パッケージング障害:反射はプライベート属性やメソッドにアクセスするように非反射コードで機能しないコードを実行できるため、反射を使用すると予想外の副作用が発生し、コード機能の低下や移植性が損なわれます.また、Reflectionは抽象を破り、プラットフォームのアップグレード時に動作を変える可能性があります.

[注意]

  • https://tecoble.techcourse.co.kr/post/2020-07-16-reflection-api/
  • https://medium.com/msolo021015/%EC%9E%90%EB%B0%94-reflection%EC%9D%B4%EB%9E%80-ee71caf7eec5
  • https://docs.oracle.com/javase/tutorial/reflect/
  • https://www.baeldung.com/java-reflection