Blog
It's a Wonderful Life
java的反射机制
反射(reflection)通俗来讲就是根据给出的类名(字符串方式)来动态地生成对象。这种编程方式可以让对象在生成时才决定到底是哪一种对象。
下面给出一个详细的实例代码,注意参看注释。
package com.leo.test;
import java.lang.reflect.AnnotatedType;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
public class ReflectionTest
{
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, IllegalArgumentException, IllegalArgumentException, InvocationTargetException
{
//get class's package name and class name
demo1();
System.out.println("-------------------------------");
//verify every class is a subclass of Class object
demo2();
System.out.println("-------------------------------");
//create a new object through reflection
demo3();
System.out.println("-------------------------------");
//create a new object through reflection (with a construction parameter)
demo4();
System.out.println("-------------------------------");
//get private fields of new created object
demo5();
System.out.println("-------------------------------");
//get object's specific information through reflection
demo6();
System.out.println("-------------------------------");
//invoke new created object's methods through reflection
demo7();
System.out.println("-------------------------------");
//get object's ClassLoader through reflection
demo8();
}
//get class's package name and class name
public static void demo1() throws ClassNotFoundException
{
Class<?> c = Class.forName("com.leo.test.Person");
System.out.println("Package name: " + c.getPackage().getName());
System.out.println("Class name: " + c.getName());
}
//verify every class is a subclass of Class object
public static void demo2() throws ClassNotFoundException
{
Class<?> c = null;
c = Class.forName("com.leo.test.Person");
System.out.println("Package name: " + c.getPackage().getName());
System.out.println("Class name: " + c.getName());
}
//create a new object through reflection
public static void demo3() throws ClassNotFoundException, InstantiationException, IllegalAccessException
{
Class<?> c = Class.forName("com.leo.test.Person");
//Cus c.newInstance() can't carry on a parameter, therefore, Person class must have a no-parameter's constructor
Person p = (Person) c.newInstance();
p.setName("Leo");
p.setAge(22);
System.out.println(p.toString());
}
//create a new object through reflection (with a construction parameter)
public static void demo4() throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException
{
Class<?> c = Class.forName("com.leo.test.Person");
Constructor<?> constructor = c.getConstructor(String.class, int.class);
Person p = (Person) constructor.newInstance("Leo", 22);
System.out.println(p.toString());
}
//get private fields of new created object
public static void demo5() throws ClassNotFoundException, IllegalArgumentException, IllegalAccessException, InstantiationException
{
Class<?> c = Class.forName("com.leo.test.Person");
Person p = (Person) c.newInstance();
Field[] declaredFields = c.getDeclaredFields();
for (Field f : declaredFields)
{
f.setAccessible(true);
if (f.getAnnotatedType().getType().equals(int.class))
{
f.set(p, 22);
}
else if (f.getAnnotatedType().getType().equals(String.class))
{
f.set(p, "Leo");
}
}
System.out.println(p.toString());
}
//get object's specific information through reflection
public static void demo6() throws ClassNotFoundException
{
Class<?> c = Class.forName("com.leo.test.Policeman");
Class<?> sc = c.getSuperclass();
System.out.println("SuperClass: " + sc.getName());
System.out.println();
Field[] fields = c.getSuperclass().getDeclaredFields();
for (Field f : fields)
{
System.out.println(f);
}
System.out.println();
Method[] methods = c.getMethods();
for (Method m : methods)
{
System.out.println(m);
}
}
//invoke new created object's methods through reflection
public static void demo7() throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException
{
Class<?> c = Class.forName("com.leo.test.Policeman");
Method m = c.getMethod("patrol");
m.invoke(c.newInstance());
Method m1 = c.getMethod("patrol", int.class);
m1.invoke(c.newInstance(), 30);
}
//get object's ClassLoader through reflection
public static void demo8() throws ClassNotFoundException
{
Class<?> c = Class.forName("com.leo.test.Person");
System.out.println(c.getClassLoader().getClass().getName());
}
}
Person:
package com.leo.test;
public class Person
{
protected String name;
protected int age;
public Person(){}
public Person(String name, int age)
{
this.name = name;
this.age = age;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public int getAge()
{
return age;
}
public void setAge(int age)
{
this.age = age;
}
@Override
public String toString()
{
return "Person{" + "name=" + name + ", age=" + age + '}';
}
}
Policeman:
package com.leo.test;
public class Policeman extends Person
{
public Policeman() {}
public Policeman(String name, int age)
{
this.name = name;
this.age = age;
}
public void patrol()
{
System.out.println("Police patroling...");
}
public void patrol(int minutes)
{
System.out.println("Police patrol for " + minutes + " minutes...");
}
}
为了方便起见,我把实例代码中的Checked Exception
都throw
掉了,在实际开发环境不建议这么做。
同时,在编写这段代码的时候,我学习到了getFields()
和getDeclaredFields()
这两个方法的不同点就是前者只返回一个包含了类内部定义的public
域,以及继承而来的public
域的Field
对象数组,而后者返回一个只包含类内部定义的全部Fields
对象的数组(包括public
protected
default
private
),而不包括继承而来的域。所以如果我们想拿到继承来的域对象,可以使用以下语句:
Class<?> c = Class.forName("foo");
Field[] fields = c.getSuperClass().getDeclaredFields();
getMethods()
和getDeclaredMethods()
方法同上所述。