大学院の研究で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);
の部分で、警告がでる。
これはClass.forName()がClassを返してくるためで、この警告を回避するには以下のようにすればいい
Main.java:11: 警告:[unchecked] 無検査キャストです
検出値 : java.lang.Class
期待値 : java.lang.Class
Class filterClass = (Class)Class.forName(className);
^
警告 1 個
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時にキャストすれば警告がでずにコンパイルできる。さっそく研究に取り入れるぞ!