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)));