首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

java-反射(Reflection)

  • 25-03-07 23:21
  • 2752
  • 10931
blog.csdn.net

目录

一、什么是反射?

二、反射的用途

三、获取Class对象

四、Class类型的对象使用场景1

五、Class类型的对象使用场景2

六、通过反射创建对象

七、使用 Java 反射机制获取和调用类的构造方法,访问私有构造方法并创建对象

八、通过反射,访问并使用成员方法

九、通过反射,调用静态方法以及处理可变参数

十、反射的性能问题

十一、反射的安全性

十二、反射的常见场景


一、什么是反射?

        反射(Reflection)是一种 Java 程序运行期间的动态技术,可以在运行时(runtime)检査、修改其自身结构或行为。通过反射,程序可以访问、检测和修改它自己的类、对象、方法、属性等成员

二、反射的用途

  • 动态加载类:程序可以在运行时动态地加载类库中的类;
  • 动态创建对象:反射可以基于类的信息,程序可以在运行时,动态创建对象实例;
  • 调用方法:反射可以根据方法名称,程序可以在运行时,动态地调用对象的方法(即使方法在编写程序时还没有定义)
  • 访问成员变量:反射可以根据成员变量名称,程序可以在运行时,访问和修改成员变量(反射可以访问私有成员变量)
  • 运行时类型信息:反射允许程序在运行时,查询对象的类型信息,这对于编写通用的代码和库非常有用;

                Spring 框架使用反射来自动装配组件,实现依赖注入;

                MyBatis 框架使用反射来创建resultType 对象,封装数据查询结果;

三、获取Class对象

        反射的第一步是获取 Class 对象。Class 对象表示某个类的元数据,可以通过以下几种方式获取:

  1. //获取Class类型信息
  2. public class Text02 {
  3. public static void main(String[] args) throws ClassNotFoundException {
  4. //方式1:通过类名
  5. Class stringClass1 = String.class;
  6. //方式2:通过Class类的forName()方法
  7. Class stringClass2 = Class.forName("java.lang.String");
  8. //方式3:通过对象调用getClass()方法
  9. Class stringClass3 = "".getClass();
  10. System.out.println(stringClass1.hashCode());//1604839423
  11. System.out.println(stringClass2.hashCode());//1604839423
  12. System.out.println(stringClass3.hashCode());//1604839423
  13. }
  14. }

四、Class类型的对象使用场景1

        将一个 JSON 字符串解析为 Java 对象,并输出该对象的字段值。

  1. //Class类型的对象使用场景1
  2. public class Text03 {
  3. public static void main(String[] args) {
  4. String json= "{\"name\":\"长安荔枝\",\"favCount\":234}";
  5. //方法定义
  6. Document doc=JSON.parseObject(json,Document.class);
  7. System.out.println(doc.getName());
  8. System.out.println(doc.getFavCount());
  9. }
  10. }

         使用 JSON.parseObject 方法将 JSON 字符串解析为 Document 类的对象。在解析过程中,JSON 字符串中的数据会自动映射到 Document 类的对应字段中。

五、Class类型的对象使用场景2

        通过 Class 对象在运行时获取一个类的相关信息,包括类名、包名、成员变量(字段)、成员方法等。

  1. //Class类型的对象使用场景2
  2. //获取丰富的类型内容
  3. public class Text04 {
  4. public static void main(String[] args) throws ClassNotFoundException {
  5. Class clz = Class.forName("java.util.HashMap");
  6. //获取类名
  7. System.out.println("完全限定名:"+clz.getName());
  8. System.out.println("简单的类名:"+clz.getSimpleName());
  9. //获取包名
  10. System.out.println("package"+clz.getPackage().getName());
  11. System.out.println();
  12. //获取成员变量
  13. Field[] fieldArray =clz.getDeclaredFields();
  14. System.out.println("成员变量(字段)");
  15. for(Field field:fieldArray) {
  16. System.out.println(field);
  17. }
  18. System.out.println();
  19. //获取成员方法
  20. Method[] methodArray = clz.getDeclaredMethods();
  21. System.out.println("成员方法");
  22. for(Method method:methodArray) {
  23. System.out.println(method);
  24. }
  25. }
  26. }
  • clz.getName() 返回类的完全限定名,包括包名,例如 "java.util.HashMap"。
  • clz.getSimpleName() 返回类的简单名称,不包括包名,例如 "HashMap"。
  • clz.getPackage().getName() 返回类所属的包名,例如 "java.util"。
  • clz.getDeclaredFields() 返回一个 Field 数组,包含了类声明的所有字段(包括私有字段)。
  • clz.getDeclaredMethods() 返回一个 Method 数组,包含了类声明的所有方法(包括私有方法)。

六、通过反射创建对象

方式一:通过 Class 对象直接调用 newInstance() 方法

方式二:通过获取构造方法(Constructor)来创建对象。

  1. //通过反射的方式,创建对象
  2. public class Text05 {
  3. public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException {
  4. Class clz = Class.forName("com.apesource.demo01.Document");
  5. //方式1:直接通过Class对象,调用newInstance()方法
  6. Object objx = clz.newInstance();//相当于在执行无参构造方法
  7. //方式2:通过构造器(构造方法)
  8. //无参构造方法
  9. Constructor constructor1 = clz.getDeclaredConstructor();//获取无参构造方法
  10. System.out.println(constructor1);
  11. Object obj1 = constructor1.newInstance();//执行构造器(构造方法),创建对象
  12. //有参构造方法
  13. Constructor constructor2 = clz.getDeclaredConstructor(String.class);//获取有参构造方法
  14. System.out.println(constructor2);
  15. Object obj2 = constructor2.newInstance("两京十五日");
  16. Constructor constructor3 = clz.getDeclaredConstructor(int.class);//获取有参构造方法
  17. System.out.println(constructor3);
  18. Object obj3 = constructor3.newInstance(34);
  19. Constructor constructor4 = clz.getDeclaredConstructor(String.class,int.class);//获取有参构造方法
  20. System.out.println(constructor4);
  21. Object obj4 = constructor4.newInstance("风起陇西",64);
  22. System.out.println(objx);
  23. System.out.println(obj1);
  24. System.out.println(obj2);
  25. System.out.println(obj3);
  26. System.out.println(obj4);
  27. }
  • newInstance() 方法是 Class 对象提供的一个方法,它调用类的无参构造方法来创建类的实例。
  • 注意:这个方法在 Java 9 以后已经被弃用,推荐使用 Constructor 对象来创建实例。
  • 通过 getDeclaredConstructor() 方法获取 Document 类的无参构造方法,然后调用 newInstance() 方法创建实例。
  • 注意:如果类中没有无参构造方法,调用 getDeclaredConstructor() 会抛出 NoSuchMethodException。
  • 通过 getDeclaredConstructor(String.class) 获取带有一个 String 参数的构造方法,并传入 "两京十五日" 作为参数来创建对象。
  • 通过 getDeclaredConstructor(int.class) 获取带有一个 int 参数的构造方法,并传入 34 作为参数来创建对象。

七、使用 Java 反射机制获取和调用类的构造方法,访问私有构造方法并创建对象

  1. public class Text06 {
  2. public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
  3. Class clz = Class.forName("com.apesource.demo01.Document");
  4. //获取一组构造器
  5. Constructor[] constructorArray1 = clz.getConstructors();//public
  6. Constructor[] constructorArray2 = clz.getDeclaredConstructors();//public、private
  7. //获取指定构造器
  8. Constructor constructor1 = clz.getConstructor();
  9. Constructor constructor2 = clz.getDeclaredConstructor(String.class);
  10. System.out.println(constructor1);
  11. System.out.println(constructor2);
  12. //调用私有构造器,必须设置它的访问全限
  13. constructor2.setAccessible(true);
  14. //调用构造器,创建对象
  15. Object obj = constructor2.newInstance("长安三万里");
  16. System.out.println(obj);
  17. }
  18. }
  • getConstructors() 方法返回一个包含所有公共(public)构造方法的数组。如果类中没有 public 构造方法,则返回空数组。
  • getDeclaredConstructors() 方法返回一个包含所有声明的构造方法的数组(包括私有的、受保护的和默认访问级别的构造方法)。
  • getConstructor() 方法用于获取类的无参构造方法(必须是 public 的)。如果没有无参构造方法或者不是 public,则抛出 NoSuchMethodException。
  • getDeclaredConstructor(Class... parameterTypes) 方法用于获取指定参数类型的构造方法。这里通过传入 String.class 参数获取一个带有 String 参数的构造方法。这个构造方法可以是任何访问级别(public、private、protected、默认)。
  • setAccessible(true) 用于绕过 Java 访问控制机制,使私有构造方法也可以被调用。如果不设置 Accessible 为 true,那么调用私有构造方法时会抛出 IllegalAccessException。
  • newInstance(Object... initargs) 方法使用指定的构造方法创建对象。这里调用了带有 String 参数的构造方法,并传入 "长安三万里" 作为参数。

八、通过反射,访问并使用成员方法

  1. public class Text08 {
  2. public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException {
  3. //硬编码的方式
  4. // Document doc1 = new Document();
  5. // doc1.setName("海底两万里");
  6. // doc1.setFavCount(10025);
  7. //反射的方式
  8. Class clz = Class.forName("com.apesource.demo01.Document");//获取类型信息
  9. Object doc1 = clz.newInstance();//创建对象
  10. //获取指定名称和参数类型的方法
  11. Method setNameMethod = clz.getMethod("setName", String.class);
  12. Method setFavCountMethod = clz.getMethod("setFavCount", int.class);
  13. //执行方法
  14. //doc1.setName("海底两万里");
  15. setNameMethod.invoke(doc1, "海底两万里");
  16. //doc1.setFavCount(10025);
  17. setFavCountMethod.invoke(doc1, 10025);
  18. System.out.println(doc1);
  19. }
  20. }
  • getMethod(String name, Class... parameterTypes) 方法用于获取类的某个 public 方法。方法名称和参数类型必须匹配才能成功获取方法。
  • invoke(Object obj, Object... args) 方法用于调用指定的实例方法。
  • setNameMethod.invoke(doc1, "海底两万里"); 等同于 doc1.setName("海底两万里");。
  • setFavCountMethod.invoke(doc1, 10025); 等同于 doc1.setFavCount(10025);。

九、通过反射,调用静态方法以及处理可变参数

  1. public class Text09_01 {
  2. public static void main(String[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException, ClassNotFoundException {
  3. //硬编码的方式
  4. //调用静态方法
  5. // Document.dosth();
  6. String ret1 = String.format("HashMap的默认初始容量是%d,加载因子是%.2f", 16,0.75f);
  7. System.out.println(ret1);
  8. //反射的方式
  9. // Class clz = Class.forName("com.apesource.demo01.Document");
  10. // Method dosthMethod = clz.getMethod("dosth");
  11. // dosthMethod.invoke(null);
  12. Class clz = String.class;
  13. Method formatMethod = clz.getMethod("format", String.class,Object[].class);
  14. String ret2 = formatMethod.invoke(null, "HashMap的默认初始容量是%d,加载因子是%.2f",new Object[] {16,0.75f}).toString();
  15. System.out.println(ret2);
  16. }
  17. }
  • 这是直接调用静态方法的传统方式。假设 Document 类有一个名为 dosth() 的静态方法,可以直接使用类名调用。
  • String.format 是一个静态方法,用于格式化字符串,类似于 printf 的格式化规则
  • 获取 String 类的 Class 对象:使用 Class clz = String.class;。
  • 获取 String 类的 Class 对象:使用 Class clz = String.class;。
  • 调用静态方法:使用 invoke(null, "HashMap的默认初始容量是%d,加载因子是%.2f", new Object[] {16, 0.75f}) 调用静态方法,因为 format 是静态方法,所以第一个参数是 null。
  • 注意invoke 方法中,Object[] 参数必须以数组形式传递,所以用了 new Object[] {16, 0.75f}。

十、反射的性能问题

        反射虽然功能强大,但由于是在运行时动态操作类,因此性能相对较低。此外,反射也会破

坏封装性,使用时要谨慎。

十一、反射的安全性

        使用反射时需要注意安全问题,因为它可以绕过 Java 的访问控制机制。例如,可以访问私有

字段或方法,因此在开发中使用反射要特别小心。

十二、反射的常见场景

  • 框架开发:如 Spring 中的依赖注入、Hibernate 中的 ORM 等。
  • 调试工具:如 Java 的调试器、分析工具等。
  • 动态代理:在 Java 中,动态代理依赖于反射。
注:本文转载自blog.csdn.net的的的小白的文章"https://blog.csdn.net/m0_64481525/article/details/142066836"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

107
Java
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2025 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top