Android -从浅到懂使用反射机制 小咪咪 2022-12-26 10:12 100阅读 0赞 # 定义 # > JAVA反射机制是在运行状态中,对于任何一个类,都能够知道这个类的所有属性和方法; > 对于任何一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为 Java 语言的反射机制。 # 使用场景 # > 反射是在运行时获取确定类型,绑定对象。 常见的两个使用场景 1. 运行时获取对象的所有信息 2. 泛型擦除 ## 在运行时获取类 ## 这里的运行时指的是程序在运行后。相应的还有编译时,编译时是编译器将源代码翻译成机器能识别的代码。 举个例子说明编译时和运行时的区别: ![在这里插入图片描述][20201209220138228.png] ## 泛型擦除 ## val list = arrayListOf<Int>(1,2,3) val clz = Class.forName("java.util.ArrayList") val method = clz.getMethod("add", Object::class.java) method.invoke(list,"hhh") Log.e(TAG,"list:${list.toString()}") 输出: list:[1, 2, 3, hhh] # 反射的利弊 # ## 利 ## * 运行时类型的判断 * 动态类加载,动态代理使用反射。 ## 弊 ## * 性能问题,反射相当于一系列解释操作。 * JVM 不会去优化这部分代码 * 代码不易阅读 ## 为什么会出现性能问题? ## 1. `Method#invoke` 方法会对参数做封装和解封操作 2. 需要检查方法可见性 3. 需要校验参数 4. 反射方法难以内联 5. `JVM` 无法优化: `Java` 文档中介绍 `invoke`方法源码: class Class { @CallerSensitive public Method getMethod(String name, Class<?>... parameterTypes) throws NoSuchMethodException, SecurityException { Objects.requireNonNull(name); SecurityManager sm = System.getSecurityManager(); if (sm != null) { // 1. 检查方法权限 checkMemberAccess(sm, Member.PUBLIC, Reflection.getCallerClass(), true); } // 2. 获取方法 Method method = getMethod0(name, parameterTypes); if (method == null) { throw new NoSuchMethodException(methodToString(name, parameterTypes)); } // 3. 返回方法的拷贝 return getReflectionFactory().copyMethod(method); } @CallerSensitive public Method getDeclaredMethod(String name, Class<?>... parameterTypes) throws NoSuchMethodException, SecurityException { Objects.requireNonNull(name); SecurityManager sm = System.getSecurityManager(); if (sm != null) { // 1. 检查方法权限 checkMemberAccess(sm, Member.DECLARED, Reflection.getCallerClass(), true); } // 2. 获取方法 Method method = searchMethods(privateGetDeclaredMethods(false), name, parameterTypes); if (method == null) { throw new NoSuchMethodException(methodToString(name, parameterTypes)); } // 3. 返回方法的拷贝 return getReflectionFactory().copyMethod(method); } } # 如何使用 # > 想要使用反射机制,就必须要先获取到该类的字节码文件对象`(.class)`,通过字节码文件对象,就能够通过该类中的方法获取到我们想要的所有信息(方法,属性,类名,父类名,实现的所有接口等等),每一个类对应着一个字节码文件也就对应着一个`Class`类型的对象。 ## 获取字节码文件对象 ## * 1、根据类名:`类名.class` * 2、根据对象:`对象.getClass()` * 3、根据全限定类名:`Class.forName(全限定类名)` 常用的是第一种。 ## 获取构造函数 ## > 构造函数分为两种:带参和不带参 * 获取不带参构造函数 Class classs = Class.forName("com.xxx.xxx.User"); Constructor constructor = classs.getDeclaredConstructor(); Object user = constructor.newInstance(); * 获取带参构造函数 Class classs = Class.forName("com.xxx.xxx.User"); Constructor constructor = classs.getConstructor(int.class,String.class); Object user = constructor.newInstance(1,"张三"); ## 获取成员变量 ## > 成员变量一般为公有和私有 * 获取公有成员变量 Class classs = Class.forName("com.xxx.xxx.User"); Constructor constructor = classs.getConstructor(); Object user = constructor.newInstance(); Field declaredField = classs.getField("userName"); // 赋新值 declaredField.set(user, "李四"); * 获取私有成员变量 Class classs = Class.forName("com.xxx.xxx.User"); Constructor constructor = classs.getConstructor(); Object user = constructor.newInstance(); Field declaredField = classs.getDeclaredField("userName"); // 因为属性是私有的,所有需要打开可见权限 declaredField.setAccessible(true); // 赋新值 declaredField.set(user, "李四"); ## 获取方法 ## > 成员方法一般为公有和私有,同时方法也分有参和无参 * 获取公有成员无参方法 Class classs = Class.forName("com.xxx.xxx.User"); Constructor constructor = classs.getConstructor(); Object user = constructor.newInstance(); Method method = classs.getMethod("getUserName"); method.invoke(user); * 获取公有成员有参方法 Class classs = Class.forName("com.xxx.xxx.User"); Constructor constructor = classs.getConstructor(); Object user = constructor.newInstance(); Method method = classs.getMethod("getUserName", String.class); method.invoke(user, "王五"); * 获取私有成员无参方法 Class classs = Class.forName("com.xxx.xxx.User"); Constructor constructor = classs.getConstructor(); Object user = constructor.newInstance(); Method method = classs.getDeclaredMethod("getUserName"); // 因为属性是私有的,所有需要打开可见权限 method.setAccessible(true); method.invoke(user); * 获取私有成员有参方法 Class classs = Class.forName("com.xxx.xxx.User"); Constructor constructor = classs.getConstructor(); Object user = constructor.newInstance(); Method method = classs.getDeclaredMethod("getUserName",String.class); // 因为属性是私有的,所有需要打开可见权限 method.setAccessible(true); method.invoke(user, "王五"); ## Tip ## 1. 一般来说,构造函数大部分是 public ,而成员变量和方法大部分是 private。public 权限直接正常调用即可、private需要在调用前增加 `setAccessible(true)` 2. 获取构造函数、成员变量、成员方法都有一个获取所有的方法,根据需要去调用。如:`getConstructor:获取单个构造函数,getConstructors:获取所有构造函数` # 总结 # 反射的作用是在运行时动态获取对象信息。 实现步骤: 1. 获取 `Class`:有三种方式,常用的是 `Class.forName("类全名称")` 2. 获取构造函数:通过 `Class` 对象调用 如:`clz.getConstructor()` 得到构造函数 3. 创建对象:通过构造函数创建对象 如:`con.newInstance()` 没有 `Declared` 前缀会返回所有的 `public` 方法,包括父类的方法。 而加 `Declared` 前缀会返回所有自己定义的方法,`public,protected,private` 都在此,但是不包括父类的方法。 这也正是 `getMethod` 和 `getDeclaredMethod` 的区别。 * 获取私有构造函数 Class classs = Class.forName("com.xxx.xxx.User"); Constructor constructor = classs.getDeclaredConstructor(); // 因为属性是私有的,所有需要打开可见权限 constructor.setAccessible(true); Object user = constructor.newInstance(); * 获取私有成员变量 ... Field declaredField = classs.getDeclaredField("userName"); // 因为属性是私有的,所有需要打开可见权限 declaredField.setAccessible(true); * 获取私有成员方法 ... Method method = classs.getDeclaredMethod("getUserName"); // 因为属性是私有的,所有需要打开可见权限 method.setAccessible(true); 反射耗时的原因: * `invoke`方法需要做封装和解封操作 * 需要类型检查、权限检查 * 需要校验参数 * 需要检查方法的可见性 * `JVM`无法做优化 # 参考 # * [Reflection:Java反射机制的应用场景][Reflection_Java] * [深入浅出Java反射原理和使用场景][Java] * [java反射机制详解][java] * [Java 反射 -超详细讲解(附源码)][Java _ -] * [java反射为什么慢][java 1] * [强大的反射库 FreeReflection][FreeReflection] [20201209220138228.png]: /images/20221120/67ddcc6db5714421ab320bd0672aecd4.png [Reflection_Java]: https://segmentfault.com/a/1190000010162647?utm_source=tuicool&utm_medium=referral [Java]: https://blog.csdn.net/21aspnet/article/details/89402714 [java]: https://www.cnblogs.com/myRichard/p/11742194.html [Java _ -]: https://blog.csdn.net/lililuni/article/details/83449088 [java 1]: https://github.com/5A59/android-training/blob/master/jvm-art/java%E5%8F%8D%E5%B0%84%E4%B8%BA%E4%BB%80%E4%B9%88%E6%85%A2.md [FreeReflection]: https://github.com/tiann/FreeReflection/
相关 Java反射机制:在什么场景下会使用到反射? 在Java编程中,反射机制主要用于以下几种场景: 1. **运行时动态获取类信息**:通过反射API,可以在运行时获取指定类的信息,如名称、包名、父类等。 2. **创建对 ╰半夏微凉°/ 2024年09月04日 10:30/ 0 赞/ 12 阅读
相关 浅谈java反射机制 1.之前学习spring框架的时候老师说spring Ioc的底层原理是反射,一直是一知半解,看来这位博主的讲解,稍有感触并简单总结了一下. 2.什么是java反射机制 刺骨的言语ヽ痛彻心扉/ 2024年02月19日 20:20/ 0 赞/ 14 阅读
相关 Android - 从浅到懂理解 Binder 文章目录 背景 为什么需要跨进程通信(IPC) 为什么是Binder? 用户空间/内核空间 系统 向右看齐/ 2022年12月30日 15:58/ 0 赞/ 152 阅读
相关 Android -从浅到懂使用反射机制 定义 > JAVA反射机制是在运行状态中,对于任何一个类,都能够知道这个类的所有属性和方法; > 对于任何一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及 小咪咪/ 2022年12月26日 10:12/ 0 赞/ 101 阅读
相关 Android - 从浅到懂去理解注解 文章目录 Java注解产生背景 Java 注解是什么 作用是什么 编译时注解 运行时注解 二者的区别 本质 ╰+攻爆jí腚メ/ 2022年12月26日 08:26/ 0 赞/ 78 阅读
相关 java的反射机制浅谈 反射,当时经常听他们说,自己也看过一些资料,也可能在设计模式中使用过,但是感觉对它没有一个较深入的了解,这次重新学习了一下,感觉还行吧! 一,先看一下反射的概念: Myth丶恋晨/ 2022年09月25日 04:22/ 0 赞/ 173 阅读
相关 java的反射机制浅谈 一、java的反射机制浅谈 最近研究java研究得很给力,主要以看博文为学习方式。以下是我对java的反射机制所产生的一些感悟,希望各位童鞋看到失误之处不吝指出。受到各 淡淡的烟草味﹌/ 2022年07月16日 00:28/ 0 赞/ 150 阅读
相关 浅谈JAVA反射机制 什么是反射? 在java核心卷一给出的概括: 能够分析类能力的程序称为反射,可以在运行时分析类能力,运行时查看对象。 按照我的理解就是: 1. 探索类的信息 2. 末蓝、/ 2021年10月14日 07:14/ 0 赞/ 327 阅读
相关 Android 使用Java的反射机制总结 导语 > 反射是一种具有与Java类进行动态交互能力的一种机制,在Java和Android开发中,一般需要访问隐藏属性或者调用方法改变程序原来的逻 末蓝、/ 2021年09月14日 14:12/ 0 赞/ 575 阅读
还没有评论,来说两句吧...