本节写了个Demo测试反射机制的主要方法,有些细节的东西没有再具体细化,把反射的主要功能都实现了一遍,代码如下:
public class TestReflect
{
public static void main(String[] args)
{
//测试所有构造函数
getAllConstructors();
//测试私有构造函数
getPrivateConstructor();
//测试运行私有方法
getPrivateMethod();
//测试获取和设置属性
getFields();
}
private static void getFields()
{
try
{
//加载类对象
Class<?> c = Class.forName("reflect.domain.Human");
//实例化Human对象
Human human = (Human) c.newInstance();
//获得Human对象所有属性
Field[] fields = c.getDeclaredFields();
for(int i = 0, size = fields.length; i < size; i++)
{
Field field = fields[i];
System.out.println(field.toGenericString());
String name = field.getName();
//转换将属性名首字母大写
if(!Character.isUpperCase(name.charAt(0)))
{
name = (new StringBuilder()).append(Character.toUpperCase(name.charAt(0))).append(name.substring(1)).toString();
}
//拼接获得属性设置方法名
String setMethod = "set" + name;
//获得属性设置Method
Method method = c.getDeclaredMethod(setMethod, new Class[]{String.class});
method.setAccessible(true);
//执行属性设置方法
method.invoke(human, new Object[]{"ss"});
}
human.introdude();
}
catch(Exception e)
{
//todo
}
}
private static void getPrivateMethod()
{
try
{
Class<?> c = Class.forName("reflect.domain.Human");
Human human = (Human) c.newInstance();
//获得指定方法名和参数类型的方法
Method method = c.getDeclaredMethod("privateMethod", new Class[]{});
//设置可访问
method.setAccessible(true);
//触发执行该方法
method.invoke(human, new Object[]{});
}
catch(Exception e)
{
//todo
}
}
private static void getPrivateConstructor()
{
try
{
Class<?> c = Class.forName("reflect.domain.Human");
//获得指定参数类型的构造函数
Constructor cons = c.getDeclaredConstructor(new Class[]{String.class});
//设置可访问
cons.setAccessible(true);
//初始化实例,根据传入的参数初始化
Human human = (Human) cons.newInstance(new Object[]{"William"});
//执行对象方法
human.publicMethod();
human.introdude();
}
catch(Exception e)
{
//todo
}
}
private static void getAllConstructors()
{
try
{
Class<?> c = Class.forName("reflect.domain.Human");
//获得所有构造函数
Constructor[] constructors = c.getDeclaredConstructors();
Human human = null;
for(int i = 0, size = constructors.length; i < size; i++)
{
Constructor cons = constructors[i];
cons.setAccessible(true);
//获得构造函数完整签名
String consName = cons.toGenericString();
//获得该构造函数的参数
String[] arg1 = consName.split("\\(");
String[] arg2 = arg1[1].split("\\)");
if(0 == arg2.length)
{
//如果参数为0,调用无参构造函数实例化
human = (Human) cons.newInstance();
human.introdude();
}
else
{
//否则根据参数个数和类型分别实例化,如果不知道参数类型,也可以用反射机制获得,这里不再麻烦
String[] args = arg2[0].split(",");
if(1 == args.length)
{
human = (Human) cons.newInstance(new Object[]{"Ann"});
human.introdude();
}
else if(2 == args.length)
{
human = (Human) cons.newInstance(new Object[]{"Ann", "female"});
human.introdude();
}
}
}
}
catch(Exception e)
{
//todo
}
}
}
反射机制允许一个类使用另一个类,即使当前者被编译的时候后者还根本不存在。然后,这种能力也要付出代价:
1.丧失了编译时类型检查的好处,包括异常检查。如果程序试图用反射方式调用不存在或不可访问的方法,在运行时它可能会失败,因此需要做好防护措施;
2.执行反射访问所需要的代码非常笨拙和冗长。编写乏味,阅读困难;
3.性能损失。反射方法调用比普通方法调用慢很多。
以上来自<<Effective Java>>。
因此,在普通的方法调用中不需要使用反射,在一些复杂程序中,而且需要使用在编译时无法知道的对象时,才考虑使用反射机制。
反射是一些框架技术的核心,比如Spring,Struts2等,对于反射的原理还需要进一步掌握。