Javaリフレクションの基本と応用

一、Classオブジェクトを取得する3つの方法:

方法1: ObjectクラスのgetClass()メソッドを利用する

Person person = new Person();
Class classObj = person.getClass();

方法2: クラス名.class構文を使用する

Class classObj2 = Person.class;

方法3: ClassクラスのforNameメソッドを利用する(クラス名を文字列として渡す)

Class classObj3 = Class.forName("Person");

注意:第三の方法と前の二つの違い

前の二つの方法ではPerson型を明確に指定する必要があります。

後者はこの型の文字列を指定するだけでよいです。この拡張性がより強いです。クラスを知らなくても、文字列を提供するだけで、設定ファイルに従ってロードできます。

以下では、123を追加する際にエラーが発生する理由について説明します。原因は、ジェネリック制約の存在によるものです。int型を格納するには、ジェネリックの型消去が必要です。

public class ReflectionDemo {

    public static void main(String[] args) throws Exception {
        List<String> list = new ArrayList<>();
        list.add("abc");
        
        // ジェネリック制約により直接追加はできない
        // list.add(123); // コンパイルエラー
        
        // ジェネリックの型消去を利用
        Class<?> listClass = list.getClass();
        Method addMethod = listClass.getMethod("add", Object.class);
        addMethod.invoke(list, 123);
        
        for(Object item : list) {
            System.out.println(item);
        }
    }
}

設定ファイルによるリフレクション(重要):

3つのコンストラクタをそれぞれ作成します:

public class Student {
    public void study() {
        System.out.println("学生が勉強しています");
    }
}

public class Worker {
    public void work() {
        System.out.println("労働者が働いています");
    }
}

public class Chef {
    public void cook() {
        System.out.println("シェフが料理を作っています");
    }
}

設定ファイル:

className=com.example.reflection.Student
methodName=study
#className=com.example.reflection.Worker
#methodName=work
#className=com.example.reflection.Chef
#methodName=cook
public class ConfigReflectionDemo {

    public static void main(String[] args) throws Exception {
        // Propertiesオブジェクトを作成
        Properties props = new Properties();
        // データソースを指定
        FileInputStream fis = new FileInputStream("src/com/example/reflection/config.properties");
        // PropertiesファイルのデータをPropertiesオブジェクトに読み込む
        props.load(fis);
        // 完全修飾クラス名を取得
        String className = props.getProperty("className");
        // メソッド名を取得
        String methodName = props.getProperty("methodName");
        // Classオブジェクトを取得
        Class<?> clazz = Class.forName(className);
        // メソッドオブジェクトを取得
        Method method = clazz.getMethod(methodName);
        // オブジェクトを動的に生成
        Object instance = clazz.getDeclaredConstructor().newInstance();
        // メソッドを実行
        method.invoke(instance);
    }
}

このように、どのクラスを呼び出すかは設定ファイルを変更するだけで済みます。

設定ファイルを変更後:

#className=com.example.reflection.Student
#methodName=study
#className=com.example.reflection.Worker
#methodName=work
className=com.example.reflection.Chef
methodName=cook

実行結果は以下の通りです:

タグ: Java リフレクション ジェネリクス プロパティファイル

6月2日 17:37 投稿