Reflection
C#
public class Test
{
public string Method(string name)
{
return "hello " + name;
}
}
//利用側
Type t = Type.GetType("com.Test");
或いは Type t = typeof(Test);
object obj = Assembly.GetAssembly(t).CreateInstance("com.Test");
或いは object obj = Activator.CreateInstance(t);
MethodInfo mi = t.GetMethod("method");
string s = mi.Invoke(obj, new object[] { "Mike" }).ToString();
string s = mi.Invoke(obj, null).ToString(); //引数がない場合
★実用サンプル
<configuration>
<appSettings>
<add key="DBHelper" value="xxx.SQLServerHelper"/> 具体的なDBMSを選択
<!--<add key="DBHelper" value="xxx.OracleHelper"/>-->
</appSettings>
</configuration>
private IDBHelper dbHelper = GetDBHelper();
public static IDBHelper GetDBHelper()
{
string class = ConfigurationSettings.AppSettings["DBHelper"].ToString();
Assembly assembly = Assembly.Load("xxx");
return assembly.CreateInstance(class) as IDBHelper;
}
★すべてのメソッドを分析
Type[] types = assembly.GetTypes();
foreach (Type type in types)
{
MethodInfo[] methods = type.GetMethods();
foreach (MethodInfo method in methods)
{
method.Invoke(null, null);
}
}
Java
public class Test {
public String method(String name) {
return "hello " + name;
}
}
//利用側
Class<?> c = Class.forName("com.Test");
Object obj = c.newInstance();
String className = obj.getClass().getName();
// getMethod(メソッド名, 引数)
Method mh = c.getMethod("method", String.class);
String s = mh.invoke(obj, new Object[]{ "Mike" }).toString();
IA a = (IA)Class.forName("package.A").newInstance();
同じく
IA a = new A();
// 参照型
Class c = "".getClass();
Class c = Class.forName("java.lang.String");
Class c = String.class;
// 基本型
Class c = Integer.TYPE;
Class c = int.class;
属性を呼び出す
Class<?> c = User.class;
Object obj = c.newInstance();
Field f = c.getDeclaredField("name");
f.setAccessible(true);
f.set(obj, "Andy");
System.out.println(f.get(obj));
コンストラクタを呼び出す
Class<?> c = Class.forName("package.User");
Constructor<?> con = c.getConstructor(); // 引数なし
Object obj = con.newInstance();
Constructor<?> con = c.getConstructor(int.class, String.class); // 引数あり
Object obj = con.newInstance(1001, "Andy");
メソッドを呼び出す
Class<?> c = Class.forName("package.User");
Object obj = c.newInstance();
Method m = c.getMethod("setName", String.class);
m.invoke(obj, "Andy");
Method m = c.getMethod("setId", int.class);
m.invoke(obj, 1001);
★MetaClass クラスのクラス
・コンストラクタなし
・基本型も表現できる int.class
・Singlton
String.class.equals(new String().getClass()) true
"ab".getClass().equals(String.class) true
ArrayList.class.equals(new ArrayList<String>().getClass())) true
MetaClass取得方法
・class属性 Class<?> c = String.class
・getClassメソッド Class<?> c = new String().getClass()
・forNameメソッド Class<?> c = Class.forName("java.lang.String") 例外:ClassNotFoundException
forNameメソッドが実行される際に、staticブロックも実行されるのは一般
public class Driver extends ...{
static{
try{
java.sql.DriverManager.registerDriver(new Driver());
}catch(SQLException e){
...
}
}
}
Class.forName("com.mysql.jdbc.Driver");
★getDeclaredXXXとgetXXX
class Test{
void method(){}
}
Method m1 = Test.class.getDeclaredMethod("method"); 〇
Method m2 = Test.class.getMethod("method"); × NoSuchMethodException
getDeclaredMethod 自分自身のすべてメソッド(public + privateなど)
getMethod すべてpublicメソッド(親クラスも含む)
getDeclaredConstructorsとgetConstructorsも同様
getDeclaredFieldsとgetFieldsも同様
Constructor<?>[] cons = c.getConstructors();
System.out.println(Arrays.toString(cons));
Class<?>[] ins = c.getInterfaces();
System.out.println(Arrays.toString(ins));
Class<?> super = c.getSuperclass();
System.out.println(super);
Method[] ms = c.getMethods();
System.out.println(Arrays.toString(ms));
public <T> void printFields(T t) {
if (t == null) {
return;
}
// getFieldsは親クラスのフィールドも含む
Field[] fields = t.getClass().getDeclaredFields();
try {
for (Field field : fields) {
if ("serialVersionID".equals(field.getName())) {
continue;
}
}
String name = field.getName();
String value = field.get(t);
...
} catch (IllegalArgumentException | IllegalAccessException e) {
return;
}
}
★Accessibleの作用
※trueに設定すれば、セキュリティチェックを避けて、効率よくなる一方、privateメソッドもアクセスできる
Method method = ...;
if(!method.isAccessible()){
method.setAccessible(true);
}
method.invoke(obj, args);
class Person {
public String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
...
}
Person p = new Person("Andy", 29);
Class<?> c = p.getClass();
Field f1 = c.getField("name"); //public
String name = (String)f1.get(p);
Field f2 = c.getDeclaredField("age"); //private
f2.setAccessible(true); //privateのため
int age = (int)f2.get(p);
f2.set(p, 30); //変更
Method m1 = c.getMethod("instanceMethod", int.class);
m1.invoke(p, 10);
Method m2 = c.getMethod("staticMethod", String.class);
m2.invoke(null, "XXX");
★配列の生成
String[] strs = (String[]) Array.newInstance(String.class, 6);
int[][] ints = (int[][]) Array.newInstance(int.class, 2, 3);
★クラス検索
//方法1
Class<?> cls = Class.forName("com.Proxy");
System.out.println(cls.getName());
System.out.println(cls.getSuperclass());
System.out.println(cls.getInterfaces());
//方法2
Class<?> cls = Proxy.class;
System.out.println(cls.getName());
★クラス判断
Proxy a = new Proxy(null);
Proxy b = new Proxy(null);
if(a.getClass() == b.getClass()) {
//do something
}
//方法1
if(a instanceof Proxy) {
//do something
}
//方法2
if(Proxy.class.isInstance(a)) {
//do something
}
★インスタンス作成
try {
Proxy c = Proxy.class.newInstance();
} catch (InstantiationException e) {
System.err.println("引数なしコンストラクタがない");
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
//引数なしコンストラクタ
String s = (String)c.newInstance();
//引数ありコンストラクタ
char[] chars = {'h','e','l','l','o'};
Constructor<?> con = c.getConstructor(char[].class);
String s = (String)con.newInstance(chars);
★クラス名を比較するのではなくクラスを比較
1.オブジェクトobjが期待されるクラスかどうか
if(obj.getClass().getName().equals("com.xxx.yyy")) {...}
↓
if(auth.getClass == this.getClass().getClassLoader().loadClass("com.xxx.yyy")) {...}
2.xとyが同じクラスかどうか
if(x.getClass().getName().equals(y.getClass().getName())) {...}
↓
if(x.getClass == y.getClass()) {...}
★Reflection + Generics
public static <T> List<T> getRecords(Class<T> c, int len)
throws InstantiationException, IllegalAccessException {
List<T> list = new ArrayList<T>();
for (int i = 0; i < len; i++) {
T t = c.newInstance();
list.add(t);
}
return list;
}
★org.reflections.ReflectionUtils
https://code.google.com/p/reflections/
getAllSuperTypes(Class, com.google.common.base.Predicate...)
getAllFields(Class, com.google.common.base.Predicate...)
getAllMethods(Class, com.google.common.base.Predicate...)
getAllConstructors(Class, com.google.common.base.Predicate...)
withAnnotation(java.lang.annotation.Annotation)
withModifier(int)
withName(String)
withParameters(Class[])
withAnyParameterAnnotation(Class)
withParametersAssignableTo(Class[])
withPrefix(String)
withReturnType(Class)
withType(Class)
withTypeAssignableTo(java.lang.Class<T>)
Set<Method> getters = getAllMethods(SomeClass.class,
Predicates.and(
withModifier(PUBLIC),
withPrefix("get"),
withParametersCount(0)));