反射和代理经常使用的类和接口
类
Class
主要方法有:
- Method getMethod(String name, Class<?>... parameterTypes),
- Method[] getMethods()
- Method getDeclaredMethod(String name, Class<?>... parameterTypes)name 为方法名, parameterTypes 为该方法的参数列表
- Method[] getDeclaredMethods()
- Field 跟Method类似
- getClassLoader(), getInterfaces() 动态代理用到
- newInstance(), 类似于new, 动态创建一个新对象
- Method getMethod(String name, Class<?>... parameterTypes),
getMethod和getDeclaredMethod的区别是getMethod()
可以得到父类的公共方法,但是不能得到该类的私有方法,而getDeclaredMethod方法不能取得父类的方法,但是可以取得该类的私有方法
- Method
- Object invoke(Object obj, Object... args), 在对象obj 上调用该方法, args 为该方法的参数
- Object invoke(Object obj, Object... args), 在对象obj 上调用该方法, args 为该方法的参数
- Field
- Constructor
- Proxy
- Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) 动态代理产生新的对象
- Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) 动态代理产生新的对象
孙卫琴老师 的例子
大致步骤是取得某个类先--> 所有字段--> 得到get/set 方法-->在原对象上调用get方法取得值--> 在copy的对象调用set方法赋值
public class ReflectTester{
public Object copy(Object object)throws Exception{
//获得对象的类型
Class classType = object.getClass();
//创建一个新的对象
Object objectCopy = classType.newInstance();
//获得对象的所有字段
Field fields[] = classType.getDeclaredFields();
for (int i = 0; i < fields.length; i++){
Field field = fields[i];
String fieldName = field.getName();
String firstLetter = fieldName.substring(0, 1).toUpperCase();
//获得get 方法
String getMethodName = "get" + firstLetter + fieldName.substring(1);
//获得set 方法
String setMethodName = "set" + firstLetter + fieldName.substring(1);
Method getMethod = classType.getMethod(getMethodName);
// Method getMethod(String name, Class<?>... parameterTypes)
Method setMethod = classType.getMethod(setMethodName, new Class[]{field.getType()});
//调用原对象的get 方法
Object value = getMethod.invoke(object);
//调用原对象的set 方法,
setMethod.invoke(objectCopy, new Object[]{value});
}
return objectCopy;
}
public static void main(String args[])throws Exception{
ReflectTester reflect = new ReflectTester();
Customer customer = new Customer("tom", 21);
customer.setId(new Long(1));
Customer customerCopy = (Customer)reflect.copy(customer);
System.out.println("Copy information:" + customerCopy.getName() + ", "
+ customerCopy.getAge() + "," + customerCopy.getId());
}
}
class Customer{
private long id;
private String name;
private int age;
public Customer(){
}
public Customer(String name, int age){
this.name = name;
this.age = age;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
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;
}
}
另外java.beans包对反射做了更好的封装
下面的代码可以取得跟上面的一样的效果
public Object beanCopy(Object obj) throws Exception{
BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass());
PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
Object objCopy = obj.getClass().newInstance();
for (int i = 0; i < pds.length; i++){
if (pds[i].getName().equals("class")){
continue;
}
PropertyDescriptor pd = new PropertyDescriptor(pds[i].getName(), obj.getClass());
Method method = pd.getReadMethod();
Object value = method.invoke(obj);
method = pd.getWriteMethod();
method.invoke(objCopy, value);
}
return objCopy;
}
接口
- InvocationHandler(是代理实例的调用处理程序 实现的接口)要求用户程序实现该接口,类似于下面说到的TestProxy,
先是静态代理: (关于代理个人理解是做比代理类更多的事,或者是把一些在被代理类中不好处理的部分放到代理类中处理),
1.Test接口, 声明一个方法
public void sayHello();
2.TestImpl 实现Test接口
public void sayHello() {
System.out.println("say hello");
}
3.TestProxy, 实现Test接口,并在sayHello()中做其他事情
public void sayHello() {
System.out.println("before calling: sayHello()"); //前处理
test.sayHello(); //test为被代理的Test 实例, 调用test 的sayHello() 方法
System.out.println("after calling: sayHello()"); //后处理
}
4.客户端代码
public static void main(String args[]){
Test test = new TestImp1();
Test testProxy = new TestProxy(test);
testProxy.sayHello();
}
动态代理:
在这里讲解的很不错,
步骤是 获取一个实现了接口的对象(TestImpl) --> 获取一个实现了InvocationHandler接口的实现类 --> 创建动态代理对象 -- > 调用动态代理对象方法
是不是跟静态代理很像,只不过静态代理是直接从TestProxy new 出来的,而动态代理是由Proxy 类动态产生的,
下面是个基于内部类的动态代理类的实现,看起来更简洁点
public class ProxyFactory {
public static Object dynamicProxy(final Object obj){ // obj 一定要是final的
// 创建一个实现了 InvocationHandler 接口的内部类的实例
InvocationHandler handler = new InvocationHandler(){
public Object invoke(Object proxy, Method method, Object args[])throws Exception{
System.out.println("before calling: " + method.getName());
Object result = method.invoke(obj, args);
System.out.println("after calling: " + method.getName());
return result;
}
};
Class classType = obj.getClass();
return Proxy.newProxyInstance(classType.getClassLoader(), classType.getInterfaces(), handler);
}
}
invoke 方法实在是跟TestProxy 的代理方法像极了
客户端调用也很简单
public static void main(String args[]){
Test test = new TestImp1();
Test testDynamicProxy = (Test)ProxyFactory.dynamicProxy(test);
testDynamicProxy.sayHello();
}