JavaのリフレクションAPIでコンストラクタ取得、インスタンス生成

JavaのリフレクションAPIでコンストラクタ取得、インスタンス生成を試してみたメモです。

前回に引き続き、JavaのリフレクションAPIを利用して、
コンストラクタ取得、インスタンス生成を試してみました。

java.lang.reflect.Constructor

JavaのリフレクションAPIを利用することで、メタデータにアクセスできます。
java.lang.reflect.Constructorクラスを利用してコンストラクタ取得、インスタンス生成を試してみたいと思います。

テスト用クラス

Mavenプロジェクトを作成し、pom.xmljunitとhamcrestだけdependencyに追加しました。

pom.xml

    <dependencies>
        <dependency>
            <groupId>org.hamcrest</groupId>
            <artifactId>hamcrest-all</artifactId>
            <version>1.3</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit-dep</artifactId>
            <version>4.10</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

テスト対象のクラスは下記のようなクラスを作りました。

ReflectConstructorExample.java

package reflect;

public class ReflectConstructorExample {
    private String name;
    private int age;
    private int num;

    public ReflectConstructorExample() {

    }

    protected ReflectConstructorExample(String name) {
        this.name = name;
    }

    ReflectConstructorExample(String name, int age) {
        this.name = name;
        this.age = age;
    }

    private ReflectConstructorExample(int num) {
        this.num = num;
    }
}

public、protected、修飾子なし、private
のアクセス修飾子でそれぞれコンストラクタを作成しました。

Constructorオブジェクト

Constructorオブジェクトを取得するためのメソッドは下記です。
すべてClassクラスのメソッドです。

メソッド 戻り値 取得可能なアクセス修飾子
getConstructor Constructor public
getConstructors Constructor[] public
getDeclaredConstructor Constructor すべて
getDeclaredConstructors Constructor[] すべて
getConstructor()

getConstructor()では、指定したクラスのコンストラクタが取得できます。
取得できるのはpublicコンストラクタのみです。
引数にはコンストラクタへの引数の型を指定します。

    // 引数なしのコンストラクタ
    Constructor cons = ReflectConstructorExample.class.getConstructor();

    // Stringを引数に取るコンストラクタ
    Constructor cons = ReflectConstructorExample.class.getConstructor(String.class);

テストコード。

    public static class getConstructorの確認 {
        @Test
        public void getConstructorでpublicコンストラクタが取得できること() throws Exception {
            Constructor cons = ReflectConstructorExample.class.getConstructor();
            int mod = cons.getModifiers();
            assertThat(mod, is(Modifier.PUBLIC));
        }

        @Test(expected = NoSuchMethodException.class)
        public void getConstructorでprotectedコンストラクタが取得できないこと() throws Exception {
            Constructor cons = ReflectConstructorExample.class.getConstructor(String.class);
        }

        @Test(expected = NoSuchMethodException.class)
        public void getConstructorでdefaultコンストラクタが取得できないこと() throws Exception {
            Constructor cons = ReflectConstructorExample.class.getConstructor(String.class, String.class);
        }

        @Test(expected = NoSuchMethodException.class)
        public void getConstructorでprivateコンストラクタが取得できないこと() throws Exception {
            Constructor cons = ReflectConstructorExample.class.getConstructor(int.class);
        }
    }
getConstructors()

getConstructors()では、指定したクラスのコンストラクタがConstructorクラスの配列で取得できます。
取得できるのはpublicコンストラクタのみです。

テストコード。

    public static class getConstructorsの確認 {
        @Test
        public void getConstructorsでコンストラクタオブジェクトが取得できること() throws Exception {
            Class clazz = ReflectConstructorExample.class;
            Constructor[] cons = clazz.getConstructors();
            Constructor[] expected = {
                    clazz.getConstructor()
            };
            assertThat(cons, is(arrayContainingInAnyOrder(expected)));
        }
    }
getDeclaredConstructor()

getDeclaredConstructor()では、getConstructor()と同様にコンストラクタが取得できますが、
getConstructor()と異なり、すべてのアクセス修飾子(public、protected、デフォルト、private)のコンストラクタが取得できます。

    // publicコンストラクタ
    Constructor cons = ReflectConstructorExample.class.getDeclaredConstructor();

    // protectedコンストラクタ
    Constructor cons = ReflectConstructorExample.class.getDeclaredConstructor(String.class);

    // defaultコンストラクタ
    Constructor cons = ReflectConstructorExample.class.getDeclaredConstructor(String.class, int.class);

    // privateコンストラクタ
    Constructor cons = ReflectConstructorExample.class.getDeclaredConstructor(int.class);

テストコード。

    public static class getDeclaredConstructorの確認 {
        @Test
        public void getDeclaredConstructorでpublicコンストラクタが取得できること() throws Exception {
            Constructor cons = ReflectConstructorExample.class.getDeclaredConstructor();
            int mod = cons.getModifiers();
            assertThat(mod, is(Modifier.PUBLIC));
        }

        @Test
        public void getDeclaredConstructorでprotectedコンストラクタが取得できること() throws Exception {
            Constructor cons = ReflectConstructorExample.class.getDeclaredConstructor(String.class);
            int mod = cons.getModifiers();
            assertThat(mod, is(Modifier.PROTECTED));
        }

        @Test
        public void getDeclaredConstructorでdefaultコンストラクタが取得できること() throws Exception {
            Constructor cons = ReflectConstructorExample.class.getDeclaredConstructor(String.class, int.class);
            int mod = cons.getModifiers();
            assertThat(mod, is(0));
        }

        @Test
        public void getDeclaredConstructorでprivateコンストラクタが取得できること() throws Exception {
            Constructor cons = ReflectConstructorExample.class.getDeclaredConstructor(int.class);
            int mod = cons.getModifiers();
            assertThat(mod, is(Modifier.PRIVATE));
        }
    }
getDeclaredConstructors()

getDeclaredConstructors()では、getConstructors()同様にConstructorクラスの配列で取得できますが、
getConstructors()と異なり、すべてのアクセス修飾子(public、protected、デフォルト、private)のコンストラクタが取得できます。

テストコード。

    public static class getDeclaredConstructorsの確認 {
        @Test
        public void getDeclaredConstructorsでコンストラクタオブジェクトが取得できること() throws Exception {
            Class clazz = ReflectConstructorExample.class;
            Constructor[] cons = clazz.getDeclaredConstructors();
            Constructor[] expected = {
                    clazz.getDeclaredConstructor(),
                    clazz.getDeclaredConstructor(String.class),
                    clazz.getDeclaredConstructor(String.class, int.class),
                    clazz.getDeclaredConstructor(int.class)
            };
            assertThat(cons, is(arrayContainingInAnyOrder(expected)));
        }
    }

Constructorクラス

コンストラクタ情報取得

Constructorクラスのメソッドを利用してコンストラクタの情報が取得できます。

    Constructor cons = ReflectConstructorExample.class.getConstructor();
    // コンストラクタを宣言するクラスを取得
    Class clazz = cons.getDeclaringClass();

    // コンストラクタの名前取得
    String name = cons.getName();

テストコード。

    public static class Constructorクラスでコンストラクタ情報取得 {
        @Test
        public void getDeclaringClassでコンストラクタを宣言するクラスが取得できること() throws Exception {
            Constructor cons = ReflectConstructorExample.class.getConstructor();
            Class clazz = cons.getDeclaringClass();
            assertThat(clazz, is(equalTo(ReflectConstructorExample.class)));
        }

        @Test
        public void getNameでコンストラクタの名前が取得できること() throws Exception {
            Constructor cons = ReflectConstructorExample.class.getConstructor();
            String name = cons.getName();
            assertThat(name, is("reflect.ReflectConstructorExample"));
        }
    }
コンストラクタを利用したインスタンス生成

ConstructorクラスのnewInstance()メソッドで、インスタンスを生成できます。
引数にはコンストラクタの要求する引数を指定します。

    Class<ReflectConstructorExample> clazz = ReflectConstructorExample.class;

    // 引数なしのコンストラクタでインスタンス生成
    ReflectConstructorExample ref = clazz.getConstructor().newInstance();

    // Stringを引数に取るコンストラクタでインスタンス生成
    ReflectConstructorExample ref = clazz.getDeclaredConstructor(String.class).newInstance("pro");

テストコード。

    public static class コンストラクタを利用したインスタンス生成確認 {
        @Test
        public void publicコンストラクタでのインスタンス生成() throws Exception {
            Class<ReflectConstructorExample> clazz = ReflectConstructorExample.class;
            ReflectConstructorExample ref = clazz.getConstructor().newInstance();
            assertThat(ref, is(instanceOf(ReflectConstructorExample.class)));
        }

        @Test
        public void protectedコンストラクタでのインスタンス生成() throws Exception {
            Class<ReflectConstructorExample> clazz = ReflectConstructorExample.class;
            ReflectConstructorExample ref = clazz.getDeclaredConstructor(String.class).newInstance("pro");
            assertThat(ref, is(instanceOf(ReflectConstructorExample.class)));
        }

        @Test
        public void defaultコンストラクタでのインスタンス生成() throws Exception {
            Class<ReflectConstructorExample> clazz = ReflectConstructorExample.class;
            ReflectConstructorExample ref = clazz.getDeclaredConstructor(String.class, int.class).newInstance("def", 19);
            assertThat(ref, is(instanceOf(ReflectConstructorExample.class)));
        }

        @Test(expected = IllegalAccessException.class)
        public void privateコンストラクタでのインスタンス生成ができないこと() throws Exception {
            Class<ReflectConstructorExample> clazz = ReflectConstructorExample.class;
            ReflectConstructorExample ref = clazz.getDeclaredConstructor(int.class).newInstance(20);
            assertThat(ref, is(instanceOf(ReflectConstructorExample.class)));
        }
    }

テストコード

今回のテストコードの全体です。

ReflectConstructorExampleTest.java

package reflect;

import org.junit.Test;
import org.junit.experimental.runners.Enclosed;
import org.junit.runner.RunWith;

import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;

import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.Matchers.arrayContainingInAnyOrder;
import static org.junit.Assert.*;

/**
 * Created by pppurple on 2016/07/26.
 */
@RunWith(Enclosed.class)
public class ReflectConstructorExampleTest {
    public static class getConstructorの確認 {
        @Test
        public void getConstructorでpublicコンストラクタが取得できること() throws Exception {
            Constructor cons = ReflectConstructorExample.class.getConstructor();
            int mod = cons.getModifiers();
            assertThat(mod, is(Modifier.PUBLIC));
        }

        @Test(expected = NoSuchMethodException.class)
        public void getConstructorでprotectedコンストラクタが取得できないこと() throws Exception {
            Constructor cons = ReflectConstructorExample.class.getConstructor(String.class);
        }

        @Test(expected = NoSuchMethodException.class)
        public void getConstructorでdefaultコンストラクタが取得できないこと() throws Exception {
            Constructor cons = ReflectConstructorExample.class.getConstructor(String.class, String.class);
        }

        @Test(expected = NoSuchMethodException.class)
        public void getConstructorでprivateコンストラクタが取得できないこと() throws Exception {
            Constructor cons = ReflectConstructorExample.class.getConstructor(int.class);
        }
    }

    public static class getConstructorsの確認 {
        @Test
        public void getConstructorsでコンストラクタオブジェクトが取得できること() throws Exception {
            Class clazz = ReflectConstructorExample.class;
            Constructor[] cons = clazz.getConstructors();
            Constructor[] expected = {
                    clazz.getConstructor()
            };
            assertThat(cons, is(arrayContainingInAnyOrder(expected)));
        }
    }

    public static class getDeclaredConstructorの確認 {
        @Test
        public void getDeclaredConstructorでpublicコンストラクタが取得できること() throws Exception {
            Constructor cons = ReflectConstructorExample.class.getDeclaredConstructor();
            int mod = cons.getModifiers();
            assertThat(mod, is(Modifier.PUBLIC));
        }

        @Test
        public void getDeclaredConstructorでprotectedコンストラクタが取得できること() throws Exception {
            Constructor cons = ReflectConstructorExample.class.getDeclaredConstructor(String.class);
            int mod = cons.getModifiers();
            assertThat(mod, is(Modifier.PROTECTED));
        }

        @Test
        public void getDeclaredConstructorでdefaultコンストラクタが取得できること() throws Exception {
            Constructor cons = ReflectConstructorExample.class.getDeclaredConstructor(String.class, int.class);
            int mod = cons.getModifiers();
            assertThat(mod, is(0));
        }

        @Test
        public void getDeclaredConstructorでprivateコンストラクタが取得できること() throws Exception {
            Constructor cons = ReflectConstructorExample.class.getDeclaredConstructor(int.class);
            int mod = cons.getModifiers();
            assertThat(mod, is(Modifier.PRIVATE));
        }
    }

    public static class getDeclaredConstructorsの確認 {
        @Test
        public void getDeclaredConstructorsでコンストラクタオブジェクトが取得できること() throws Exception {
            Class clazz = ReflectConstructorExample.class;
            Constructor[] cons = clazz.getDeclaredConstructors();
            Constructor[] expected = {
                    clazz.getDeclaredConstructor(),
                    clazz.getDeclaredConstructor(String.class),
                    clazz.getDeclaredConstructor(String.class, int.class),
                    clazz.getDeclaredConstructor(int.class)
            };
            assertThat(cons, is(arrayContainingInAnyOrder(expected)));
        }
    }

    public static class Constructorクラスでコンストラクタ情報取得 {
        @Test
        public void getDeclaringClassでコンストラクタを宣言するクラスが取得できること() throws Exception {
            Constructor cons = ReflectConstructorExample.class.getConstructor();
            Class clazz = cons.getDeclaringClass();
            assertThat(clazz, is(equalTo(ReflectConstructorExample.class)));
        }

        @Test
        public void getNameでコンストラクタの名前が取得できること() throws Exception {
            Constructor cons = ReflectConstructorExample.class.getConstructor();
            String name = cons.getName();
            assertThat(name, is("reflect.ReflectConstructorExample"));
        }
    }

    public static class コンストラクタを利用したインスタンス生成確認 {
        @Test
        public void publicコンストラクタでのインスタンス生成() throws Exception {
            Class<ReflectConstructorExample> clazz = ReflectConstructorExample.class;
            ReflectConstructorExample ref = clazz.getConstructor().newInstance();
            assertThat(ref, is(instanceOf(ReflectConstructorExample.class)));
        }

        @Test
        public void protectedコンストラクタでのインスタンス生成() throws Exception {
            Class<ReflectConstructorExample> clazz = ReflectConstructorExample.class;
            ReflectConstructorExample ref = clazz.getDeclaredConstructor(String.class).newInstance("pro");
            assertThat(ref, is(instanceOf(ReflectConstructorExample.class)));
        }

        @Test
        public void defaultコンストラクタでのインスタンス生成() throws Exception {
            Class<ReflectConstructorExample> clazz = ReflectConstructorExample.class;
            ReflectConstructorExample ref = clazz.getDeclaredConstructor(String.class, int.class).newInstance("def", 19);
            assertThat(ref, is(instanceOf(ReflectConstructorExample.class)));
        }

        @Test(expected = IllegalAccessException.class)
        public void privateコンストラクタでのインスタンス生成ができないこと() throws Exception {
            Class<ReflectConstructorExample> clazz = ReflectConstructorExample.class;
            ReflectConstructorExample ref = clazz.getDeclaredConstructor(int.class).newInstance(20);
            assertThat(ref, is(instanceOf(ReflectConstructorExample.class)));
        }
    }
}

ソースはあげておきました。
github.com

終わり。