反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。
1、Java反射机制提供的功能
-
在运行时判断任意一个对象所属的类
-
在运行时构造任意一个类的对象
-
在运行时判断任意一个类所具有的成员变量和方法
-
在运行时调用任意一个对象的成员变量和方法
-
生成动态代理
-
在运行时获取泛型信息
-
在运行时处理注解
2、反射相关的主要API
-
java.lang.Class:代表一个类
-
java.lang.reflect.Method:代表类的方法
-
java.lang.reflect.Field:代表类的成员变量
-
java.lang.reflect.Constructor:代表类的构造器
3、常用方法
-
static Class forName(String name):返回指定类名 name 的 Class 对象
-
Object newInstance():调用缺省构造函数,返回该Class对象的一个实例
-
getName():返回此Class对象所表示的实体(类、接口、数组类、基本类型或void)名称
-
Class getSuperClass():返回当前Class对象的父类的Class对象
-
Class [] getInterfaces():获取当前Class对象的接口
-
ClassLoader getClassLoader():返回该类的类加载器
-
Constructor[] getConstructors():返回一个包含某些Constructor对象的数组
-
Field[] getDeclaredFields():返回Field对象的一个数组
-
Method getMethod(Stringname,Class … paramTypes):返回一个Method对象,此对象的形参类型为paramType
4、获取Class类的实例(四种方法)
-
已知具体的类,通过类的class属性获取, 该方法最为安全可靠,程序性能最高:Class clazz = String.class;
-
已知某个类的实例,调用该实例的getClass()方法获取Class对象:Class clazz = “www.atguigu.com”.getClass();
-
已知一个类的全类名,且该类在类路径下, 可通过Class类的静态方法forName()获取,可能抛出ClassNotFoundException:Class clazz = Class.forName(“java.lang.String”);
-
其他方式(不做要求):Class clazz4 =this.getClass().getClassLoader().loadClass(“类的全类名”);
5、创建运行时类的对象
-
调用Class对象的newInstance()方法
-
类必须有一个无参数的构造器。
-
类的构造器的访问权限需要足够。
-
通过Class类的getDeclaredConstructor(Class … parameterTypes)取得本类的指定形参类型的构造器,在通过构造器的newInstance()方法创建对象
6、通过反射获取运行时类的完整结构:
(1)实现的全部接口Interface
- public Class<?>[] getInterfaces()
(2)所继承的父类Superclass
- public Class<? Super T> getSuperclass()
(3)获取构造器Constructor
- public Constructor<T>[] getConstructors():返回此 Class 对象所表示的类的所有public构造方法。
- public Constructor<T>[] getDeclaredConstructors():返回此 Class 对象表示的类声明的所有构造方法。
- Constructor类中:
-
- 取得修饰符:public int getModifiers();
-
- 取得方法名称:public String getName();
-
- 取得参数的类型:public Class<?>[] getParameterTypes();
-
- 创建对象:public TnewInstance(Object... initargs);
(4)获取方法Method
- public Method[] getDeclaredMethods():返回此Class对象所表示的类或接口的全部方法
- public Method[] getMethods():返回此Class对象所表示的类或接口的public的方法
- public Method getMethod(String name,Class…parameterTypes):获取指定方法名的方法对象
- Method类中:
-
- public Class<?> getReturnType():取得全部的返回值
-
- public Class<?>[] getParameterTypes():取得全部的参数
-
- public int getModifiers():取得修饰符
-
- public Class<?>[] getExceptionTypes():取得异常信息
-
- Object invoke(Object obj, Object[] args):执行指定的方法
-
-
- 若原方法声明为private,则需要在调用此invoke()方法前,显式调用方法对象的setAccessible(true)方法,将可访问private的方法。
-
(5)获取属性Field
- public Field[] getFields():返回此Class对象所表示的类或接口的public的Field。
- public Field[] getDeclaredFields():返回此Class对象所表示的类或接口的全部Field。
- public Field getField(String name):返回此Class对象表示的类或接口的指定的public的Field。
- public Field getDeclaredField(String name):返回此Class对象表示的类或接口的指定的Field。
- Field类中:
-
- public int getModifiers():以整数形式返回此Field的修饰符
-
- public Class<?> getType():得到Field的属性类型
-
- public String getName():返回Field的名称。
-
- public Object get(Object obj) 取得指定对象obj上此Field的属性内容
-
- public void set(Object obj,Object value) 设置指定对象obj上此Field的属性内容
-
-
- 若原属性声明为private,则需要在调用此get()/set()方法前,显式调用对象的setAccessible(true)方法,将可访问private的属性。
-
(6)获取注解Annotation
- get Annotation(Class<T> annotationClass)
- getDeclaredAnnotations()
(7)获取泛型
- 获取父类泛型类型:Type getGenericSuperclass()
- 泛型类型:ParameterizedType
- 获取实际的泛型类型参数数组:getActualTypeArguments()
(8)获取包名
- Package getPackage()
7、关于setAccessible方法的使用
-
Method和Field、 Constructor对象都有setAccessible()方法。
-
setAccessible启动和禁用访问安全检查的开关。
-
参数值为true则指示反射的对象在使用时应该取消Java语言访问检查。
-
提高反射的效率。 如果代码中必须用反射, 而该句代码需要频繁的被调用, 那么请设置为true。
-
使得原本无法访问的私有成员也可以访问
-
参数值为false则指示反射的对象应该实施Java语言访问检查。
8、动态代理
动态代理是指客户通过代理类来调用其它对象的方法,并且是在程序运行时根据需要动态创建目标类的代理对象。
(1)创建接口InvocationHandler的实现类
public class MyInvocationHandler implements InvocationHandler { private Object obj; //需要使用被代理类的对象进行赋值 public void bind(Object obj) { this.obj = obj; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("代理功能1"); Object returnValue = method.invoke(obj, args); //method:即为代理类对象调用的方法,此方法也就作为了被代理类对象要调用的方法 System.out.println("代理功能2"); return returnValue; //上述方法的返回值就作为当前类中的invoke()的返回值。 } }
(2)创建被代理类及其接口
必须创建接口,因为代理类是通过接口代理的
(3)创建代理类对象
MyInvocationHandler handler = new MyInvocationHandler(); Human person = new Person(); handler.bind(person); Human personProxyInstance = (Human) Proxy.newProxyInstance(person.getClass().getClassLoader(), person.getClass().getInterfaces(), handler); //创建person类的代理类对象
(4)执行代理操作
String belief = personProxyInstance.getBelief();
(5)创建代理类对象方式二:创建代理类工厂来获取代理类对象
public class ProxyFactory { public static Object getProxyInstance(Object object) { MyInvocationHandler handler = new MyInvocationHandler(); handler.bind(object); return Proxy.newProxyInstance(object.getClass().getClassLoader(), object.getClass().getInterfaces(), handler); } }