Try using it in your preferred language.

English

  • English
  • 汉语
  • Español
  • Bahasa Indonesia
  • Português
  • Русский
  • 日本語
  • 한국어
  • Deutsch
  • Français
  • Italiano
  • Türkçe
  • Tiếng Việt
  • ไทย
  • Polski
  • Nederlands
  • हिन्दी
  • Magyar
translation

これはAIが翻訳した投稿です。

제이온

[Java] リフレクションの概念と使用方法

言語を選択

  • 日本語
  • English
  • 汉语
  • Español
  • Bahasa Indonesia
  • Português
  • Русский
  • 한국어
  • Deutsch
  • Français
  • Italiano
  • Türkçe
  • Tiếng Việt
  • ไทย
  • Polski
  • Nederlands
  • हिन्दी
  • Magyar

durumis AIが要約した文章

  • リフレクションは、実行時にクラス情報にアクセスしてクラスを操作できるAPIです。
  • リフレクションを使用すると、クラスのインスタンスを生成したり、フィールドやメソッドにアクセス制御子に関係なくアクセスできます。特に、フレームワークなど大規模な開発段階で依存関係を動的に管理する場合に役立ちます。
  • ただし、カプセル化を損なったり、パフォーマンスを低下させる可能性があるため、必要な場合にのみ使用することをお勧めします。

リフレクションとは?

リフレクションは、ヒープ領域にロードされたClass型のオブジェクトを通じて、目的のクラスのインスタンスを作成できるようにサポートし、インスタンスのフィールドとメソッドにアクセス修飾子に関係なくアクセスできるようにサポートするAPIです。



ここで、ロードされたクラスとは、JVMのクラスローダーがクラスファイルのロードを完了した後、そのクラスの情報を含むClass型のオブジェクトを生成してメモリ上のヒープ領域に保存したものを意味します。newキーワードを使って作るオブジェクトとは違う点に注意しましょう。もし、このClass型のオブジェクトについて理解が不足している場合は、java.lang.classオブジェクトのJDKドキュメントを確認すると良いでしょう。


使用方法

リフレクションを使用する前に、ヒープ領域にロードされたクラス型のオブジェクトを取得する必要があります。合計3つの方法があります。


  • クラス.classで取得
  • インスタンス.getClass()で取得
  • Class.forName("クラス名")で取得


public class Member {

    private String name;

    protected int age;

    public String hobby;

    public Member() {
    }

    public Member(String name, int age, String hobby) {
        this.name = name;
        this.age = age;
        this.hobby = hobby;
    }

    public void speak(String message) {
        System.out.println(message);
    }

    private void secret() {
        System.out.println("パスワードは1234です。");
    }

    @Override
    public String toString() {
        return "Member{" +
            "name='" + name + '\'' +
            ", age=" + age +
            ", hobby='" + hobby + '\'' +
            '}';
    }
}

public class Main {

    public static void main(String[] args) throws ClassNotFoundException {
        Class memberClass = Member.class;
        System.out.println(System.identityHashCode(memberClass));

        Member member = new Member("ジェイオン", 23, "ダラツ開発");
        Class memberClass2 = member.getClass();
        System.out.println(System.identityHashCode(memberClass2));

        Class memberClass3 = Class.forName("{パッケージ名}.Member");
        System.out.println(System.identityHashCode(memberClass3));
    }
}

// 実行結果
1740000325
1740000325

3つの方法で取得したClass型のインスタンスはすべて同じであることが確認できます。どの方法を使用してもハッシュ値が同じなので、状況に応じて適切に使用すれば良いでしょう。


これで、取得したClass型を通じて、そのクラスのインスタンスを作成することも、インスタンスのフィールドとメソッドにアクセス修飾子に関係なくアクセスすることもできるようになりました。まず、そのクラスのインスタンスを作成してみましょう。


public class Main {

    public static void main(String[] args) throws Exception {
        // Memberのすべてのコンストラクター出力
        Member member = new Member();
        Class memberClass = member.getClass();
        Arrays.stream(memberClass.getConstructors()).forEach(System.out::println);

        // Memberのデフォルトコンストラクターによるインスタンス生成
        Constructor constructor = memberClass.getConstructor();
        Member member2 = constructor.newInstance();
        System.out.println("member2 = " + member2);

        // Memberの別のコンストラクターによるインスタンス生成
        Constructor fullConstructor =
            memberClass.getConstructor(String.class, int.class, String.class);
        Member member3 = fullConstructor.newInstance("ジェイオン", 23, "ダラツ開発");
        System.out.println("member3 = " + member3);
    }
}

// 実行結果
public Member()
public Member(java.lang.String,int,java.lang.String)
member2 = Member{name='null', age=0, hobby='null'}

getConstructor()を使用してコンストラクターを取得し、newInstance()を使用してMemberインスタンスを動的に作成することができます。

最後に、インスタンスのフィールドとメソッドにアクセス修飾子に関係なくアクセスして使用してみましょう。

public class Main {

    public static void main(String[] args) throws Exception {
        Member member = new Member("ジェイオン", 23, "ダラツ開発");
        Class memberClass = member.getClass();

        // フィールドアクセス
        Field[] fields = memberClass.getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            System.out.println(field.get(member));
        }
        fields[0].set(member, "ジェイオン2");
        System.out.println(member);

        // メソッドアクセス
        Method speakMethod = memberClass.getDeclaredMethod("speak", String.class);
        speakMethod.invoke(member, "リフレクションテスト");

        Method secretMethod = memberClass.getDeclaredMethod("secret");
        secretMethod.setAccessible(true);
        secretMethod.invoke(member);
    }
}

// 実行結果
ジェイオン
23
ダラツ開発
Member{name='ジェイオン2', age=23, hobby='ダラツ開発'}
リフレクションテスト

getDeclaredFileds()を使用してクラスのインスタンス変数をすべて取得し、get()を使用してフィールド値を返却し、set()を使用してフィールド値を変更できることがわかります。ここで注意すべき点は、privateアクセス修飾子を持つフィールドにアクセスする場合、setAccessible()の引数にtrueを指定する必要があるということです。


メソッドもgetDeclaredMethod()を使用して取得できます。このとき、メソッドの名前とパラメーターの型を引数として渡す必要があります。同様に、privateアクセス修飾子を持つメソッドにアクセスする場合、setAccessible()の引数にtrueを設定する必要があります。最後に、invoke()メソッドを使用して、リフレクションAPIで取得したメソッドを呼び出すことができます。


長所と短所

  • 長所
    • 実行時にクラスのインスタンスを作成し、アクセス修飾子に関係なくフィールドとメソッドにアクセスして、必要なタスクを実行できる柔軟性があります。
  • 短所
    • カプセル化を損なう可能性があります。
    • 実行時にインスタンスを作成するため、コンパイル時にその型をチェックできません。
    • 実行時にインスタンスを作成するため、具体的な動作フローを把握するのが難しい場合があります。
    • 単純にフィールドとメソッドにアクセスする場合よりも、リフレクションを使用してアクセスする場合の方がパフォーマンスが低下する可能性があります。(すべての状況でパフォーマンスが低下するわけではありません)。


使用理由

リフレクションAPIを使用すると、実行時にクラス情報にアクセスして、クラスを自由に操作することができます。privateアクセス修飾子で宣言されたフィールドやメソッドでさえ操作可能です。オブジェクト指向設計では、カプセル化が重要であるため、使用すべきではない技術のように見えるかもしれません。


規模の小さいコンソールレベルでは、開発者はコンパイル時にプログラムで使用されるオブジェクトと依存関係をすべて把握することができます。しかし、フレームワークなど大規模な開発段階では、膨大な数のオブジェクトと依存関係を把握するのは困難です。このような場合、リフレクションを使用すると、動的にクラスを作成して依存関係を結び付けることができます。


例えば、SpringのBean Factoryを見てみると、@Controller、@Service、@Repositoryなどのアノテーションを付けるだけで、Bean Factoryが自動的にそのアノテーションが付けられたクラスを作成して管理していることがわかります。開発者は、Bean Factoryにそのクラスを知らせていませんが、それが可能な理由は、リフレクションのおかげです。実行時に、そのアノテーションが付けられたクラスを探索して発見したら、リフレクションを使用してそのクラスのインスタンスを作成し、必要なフィールドを注入してBean Factoryに保存するような形で使用されます。


もちろん、前述したように、カプセル化を損なう可能性があるため、本当に必要な場合にのみ使用するようにしましょう。


出典

제이온
제이온
제이온
제이온
[Effective Java] アイテム 1. 静的ファクトリメソッドをコンストラクタよりも優先する 静的ファクトリメソッドは、コンストラクタの代わりにインスタンスを作成する柔軟で効率的な方法です。 名前を付けることができ、特定の条件に合致するインスタンスを返したり、キャッシュを使ってパフォーマンスを向上させることができます。 シングルトンパターンとは異なり、複数のタイプのインスタンスを作成して返したり、リフレクションを使わずに柔軟性を維持することができます。

2024年4月27日

[Effective Java] アイテム 4. インスタンス化を阻止するには、private コンストラクターを使用する 静的メソッドとフィールドのみを含むユーティリティクラスは、インスタンス化を防ぐために、コンストラクターのアクセス修飾子をprivateに設定するのが最適です。 これにより、ユーザーがコンストラクターが自動生成されたものと誤解するのを防ぎ、継承を不可能にすることで、クラスの意図を明確に示すことができます。

2024年4月28日

[エフェクティブ・Java] アイテム 3. プライベートコンストラクタまたは列挙型でシングルトンであることを保証する Javaでのシングルトンパターンの実装方法3つ(public static メンバー、静的ファクトリメソッド、列挙型)を紹介し、それぞれの方法の長所と短所、シリアライズ時の注意点について説明します。リフレクション攻撃に対する安全性とコードの簡潔さを考慮して、列挙型方式を最も望ましい方法として提示します。(出典:エフェクティブ・Java、 https://catsbi.oopy.io/d7f3a636-b613-453b-91c7-655d71fda2b1)

2024年4月27日

概念的データモデリング 概念的データモデリングは、エンティティを分離し、エンティティ間の関係をERDで表現するプロセスです。エンティティは独立した情報単位であり、属性は エンティティが持つデータです。識別子はエンティティを一意に識別し、関係はエンティティ間の相互作用を表します。カーディナリティはエンティティ間の数値的 関係、オプション性はデータの必須性を示します。
제이의 블로그
제이의 블로그
제이의 블로그
제이의 블로그

2024年4月8日

[Javascript] オブジェクトの構造 (V8) JavaScriptのObjectは、V8エンジンでは、状態に応じて、構造体のように最適化されたFastモードと、ハッシュマップとして動作するDictionary モードに変換されます。Fastモードは、キーと値がほとんど固定された形式で高速ですが、新しいキーが追加されたり、要素を削除したりするなどの操作が行われた場合、 Dictionaryモードに切り替わり、速度が遅くなる可能性があります。
곽경직
곽경직
곽경직
곽경직
곽경직

2024年3月18日

レヴューコーポレーション、インフルエンサーマルチリンクサービス「レヴューリンク」リリース レヴューコーポレーションは、インフルエンサーがさまざまなチャンネルを1つのリンクにまとめて表示できるマルチリンクサービス「レヴューリンク(REVU Link)」を リリースしました。インフルエンサーは自分のソーシャルメディアアカウントを簡単に共有することで、広告主に対して影響力をアピールし、コラボレーションの機会を獲得できます。
스타트업 커뮤니티 씬디스 (SeenThis.kr)
스타트업 커뮤니티 씬디스 (SeenThis.kr)
스타트업 커뮤니티 씬디스 (SeenThis.kr)
스타트업 커뮤니티 씬디스 (SeenThis.kr)

2024年5月16日

SK C&C、顧客向けsLLM実装支援プラットフォーム「Soluer LLMOps」発表 SK C&Cが、企業向けにカスタマイズされた小型大規模言語モデル(sLLM)構築プラットフォーム「Soluer LLMOps」をリリースしました。このプラットフォームは、 ChatGPT、HyperCLOVA Xなどの様々なファウンデーションモデルを活用することで、ドラッグ&ドロップ方式で簡単にsLLMを作成できます。
스타트업 커뮤니티 씬디스 (SeenThis.kr)
스타트업 커뮤니티 씬디스 (SeenThis.kr)
스타트업 커뮤니티 씬디스 (SeenThis.kr)
스타트업 커뮤니티 씬디스 (SeenThis.kr)

2024年5月20日

[React Hook] useState ReactのuseStateフックが再レンダリング時にコンポーネント全体を再レンダリングする理由、値の保持方法、そして内部実装構造の詳細な説明を記載しています。 ReactFiberHooks.jsコード分析を通してフックの動作原理を理解し、mountState、updateState、rerenderState関数の役割を把握することができます。
Sunrabbit
Sunrabbit
Sunrabbit
Sunrabbit

2024年3月14日

[非専攻、開発者として生き残る] 14. 新卒開発者がよく聞かれる技術面接内容まとめ 新卒開発者向けの技術面接準備ガイドです。メインメモリ領域、データ構造、RDBMSとNoSQL、手続き型とオブジェクト指向、 オーバーライドとオーバーロード、ページ置換アルゴリズム、プロセスとスレッド、OSI 7層、TCPとUDPなど、面接でよく登場する概念を 説明します。
투잡뛰는 개발 노동자
투잡뛰는 개발 노동자
투잡뛰는 개발 노동자
투잡뛰는 개발 노동자

2024年4月3日