java反射与动态代理

前言

本章将围绕以下问题进行分析

  • 什么是反射
  • 反射的使用
  • 什么是动态代理
  • 动态代理的使用

正文

反射

定义

在程序运行时可以动态的修改类或对象的属性和方法(私有、公有和静态等)。本质是JVM得到class对象之后,再通过class对象进行反编译,从而获取对象的各种信息。

使用

1、构造Class类

ini 复制代码
//Class clas = 类名.class;
Class clas = Class.forName("相对路径的类名");

2、获取类的方法

(一)、构造方法
ini 复制代码
//根据构造方法的参数获取指定的公有构造方法 参数如:String.class,int.class
Constructor singleConstructor1 = clas.getConstructor(XXX.class,....);

//根据构造方法的参数获取指定的构造方法 参数如:String.class,int.class
Constructor singleConstructor2 = clas.getDeclaredConstructor(XXX.class,....);

//获取类的所有公有构造方法
Constructor[] constructors = clas.getConstructors();

//获取类的所有构造方法()
Constructor[] declaredConstructors = clas.getDeclaredConstructors();

可以通过Class类getConstructor(Class<?>... parameterTypes)getConstructors()获取指定类的公有 构造方法,getDeclaredConstructor(Class<?>... parameterTypes)getDeclaredConstructors()获取指定类的所有访问域(公有、保护、私有)构造方法

  • getConstructor(Class<?>... parameterTypes)通过传入参数获取类对应的公有构造方法。参数的值是Class类,如:String.class、int.class等;并且传入参数的值和构造方法参数类型必须一一对应,否则会出现NoSuchMethodException异常。
  • getConstructors()获取类的所有公有构造方法
  • getDeclaredConstructor(Class<?>... parameterTypes)通过传入参数获取类对应的访问域(公有、保护、私有)构造方法。参数的值是Class类,如:String.class、int.class等;并且传入参数的值和构造方法参数类型必须一一对应,否则会出现NoSuchMethodException异常。
  • getDeclaredConstructors()获取类中所有访问域(公有、保护、私有)的构造方法
(二)、其他方法
ini 复制代码
//获取指定类或指定类超类对应的公有方法
Method method1 = clas.getMethod("方法名称",XXX.class,.....);

//获取指定类对应访问域方法(不能获取超类的方法)
Method method2 = clas.getDeclaredMethod("方法名称",XXX.class,.....);

//获取指定类或指定类超类的所有公有方法
Method[] methods = clas.getMethods();

//获取指定类所有访问域方法(不能获取超类的方法)
Method[] declaredMethods = clas.getDeclaredMethods();

可以通过Class类getMethod(String name, Class<?>... parameterTypes)getMethods()获取指定类或其超类的公有方法getDeclaredMethod(String name, Class<?>... parameterTypes)getDeclaredMethods()获取指定类的所有访问域(公有、保护、私有)方法,但不能获取到其超类的方法

  • getMethod(String name, Class<?>... parameterTypes)通过传入方法名和方法参数获取类或其超类对应的公有方法。参数的值是Class类,如:String.class、int.class等;并且传入参数的值和方法参数类型必须一一对应,否则会出现NoSuchMethodException异常。
  • getMethods()获取类和其超类的所有公有方法
  • getDeclaredMethod(String name, Class<?>... parameterTypes)通过传入方法名和方法参数获取类对应访问域的方法。参数的值是Class类,如:String.class、int.class等;并且传入参数的值和方法参数类型必须一一对应,否则会出现NoSuchMethodException异常。
  • getDeclaredMethods()获取类中所有访问域(公有、保护、私有)的方法

3、获取类的属性

ini 复制代码
//获取指定类或其超类对应的公有属性
Field field1 = clas.getField("属性名");

//获取指定类对应的所有访问域属性
Field field2 = clas.getDeclaredField("属性名");

//获取指定类或其超类的公有属性
Field[] fields = clas.getFields();

//获取指定类所有的属性
Field[] declaredFields = clas.getDeclaredFields();

可以通过Class类getField(String name)getFields()获取指定类或其超类的公有属性getDeclaredField(String name)getDeclaredFields()获取指定类的所有访问域(公有、保护、私有)属性,但不能获取到其超类的属性

  • getField(String name)通过传入属性名获取类或其超类对应的公有属性。传入的属性名必须在指定类或其超类存在,否则会出现NoSuchFieldException异常。
  • getFields()获取类和其超类的所有公有属性
  • getDeclaredField(String name)通过传入属性名获取类对应的访问域(公有、保护、私有)属性。传入的属性名必须在指定类存在,否则会出现NoSuchFieldException异常。
  • getDeclaredFields()获取类中所有访问域(公有、保护、私有)的属性

4、反射调用类的方法

伪代码(非静态方法)
  1. 构造Class类
  2. 构建Class对象
  3. 获取class对象方法并调用
代码(非静态方法)
scss 复制代码
try {
    //构造class类
    Class clas = Class.forName("相对路径类名");
    //获取构造方法
    Constructor singleConstructor = clas.getDeclaredConstructor();
    //如果是私有构造方法必须关闭访问检测
    singleConstructor.setAccessible(true);
    //创建对象
    Object instance = singleConstructor.newInstance();
    //调用方法
    Method setColor = clas.getMethod("方法名", xxx.class,....);
    //设置方法参数值
    setColor.invoke(instance, "参数值");
} catch (ClassNotFoundException e) {
    e.printStackTrace();
} catch (NoSuchMethodException e) {
    e.printStackTrace();
} catch (IllegalAccessException e) {
    e.printStackTrace();
} catch (InvocationTargetException e) {
    e.printStackTrace();
} catch (InstantiationException e) {
    e.printStackTrace();
}

调用对象的方法前,必须要先构建class对象。可以使用Class类的newInstance()或者Class构造方法的newInstance(Object ... initargs)构建Class对象。但使用Class类的newInstance()构建对象时Class类的默认构造方法必须是public的 ,否则会构建失败。而使用Class构造方法的newInstance(Object ... initargs)构建Class对象时,构造方法可以是任意访问域(public、private、protected),如果是private或者protected访问域,必须关闭访问检测(setAccessible(true)),否则也会构建失败。

伪代码(静态方法 static或static final修饰)
  1. 构造Class类
  2. 获取class类的静态方法并调用
代码(静态方法 static或static final修饰)
ini 复制代码
try {
     //构造class类
     Class clas = Class.forName("相对路径类名");
//            Method method = clas.getMethod("参数名");
     Method method = clas.getDeclaredMethod("参数名");
     method.setAccessible(true);
     method.invoke(null,"参数值");
     } catch (ClassNotFoundException e) {
       e.printStackTrace();
     } catch (NoSuchMethodException e) {
       e.printStackTrace();
     } catch (IllegalAccessException e) {
       e.printStackTrace();
     } catch (InvocationTargetException e) {
       e.printStackTrace();
     }

5、反射修改类的属性值

伪代码(非静态属性)
  1. 构造Class类
  2. 构建Class对象
  3. 获取Class对象属性并修改属性值
代码(非静态属性)
scss 复制代码
try {
    //构造class类
    Class clas = Class.forName("相对路径类名");
    //获取构造方法
    Constructor singleConstructor = clas.getDeclaredConstructor();
    //如果是私有构造方法必须关闭访问检测
    singleConstructor.setAccessible(true);
    //创建对象
    Object instance = singleConstructor.newInstance();
    //获取属性
    Field field = clas.getDeclaredField("属性名");
    //关闭访问检测(私有属性必须关闭)
    field.setAccessible(true);
    //修改属性值
    field.set(instance, "属性值");
} catch (ClassNotFoundException e) {
    e.printStackTrace();
} catch (NoSuchFieldException e) {
    e.printStackTrace();
} catch (NoSuchMethodException e) {
    e.printStackTrace();
} catch (InstantiationException e) {
    e.printStackTrace();
} catch (IllegalAccessException e) {
    e.printStackTrace();
} catch (InvocationTargetException e) {
    e.printStackTrace();
}
伪代码(静态属性 static修饰)
  1. 构造Class类
  2. 构建Class的静态属性并修改属性值
代码(静态属性 static修饰)
ini 复制代码
try {
    //构造class类
    Class clas = Class.forName("相对路径类名");
    //   Field field = clas.getField("属性名");
    Field field = clas.getDeclaredField("属性名");
    field.setAccessible(true);
    field.set(null,"属性值");
} catch (ClassNotFoundException e) {
    e.printStackTrace();
} catch (IllegalAccessException e) {
    e.printStackTrace();
} catch (NoSuchFieldException e) {
    e.printStackTrace();
}
伪代码(静态常量属性 static final修饰)
  1. 构造Class类
  2. 构建Class的静态属性,去除final的影响
  3. 修改属性值
代码(静态常量属性 static final修饰)
ini 复制代码
try {
    //构造class类
    Class clas = Class.forName("相对路径类名");
    //   Field field = clas.getField("属性名");
    Field field = clas.getDeclaredField("属性名");
    field.setAccessible(true);
    //去除final的影响
    Field modifiersField = Field.class.getDeclaredField("modifiers");
    AccessController.doPrivileged((PrivilegedAction) () -> {
        modifiersField.setAccessible(true);
        return null;
    });
    modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
    //设置属性值
    field.set(null, "属性值");
} catch (ClassNotFoundException e) {
    e.printStackTrace();
} catch (IllegalAccessException e) {
    e.printStackTrace();
} catch (NoSuchFieldException e) {
    e.printStackTrace();
}

动态代理

定义

使用反射的方式,动态地获取抽象接口的类型,从而获取相关特性进行代理。

使用代码

scss 复制代码
接口类 proxyService = (接口类) Proxy.newProxyInstance(接口类.getClassLoader(), new Class<?>[]{接口类}, (proxy, method, args1) -> {
    //进行拦截
    ......
    //返回实现类的实现
    return method.invoke("实现类",args);
});
接口类.实现方法();

以上是创建代理模式的公式。在实际开发中,我们可以使用代理类进行拦截实体类的实现或者加入自己的实现逻辑。

相关推荐
是小崔啊1 小时前
开源轮子 - EasyExcel02(深入实践)
java·开源·excel
心软小念1 小时前
外包干了27天,技术退步明显。。。。。
软件测试·面试
myNameGL2 小时前
linux安装idea
java·ide·intellij-idea
青春男大2 小时前
java栈--数据结构
java·开发语言·数据结构·学习·eclipse
HaiFan.2 小时前
SpringBoot 事务
java·数据库·spring boot·sql·mysql
我要学编程(ಥ_ಥ)2 小时前
一文详解“二叉树中的深搜“在算法中的应用
java·数据结构·算法·leetcode·深度优先
music0ant3 小时前
Idea 添加tomcat 并发布到tomcat
java·tomcat·intellij-idea
计算机徐师兄3 小时前
Java基于SSM框架的无中介租房系统小程序【附源码、文档】
java·微信小程序·小程序·无中介租房系统小程序·java无中介租房系统小程序·无中介租房微信小程序
源码哥_博纳软云3 小时前
JAVA智慧养老养老护理帮忙代办陪诊陪护小程序APP源码
java·开发语言·微信小程序·小程序·微信公众平台
忒可君4 小时前
C# winform 报错:类型“System.Int32”的对象无法转换为类型“System.Int16”。
java·开发语言