マイペースなプログラミング日記

DTMやプログラミングにお熱なd-kamiがマイペースに書くブログ

リフレクションを使ってコンストラクタを呼び出してみる

大学院の研究でJavaを使っていて、リフレクションを使いたいなと思ったので、リフレクションを使った簡単なプログラムを作ってみることにした。リフレクションでコンストラクタを呼び出すクラスはPassedFilterとNotPassedFilterというinterfaceのFilterを実装したもの。実際にはFilterを実装したAbstractFilterを継承したクラス。Mainを実行する前に、これらのFilterをコンパイルしておかないといけない。Mainをコンパイルしても、MainとinterfaceのFilterしかコンパイルされないので注意。とりあえずソース

Main.java

import java.lang.reflect.Constructor;

public class Main{
    public static void main(String[] args) throws Exception{
        printFilter(newFilter("PassedFilter", "UserName"));
        System.out.println();
        printFilter(newFilter("NotPassedFilter", "Password"));
    }

    //フィルタを作成する
    private static Filter newFilter(String className, String name) throws Exception{
        Class<? extends Filter> filterClass = (Class<? extends Filter>)Class.forName(className);
        Constructor<? extends Filter> filterConstructor = filterClass.getConstructor(String.class);
        return filterConstructor.newInstance(name);
    }

    //フィルタの内容を表示する
    private static void printFilter(Filter filter){
        System.out.println(filter.getName());
        System.out.println(filter.getType());
        System.out.println(filter.isPassed("parameter"));
    }
}

Filter.java

public interface Filter{
    String getName();
    String getType();

    boolean isPassed(String parameter);
}

AbstractFilter.java

public abstract class AbstractFilter implements Filter{
    protected String name;
    protected String type;

    protected AbstractFilter(String name){
        this.name = name;
        this.type = this.getClass().getName();
    }

    public String getName(){
       return this.name;
    }

    public String getType(){
        return this.type;
    }

    public abstract boolean isPassed(String parameter);
}

PassedFilter.java

public class PassedFilter extends AbstractFilter{
    public PassedFilter(String name){
        super(name);
    }

    @Override
    public boolean isPassed(String parameter){
        return true;
    }
}

NotPassedFilter.java

public class NotPassedFilter extends AbstractFilter{
    public NotPassedFilter(String name){
        super(name);
    }

    @Override
    public boolean isPassed(String parameter){
        return false;
    }
}

このプログラムには問題点がある、Main.java

Class<? extends Filter> filterClass = (Class<? extends Filter>)Class.forName(className);

の部分で、警告がでる。


Main.java:11: 警告:[unchecked] 無検査キャストです
検出値 : java.lang.Class
期待値 : java.lang.Class
Class filterClass = (Class)Class.forName(className);
^
警告 1 個
これはClass.forName()がClassを返してくるためで、この警告を回避するには以下のようにすればいい

Main2.java

import java.lang.reflect.Constructor;

public class Main2{
    public static void main(String[] args) throws Exception{
        printFilter(newFilter("PassedFilter", "UserName"));
        System.out.println();
        printFilter(newFilter("NotPassedFilter", "Password"));
    }

    private static Filter newFilter(String className, String name) throws Exception{
        Class<?> filterClass = Class.forName(className);
        Constructor<?> filterConstructor = filterClass.getConstructor(String.class);
        return (Filter)filterConstructor.newInstance(name);
    }

    private static void printFilter(Filter filter){
        System.out.println(filter.getName());
        System.out.println(filter.getType());
        System.out.println(filter.isPassed("parameter"));
    }
}

Constructor#newInstance時にキャストすれば警告がでずにコンパイルできる。さっそく研究に取り入れるぞ!