当前位置: 首页 > news >正文

【JavaSE】Java反射机制详解

【JavaSE】Java反射机制详解

文章目录

  • 【JavaSE】Java反射机制详解
    • 一:反射简介?
    • 二:反射的应用场景
    • 三:反射实战
      • 1:获取 Class 对象
      • 2:获取构造方法
      • 3:获取字段
      • 4:获取方法
      • 5: 反射的一些基本操作
    • 四:反射的优缺点?

一:反射简介?

反射之所以被称为框架的灵魂,主要是因为它赋予了我们在运行时分析类以及执行类中方法的能力。

通过反射你可以获取任意一个类的所有属性和方法,你还可以调用这些方法和属性。

Class clazz = Class.forName("com.yby.Writer");
Method method = clazz.getMethod("setName", String.class);
Constructor constructor = clazz.getConstructor();
Object object = constructor.newInstance();
method.invoke(object,"blblccc");

像上面这个例子,就可以理解为“反射”。

二:反射的应用场景

  • 开发通用框架:像 Spring,为了保持通用性,通过配置文件来加载不同的对象,调用不同的方法。
  • 动态代理:在面向切面编程中,需要拦截特定的方法,就会选择动态代理的方式,而动态代理的底层技术就是反射。
  • 注解:注解本身只是起到一个标记符的作用,它需要利用发射机制,根据标记符去执行特定的行为。

比如下面是通过 JDK 实现动态代理的示例代码,其中就使用了反射类 Method 来调用指定的方法。

public class DebugInvocationHandler implements InvocationHandler {
    /**
     * 代理类中的真实对象
     */
    private final Object target;

    public DebugInvocationHandler(Object target) {
        this.target = target;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException {
        System.out.println("before method " + method.getName());
        Object result = method.invoke(target, args);
        System.out.println("after method " + method.getName());
        return result;
    }
}

三:反射实战

1:获取 Class 对象

如果我们动态获取到这些信息,我们需要依靠 Class 对象。Class 类对象将一个类的方法、变量等信息告诉运行的程序。Java 提供了四种方式获取 Class 对象:

1. 知道具体类的情况下可以使用:

Class alunbarClass = TargetObject.class;

但是我们一般是不知道具体类的,基本都是通过遍历包下面的类来获取 Class 对象,通过此方式获取 Class 对象不会进行初始化

2. 通过 Class.forName()传入类的全路径获取:

Class alunbarClass1 = Class.forName("cn.yby.TargetObject");

3. 通过对象实例instance.getClass()获取:

TargetObject o = new TargetObject();
Class alunbarClass2 = o.getClass();

4. 通过类加载器xxxClassLoader.loadClass()传入类路径获取:

ClassLoader.getSystemClassLoader().loadClass("cn.yby.TargetObject");

通过类加载器获取 Class 对象不会进行初始化,意味着不进行包括初始化等一系列步骤,静态代码块和静态对象不会得到执行

2:获取构造方法

Class 对象提供了以下方法来获取构造方法 Constructor 对象:

  • getConstructor():返回反射类的特定 public 构造方法,可以传递参数,参数为构造方法参数对应 Class 对象;缺省的时候返回默认构造方法。
  • getDeclaredConstructor():返回反射类的特定构造方法,不限定于 public 的。
  • getConstructors():返回类的所有 public 构造方法。
  • getDeclaredConstructors():返回类的所有构造方法,不限定于 public 的。
Class c2 = Class.forName("com.yby.Writer");
Constructor constructor = c2.getConstructor();

Constructor[] constructors1 = String.class.getDeclaredConstructors();
for (Constructor c : constructors1) {
    System.out.println(c)
}

3:获取字段

大体上和获取构造方法类似,把关键字 Constructor 换成 Field 即可。

Method setNameMethod = clazz.getMethod("setName", String.class);
Method getNameMethod = clazz.getMethod("getName");

4:获取方法

大体上和获取构造方法类似,把关键字 Constructor 换成 Method 即可。

Method[] methods1 = System.class.getDeclaredMethods();
Method[] methods2 = System.class.getMethods();

如果你想反射访问私有字段和(构造)方法的话,需要使用Constructor/Field/Method.setAccessible(true) 来绕开 Java 语言的访问限制。

5: 反射的一些基本操作

  1. 创建一个我们要使用反射操作的类 TargetObject

    package cn.yby;
    
    public class TargetObject {
        private String value;
    
        public TargetObject() {
            value = "yby";
        }
    
        public void publicMethod(String s) {
            System.out.println("I love " + s);
        }
    
        private void privateMethod() {
            System.out.println("value is " + value);
        }
    }
    
  2. 使用反射操作这个类的方法以及参数

package cn.yby;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Main {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchFieldException {
        /**
         * 获取 TargetObject 类的 Class 对象并且创建 TargetObject 类实例
         */
        Class<?> targetClass = Class.forName("cn.yby.TargetObject");
        TargetObject targetObject = (TargetObject) targetClass.newInstance();
        /**
         * 获取 TargetObject 类中定义的所有方法
         */
        Method[] methods = targetClass.getDeclaredMethods();
        for (Method method : methods) {
            System.out.println(method.getName());
        }

        /**
         * 获取指定方法并调用
         */
        Method publicMethod = targetClass.getDeclaredMethod("publicMethod",
                String.class);

        publicMethod.invoke(targetObject, "yby");

        /**
         * 获取指定参数并对参数进行修改
         */
        Field field = targetClass.getDeclaredField("value");
        //为了对类中的参数进行修改我们取消安全检查
        field.setAccessible(true);
        field.set(targetObject, "yby");

        /**
         * 调用 private 方法
         */
        Method privateMethod = targetClass.getDeclaredMethod("privateMethod");
        //为了调用private方法我们取消安全检查
        privateMethod.setAccessible(true);
        privateMethod.invoke(targetObject);
    }
}

输出内容:

publicMethod
privateMethod
I love yby
value is yby

四:反射的优缺点?

反射可以让我们的代码更加灵活、为各种框架提供开箱即用的功能提供了便利。

不过,反射让我们在运行时有了分析操作类的能力的同时,也增加了安全问题,比如可以无视泛型参数的安全检查(泛型参数的安全检查发生在编译时)。另外,反射的性能也要稍差点,不过,对于框架来说实际是影响不大的。

相关文章:

  • 免费设计素材下载/大连seo优化
  • 合作客户北京网站建设/seo综合查询
  • wordpress页面404/seo定义
  • 国家和城乡建设部网站首页/品牌运营岗位职责
  • 万维网络(临沂网站建设)/百度推广网址
  • 电子商城平台网站建设/营销方式和手段
  • Unity 之 Addressable可寻址系统 -- 资源加载和释放
  • 静态链接过程分析
  • Java对象引用级别
  • 【Java入门】常量和变量
  • 九、MySQL 常用函数汇总(2)
  • IOC/DI配置管理第三方bean及注解开发。
  • 【ESP 保姆级教程】玩转emqx篇② ——控制客户端连接,认证安全
  • Linux-cp创建接口对
  • QT中矩形操作中QMarginsF[QMargins]的使用与QRectF的adjusted的对比
  • HTTP/HTTPS协议介绍
  • 并查集是什么?怎么模拟实现?如何应用?
  • 同源策略和跨域请求的实现