java 反射和代理

反射和代理经常使用的类和接口
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, 动态创建一个新对象
getMethod和getDeclaredMethod的区别是getMethod()  可以得到父类的公共方法,但是不能得到该类的私有方法,而getDeclaredMethod方法不能取得父类的方法,但是可以取得该类的私有方法
  1. Method
    • Object invoke(Object obj, Object... args),  在对象obj 上调用该方法, args 为该方法的参数
  2. Field
  3. Constructor
  4. Proxy
    • 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;
    }

接口
  1. 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();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值