lukazan

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理
反射机制允许程序在执行期借助于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);
    }
}
 
posted on 2021-05-09 19:14  lukazan  阅读(119)  评论(0编辑  收藏  举报