CodeGym /コース /JAVA 25 SELF /クラス、フィールド、メソッドに関する情報の取得

クラス、フィールド、メソッドに関する情報の取得

JAVA 25 SELF
レベル 62, レッスン 1
使用可能

1. フィールド情報の取得

getFields() と getDeclaredFields() の違い

Java の各クラスにはフィールド(fields)があります。これはクラス内で宣言された変数です。リフレクションを使うと、それらの名前、型、アクセス修飾子(public/private)を調べたり、実行時にアクセスしたりできます。エントリポイントは Class<?> オブジェクトです。

フィールド操作に使う Class の主なメソッド:

メソッド 返すもの
getFields()
クラス、その親クラス、インターフェースのすべての public フィールドの配列
getDeclaredFields()
このクラスで宣言されているすべてのフィールドの配列

たとえば、getFields() は展示室(public)だけの見学、getDeclaredFields() は裏方の部屋(private、protected、package-private)まで含むツアー、というイメージです。

例: クラスの全フィールドを出力

次のクラスがあるとします:

public class Person {
    public String name;
    private int age;
    protected String email;
}

フィールド情報を取得します:

import java.lang.reflect.Field;

Class<?> clazz = Person.class;

// すべての public フィールド(継承分を含む)
System.out.println("Public fields:");
for (Field field : clazz.getFields()) {
    System.out.println(field.getName() + " : " + field.getType().getSimpleName());
}

// 宣言されているすべてのフィールド(private を含む、自クラスのみ)
System.out.println("\nDeclared fields:");
for (Field field : clazz.getDeclaredFields()) {
    System.out.println(field.getName() + " : " + field.getType().getSimpleName());
}

結果:

Public fields:
name : String

Declared fields:
name : String
age : int
email : String

フィールドの修飾子を取得するには?

各フィールド(Field)には修飾子(public/private/protected、static、final など)があります。getModifiers() で取得し、Modifier で文字列に変換できます:

import java.lang.reflect.Modifier;

for (Field field : clazz.getDeclaredFields()) {
    int mods = field.getModifiers();
    System.out.println(field.getName() + " : " + Modifier.toString(mods));
}

2. メソッド情報の取得

getMethods() と getDeclaredMethods()

メソッドはオブジェクトが実行できる処理です。リフレクションを使えば、クラスに存在するメソッド、そのパラメータ、戻り値の型、修飾子、アノテーションを調べられます。

メソッド 返すもの
getMethods()
クラスおよびその親(Object を含む)のすべての public メソッド
getDeclaredMethods()
このクラスで宣言されているすべてのメソッド(private を含む)

例: クラスのすべてのメソッドを出力

import java.lang.reflect.Method;

System.out.println("Public methods:");
for (Method method : clazz.getMethods()) {
    System.out.println(method.getName());
}

System.out.println("\nDeclared methods:");
for (Method method : clazz.getDeclaredMethods()) {
    System.out.println(method.getName());
}

結果(Person の場合):

Public methods:
getClass
hashCode
equals
toString
notify
notifyAll
wait
wait
wait

Declared methods:
(何も表示されません。Person に独自のメソッドが宣言されていない場合)

Person にメソッドを追加します:

public class Person {
    public String name;
    private int age;
    protected String email;

    public void sayHello() {
        System.out.println("Hi!");
    }
}

これで getDeclaredMethods() にもこのメソッドが表示されます。

メソッドのパラメータと戻り値の型を知るには?

for (Method method : clazz.getDeclaredMethods()) {
    System.out.print(Modifier.toString(method.getModifiers()) + " ");
    System.out.print(method.getReturnType().getSimpleName() + " ");
    System.out.print(method.getName() + "(");
    Class<?>[] params = method.getParameterTypes();
    for (int i = 0; i < params.length; i++) {
        System.out.print(params[i].getSimpleName());
        if (i < params.length - 1) System.out.print(", ");
    }
    System.out.println(");");
}

出力:

public void sayHello();

3. コンストラクタ情報の取得

コンストラクタは、オブジェクトを生成するための特別なメソッドです。

メソッド 返すもの
getConstructors()
public コンストラクタのすべて
getDeclaredConstructors()
クラスで宣言されているすべてのコンストラクタ

例: クラスのすべてのコンストラクタを出力

import java.lang.reflect.Constructor;

System.out.println("Constructors:");
for (Constructor<?> constructor : clazz.getDeclaredConstructors()) {
    System.out.print(clazz.getSimpleName() + "(");
    Class<?>[] params = constructor.getParameterTypes();
    for (int i = 0; i < params.length; i++) {
        System.out.print(params[i].getSimpleName());
        if (i < params.length - 1) System.out.print(", ");
    }
    System.out.println(");");
}

クラスにデフォルトコンストラクタしかない場合でも出力されます。

4. アノテーション: クラス、メソッド、フィールドに何が付いているかを調べる

アノテーションは、クラス、メソッド、フィールド、パラメータに付けられる特別なタグです。リフレクションを使えば、その要素にどのアノテーションが付与されているかを取得できます。

アノテーションの取得

  • クラス用: clazz.getAnnotations()
  • メソッド用: method.getAnnotations()
  • フィールド用: field.getAnnotations()

例: @Deprecated アノテーションの有無を確認

for (Method method : clazz.getDeclaredMethods()) {
    if (method.isAnnotationPresent(Deprecated.class)) {
        System.out.println(method.getName() + " is @Deprecated");
    }
}

例: クラスのすべてのアノテーションを出力

for (var annotation : clazz.getAnnotations()) {
    System.out.println(annotation);
}

5. 実践: クラス構造を解析するミニプログラム

ここまでをまとめて、クラス名からその構造(フィールド、メソッド、コンストラクタ、アノテーション)を出力する小さなユーティリティを書いてみましょう。

コード例: ClassInspector

import java.lang.reflect.*;
import java.util.Scanner;

public class ClassInspector {
    public static void main(String[] args) throws Exception {
        Scanner scanner = new Scanner(System.in);
        System.out.print("クラスの完全修飾名を入力してください(例: java.util.ArrayList): ");
        String className = scanner.nextLine();

        Class<?> clazz = Class.forName(className);

        System.out.println("\n== クラス: " + clazz.getName() + " ==");

        // クラスのアノテーション
        System.out.println("アノテーション:");
        for (Annotation annotation : clazz.getAnnotations()) {
            System.out.println("  " + annotation);
        }

        // フィールド
        System.out.println("\nフィールド:");
        for (Field field : clazz.getDeclaredFields()) {
            System.out.println("  " + Modifier.toString(field.getModifiers())
                    + " " + field.getType().getSimpleName()
                    + " " + field.getName());
        }

        // メソッド
        System.out.println("\nメソッド:");
        for (Method method : clazz.getDeclaredMethods()) {
            System.out.print("  " + Modifier.toString(method.getModifiers())
                    + " " + method.getReturnType().getSimpleName()
                    + " " + method.getName() + "(");
            Class<?>[] params = method.getParameterTypes();
            for (int i = 0; i < params.length; i++) {
                System.out.print(params[i].getSimpleName());
                if (i < params.length - 1) System.out.print(", ");
            }
            System.out.println(");");
        }

        // コンストラクタ
        System.out.println("\nコンストラクタ:");
        for (Constructor<?> constructor : clazz.getDeclaredConstructors()) {
            System.out.print("  " + Modifier.toString(constructor.getModifiers())
                    + " " + clazz.getSimpleName() + "(");
            Class<?>[] params = constructor.getParameterTypes();
            for (int i = 0; i < params.length; i++) {
                System.out.print(params[i].getSimpleName());
                if (i < params.length - 1) System.out.print(", ");
            }
            System.out.println(");");
        }
    }
}

どのように動く?

  • ユーザーがクラスの完全修飾名を入力します(例: "java.util.ArrayList" や自分のクラス)。
  • プログラムがクラスを動的に読み込み、そのアノテーション、フィールド、メソッド、コンストラクタを出力します。
  • JDK の標準クラスで試してみてください――内部にどれほど多くの情報が隠れているかがわかります!

6. 役立つポイントと可視化

ビジュアル図: リフレクションでクラスから何がわかるか

graph TD
    A[Class<?>] --> B["getFields/getDeclaredFields"]
    A --> C[getMethods/getDeclaredMethods]
    A --> D[getConstructors/getDeclaredConstructors]
    A --> E[getAnnotations]
    B --> F[Field: 型、名前、修飾子]
    C --> G[Method: 戻り値の型、パラメータ]
    D --> H[Constructor: パラメータ]
    E --> I["Annotation[]"]

表: どこから情報を取得するか

知りたい情報 リフレクションでの取得方法
すべての public フィールド
clazz.getFields()
宣言されているすべてのフィールド
clazz.getDeclaredFields()
すべての public メソッド
clazz.getMethods()
宣言されているすべてのメソッド
clazz.getDeclaredMethods()
すべての public コンストラクタ
clazz.getConstructors()
宣言されているすべてのコンストラクタ
clazz.getDeclaredConstructors()
クラスのアノテーション
clazz.getAnnotations()
メソッド/フィールドのアノテーション
method.getAnnotations(), field.getAnnotations()
修飾子
Modifier.toString(field.getModifiers())

7. リフレクション使用時の典型的なエラー

エラー1: getFields() と getDeclaredFields() を取り違える。
private フィールドを探す場合は getDeclaredFields() を使いましょう。getFields() は使いません。前者はそのクラスで宣言されたすべてのフィールドを返し、後者は public のみ(かつ継承分も!)を返します。

エラー2: チェック例外を処理しない。
多くのリフレクション API は例外を送出します(例: ClassNotFoundException や SecurityException)。必ずキャッチして処理するか、メソッドシグネチャで宣言してください。

エラー3: アクセス修飾子を考慮しない。
private フィールドやメソッドへのアクセスは、setAccessible(true) を呼び出した後にのみ可能です。そうしないと IllegalAccessException になります。例:

Field field = clazz.getDeclaredField("age");
field.setAccessible(true); // private フィールドへのアクセスを有効化する
int value = (int) field.get(person);

エラー4: 自分のメソッド/フィールドだけが見えると思い込む。
getMethods() と getFields() は、現在のクラスだけでなく、すべての親クラス(Object を含む)の public メンバーも返します。自分で書いたものだけが見えると期待していると驚くかもしれません。

エラー5: アノテーションの有無を正しく確認しない。
特定のアノテーションを確認するには isAnnotationPresent() を使いましょう。不要にアノテーション配列を手作業で走査する必要はありません。

1
タスク
JAVA 25 SELF, レベル 62, レッスン 1
ロック未解除
秘密デバイスの監査 🕵️
秘密デバイスの監査 🕵️
1
タスク
JAVA 25 SELF, レベル 62, レッスン 1
ロック未解除
古代の儀式のカタログ化 📜
古代の儀式のカタログ化 📜
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION