Java反射和代理简介
来源:互联网 发布:欧陆天使淘宝店 编辑:程序博客网 时间:2024/05/28 05:15
本文所引用的代码为JDK 1.8版本
请尊重博主劳动成果,转载请标明原文链接。
反射
Java反射中最常使用到的几个类:Class,Constructor,Method,Field。
- Class:用于获取类的字节码对象,获取构造方法,普通方法,以及属性。
- Constructor;用于创建对象。
- Method:调用对象的方法和调用类的静态方法。获取方法上配置的注解信息。
- Field:修改对象的属性或类的静态属性,获取对象或类的属性值。获取属性上配置的注解信息。
在某些被限定不能访问的类,方法或属性,当我需要创建对象,调用方法或获取值时,则可以使用反射来绕过这些非public修饰符的限制。
Class
常用到的几个方法:
获取字节码对象
forName(String className)
该方法是静态方法,用于获取类的字节码对象,className为类的路径。使用方式
Class<?> clazz = Class.forName("xx.xx.Xxx");
’xx.xx.Xxx‘是类的路径。
获取构造器
getConstructors()
获取字节码对象中所有public类型的构造方法,返回值为Constructor
public A(int i, String s){ ...}
则获取A的该构造方法的方式(clazz为类A的字节码对象)
Constructor<?> con = clazzA.getConstructor(int.class, String.class);
getDeclaredMethods()
获取字节码对象中所有类型的构造方法,返回值为Constructor
获取方法
getMethods()
获取字节码对象中public类型的方法,包含public类型的静态方法,返回值为Method[]。
getDeclaredConstructors()
获取字节码对象中所有类型的方法,返回值为Method[]。
getMethod(String name, Class
获取属性
getFields()
获取字节码对象中public类型的属性,包含public类型的静态属性,返回值为Field[]。
getDeclaredFields()
获取字节码对象中所有类型的属性,返回值为Field[]。
getField(String name)
获取指定名称的public属性,返回值为Field。
getDeclaredField(String name)
获取指定名称的属性,private,protected和缺省类型的都能够获取,返回值为Field。
小结
- 获取所有public类型的构造器,方法或属性的方式:getXxxs(),返回数组。
- 获取所有类型的构造器,方法或属性的方式:getDeclaredXxxs(),返回数组。
- 获取指定的public类型的构造器,方法或属性的方式:getXxx()
- 获取指定的构造器,方法或属性的方式:getDeclaredXxx()
获取的方式都比较相似。
Constructor
创建对象
newInstance(Object … initargs)
构造方法,使用该方法来创建对象,其中initargs为初始化的参数值。Java中的另外一种创建对象的方式是使用new关键字。
如果获取到的构造方法为public类型,则可以直接调用newInstance方法创建。如果为private,protected和缺省,则需要先调用setAccessible(true)
,设置其为可访问,然后在调用newInstance方法。
获取注解
getAnnotation(Class annotationClass)
用于获取构造器上的注解信息,annotationClass为注解类的class。返回的为注解类的对象,通过该对象可以获取注解上的配置信息。
getParameterAnnotations()
用于获取构造方法中的注解信息。返回值为Annotation[][]。
Method
调用方法
invoke(Object obj, Object… args)
obj为创建或获取到的对象,args为调用该方法时需要传入的参数值。如果该Method对象为非public的则需要先调用setAccessible(true)
,设置为可访问,才能使用invoke方法。如果不清楚method访问限定类型,可以先使用getModifiers()
获取方法修饰符类型,再使用Modifier.isPublic()
判断是否为public类型。如果Method为静态方法,则obj可以为null。
获取注解
getAnnotation(Class annotationClass)
获取方法上配置的注解,annotationClass为注解类的class。返回值为注解对象。
Field
设置或获取属性
set(Object obj, Object value)
设置Field属性值。obj为创建或获取到的对象,value为设置到该属性的值。如果该Field对象为非public的则需要先调用setAccessible(true)
,设置为可访问,才能使用invoke方法。如果不清楚method访问限定类型,可以先使用getModifiers()
获取方法修饰符类型,再使用Modifier.isPublic()
判断是否为public类型。如果Field为静态方法,则obj可以为null。
get(Object obj)
获取Field属性值。使用方式同上。
获取注解
getAnnotation(Class annotationClass)
获取属性上配置的注解,annotationClass为注解类的class。返回值为注解对象。
小结
反射使用步骤:
1,通过Class.forName()获取类的字节对象。
2,通过字节对象获取到构造器Constructor
代理
代理分为两种:静态代理,动态代理。
静态代理是直接写在代码里,通过一个类去操作需要代理的类。
动态代理则是通过反射和Proxy及相关的类在代码运行时动态实现。
动态代理大致可以分为3个步骤:
1,建立委托,即创建Interface(接口)和完成实现类;
2,实现InvocationHandler,在invoke方法内执行代理操作;
3,通过Proxy.newProxyInstance()方法创建代理对象,将代理对象传递给调用者。
Proxy
创建代理对象
newProxyInstance(ClassLoader loader, Class
InvocationHandler
这是一个接口,生成代理对象需要传入该接口实现类的对象。
执行代理
invoke(Object proxy, Method method, Object[] args)
代理对象会调用这个方法来执行被代理的方法,也就是说我们可以在此根据需求对参数args进行修改或添加,或者执行其它的方法。
参数说明:
proxy:为代理的对象,即通过Proxy.newProxyInstance()生成的。
method:代理对象需要执行的方法。
args:被调用的方法需要传入的参数值。
测试
接口和实现类:
package com.reflect.test;public interface Interface { void method0(String s); void method1(int i);}//修饰符缺省,只能包内访问class InterfaceImpl implements Interface{ public InterfaceImpl(){} @Override public void method0(String s) { System.out.println(" s = " + s); } @Override public void method1(int i) { System.out.println(" i = " + i); }}
InvocationHandler实现类和测试代码
package com.reflect;import java.lang.reflect.Constructor;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;import com.reflect.test.Interface;public class ProxyTest { public static void main(String[] args) { try { //获取InterfaceImpl字节码对象 Class<?> clazz = Class.forName("com.reflect.test.InterfaceImpl"); Constructor<?> cons = clazz.getConstructor(); //设置为可访问 cons.setAccessible(true); //创建对象 Object obj = cons.newInstance(); //创建代理对象 Interface interf = (Interface) Proxy.newProxyInstance( clazz.getClassLoader(), new Class<?>[]{Interface.class}, new InterfaceIH(obj)); //代理对象调用方法 interf.method0("call method0"); interf.method1(1); clazz = Proxy.getProxyClass(clazz.getClassLoader(), new Class<?>[]{Interface.class}); System.out.println(clazz.getCanonicalName()); } catch (Exception e) { e.printStackTrace(); } }}//InvocationHandler实现类class InterfaceIH implements InvocationHandler{ //目标对象 Object target; public InterfaceIH(Object obj){ target = obj; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { String name = method.getName(); //被调用的方法名称 System.out.println("call method: " + name); //传入的参数信息 if(args != null && args.length > 0){ System.out.println("arg = " + args[0]); } //修改参数 if("method0".equals(name)){ args[0] = "proxy " + args[0]; }else if("method1".equals(name)){ args[0] = 10 + (Integer)args[0]; } return method.invoke(target, args); }}
测试结果:
call method: method0arg = call method0 s = proxy call method0call method: method1arg = 1 i = 11com.sun.proxy.$Proxy0
参考博客:
公共技术点之 Java 动态代理
http://a.codekk.com/detail/Android/Caij/%E5%85%AC%E5%85%B1%E6%8A%80%E6%9C%AF%E7%82%B9%E4%B9%8B%20Java%20%E5%8A%A8%E6%80%81%E4%BB%A3%E7%90%86
深度剖析JDK动态代理机制
http://www.cnblogs.com/MOBIN/p/5597215.html
- Java反射和代理简介
- java 反射和代理
- JAVA 反射和代理
- Java 反射和代理
- Java反射和动态代理
- java 反射和代理机制
- java、反射和动态代理
- JAVA反射和代理机制
- java 反射和代理机制
- Java基础---反射和代理
- java反射和代理机制
- Java反射和动态代理
- java反射和动态代理
- java的动态代理和反射
- java反射机制和动态代理
- java反射和静态代理模式
- JAVA的反射机制和动态代理
- Java反射机制和动态代理实例
- C#200课的主要内容
- 【字符串入门专题1】J
- 利用顺序栈(基于数组)实现十进制转换输出其他进制数
- sql优化小总结:
- ReactNative——UI3.ScrollView 实现轮播图效果
- Java反射和代理简介
- 大数据经典学习路线(及供参考)
- python 安装zbar
- C++操作符的优先级及网上找的c++primer 第五版课后习题分析
- C语言中的动态内存分配
- 队列的定义以及实现
- windows系统如何设置域名解析
- 手工构建Android应用
- python 解析JSON