• JDK1.5 新特性【反射】


    前言

            今天复习一下反射,说是复习,基本上已经忘干净了,只知道用Spring、Mybatis、JavaFX 的时候加个注解,具体原理就不知道了。所以必须再深入学习一下。

    1、设计一个框架?

    设计一个框架需要什么技术?

    反射机制、自定义注解、设计模式、AOP技术、Netty、Spring 架构、SpringBoot 自定义插件、多线程或 JUC。

    2、反射技术

    2.1、概念

    • Java中的反射是指程序在运行时动态地获取类的信息(比如方法信息、注解信息、方法参数、类的属性等)以及操作类的成员变量、方法和构造方法的能力。
    • 通过反射,可以在运行时检查类的属性和方法,获取类的构造函数并实例化对象,调用类的成员变量和方法,甚至可以在运行时动态地生成新的类,这使得Java程序具有更大的灵活性和动态性。
    • 但是,反射机制也会导致一些性能上的问题,因为反射调用的速度通常比直接调用要慢得多。

    反射机制的核心是在运行时动态地获取类的信息,并通过这些信息来调用类的成员变量和方法,这种能力使得Java程序可以在运行时动态地加载和执行代码,从而实现更加灵活和动态的功能。 

    2.2、Java中反射的主要API

    • Class类:用于表示Java类的信息,包括类的名称、父类、接口、构造函数、成员变量和方法等。
    • Constructor类:用于表示Java类的构造函数信息。
    • Method类:用于表示Java类的方法信息。
    • Field类:代表类的成员变量

    2.3、应用场景

    • JDBC 加载驱动 Class.forName("com.mysql.cj.jdbc.Driver")
    • Spring 容器框架 IOC 实例化对象
    • 自定义注解生效(反射+AOP)
    • 第三方核心的框架
    • 在 Spring 中每个 Bean 的对象都是通过反射技术来初始化的。
    • 以及在之前 Hadoop 的学习中,当我们自定义的对象需要序列化的时候,我们说必须要有无参构造方法,因为反序列化需要反射调用无参构造函数。

    3、使用反射初始化对象

    我们以往的学习经历告诉我们,初始化对象的方式无非就是直接 new:

    User user = new User();

    下面给出两种通过反射初始化对象的方式: 

    3.1、通过反射实现无参构造

    原理:Class 对象的 newInstance 方法会默认执行我们的无参构造方法来初始化对象(所以在定义一个 JavaBean的时候一定要记得写无参构造的方法)。

    1. // 通过反射调用无参构造来初始化对象
    2. Class aClass = Class.forName("kt.pojo.User");
    3. // newInstance() 默认执行到我们的无参构造方法来初始化对象
    4. User user = (User) aClass.newInstance();
    5. System.out.println(user);

    3.2、通过反射实现有参构造

    3.2.1、一个标准的 JavaBean

    1. package kt.pojo;
    2. import java.util.Objects;
    3. public class User {
    4. public String name;
    5. public Integer age;
    6. public User(){}
    7. public User(String name, Integer age) {
    8. this.name = name;
    9. this.age = age;
    10. }
    11. @Override
    12. public String toString() {
    13. return "User{" +
    14. "name='" + name + '\'' +
    15. ", age=" + age +
    16. '}';
    17. }
    18. @Override
    19. public boolean equals(Object o) {
    20. if (this == o) return true;
    21. if (o == null || getClass() != o.getClass()) return false;
    22. User user = (User) o;
    23. return age.equals(user.age) && Objects.equals(name, user.name);
    24. }
    25. @Override
    26. public int hashCode() {
    27. return Objects.hash(name, age);
    28. }
    29. public String getName() {
    30. return name;
    31. }
    32. public void setName(String name) {
    33. this.name = name;
    34. }
    35. public int getAge() {
    36. return age;
    37. }
    38. public void setAge(Integer age) {
    39. this.age = age;
    40. }
    41. }

    注意:这里的 age 属性类型也可以用 int ,区别就是 int 的默认值为 0,Integer 的默认值为 null。

    输出结果:

    User{name='null', age=null}

    3.2.2、有参构造实现 

    通过我们 Class 对象来获取我们的构造器对象 Constructor,然后调用 Constructor 对象的 newInstacne 方法来实现有参构造。

    注意:如果 age 属性类型是 int,那么 getConstructor 的第二个参数应该是 int.class 。 

    1. // 通过反射调用有参构造来初始化对象
    2. Class aClass = Class.forName("kt.pojo.User");
    3. // 通过反射调用有参构造来初始化对象
    4. Constructor constructor = aClass.getConstructor(String.class, Integer.class);
    5. User tom = (User) constructor.newInstance("tom", 10);
    6. System.out.println(tom);

    输出结果:

    User{name='tom', age=10}

    4、使用反射给对象的属性赋值

    4.1、通过对象给属性赋值

    我们通过反射获取到对象,然后调用对象的方法来赋值(必须保证对象的 setter 方法是 public 的):

    1. User user = (User) aClass.newInstance();
    2. user.setName("tom");
    3. user.setAge(10);
    4. System.out.println(user);

    运行结果:

    User{name='tom', age=10}

    4.2、通过反射给属性赋值

    通过反射获取到 Class 对象,再调用 Class 对象的 getDeclareField 方法获得指定属性的属性对象,最后通过属性的 set 方法来实现赋值:

    1. User user = (User) aClass.newInstance();
    2. // aClass.getField(); //这个方法会把我们 User 类的父类(这里是Object)中的属性页获取到
    3. Field name = aClass.getDeclaredField("name");
    4. name.setAccessible(true); // 如果属性是私有的(private) 就需要添加访问权限
    5. Field age = aClass.getDeclaredField("age");
    6. age.setAccessible(true); // 如果属性是私有的(private) 就需要添加访问权限
    7. name.set(user,"tom");
    8. age.set(user,10);
    9. System.out.println(user);

    注意:

    • JavaBean 中的属性如果是私有的需要调用属性对象(Field)的 setAccessible 方法传进一个 true 来使得属性可访问。
    • 如果需要使用该对象父类的属性的话,可以使用 getField 方法。

    5、通过反射调用方法

    我们在上面的 User 类中添加一个 sayHello 方法:

    1. public void sayHello(String name){
    2. System.out.println("hello "+name);
    3. }

    通过 Class 对象的 getDeclaredMethod 方法获取到指定的方法对象 Method,最后调用 Method 对象的 invoke 方法(需要传入执行该方法的对象和需要的参数):

    1. Class aClass = Class.forName("kt.pojo.User");
    2. User user = (User)aClass.newInstance();
    3. Method toString = aClass.getDeclaredMethod("sayHello", String.class);
    4. toString.invoke(user,"Tom");

    运行结果:

    hello Tom

  • 相关阅读:
    【Java基础】StringBuilder类概述及字符串拼接、反转升级版案例
    Redis 源码简洁剖析 13 - RDB 文件
    oracle中获取连续几天最低数据
    vue中加载OCX控件(IE浏览器执行)
    8.0、软件测试——缺陷(定义和标准)
    高并发与秒杀实战
    【node进阶】深入浅出websocket即时通讯(二)-实现简易的群聊&私聊
    jsp简单实现新闻发布系统中用户注册确认和用户模拟登录功能的开发
    docker&kubernets篇(二十三)
    RCC目前最近技术与今后发展
  • 原文地址:https://blog.csdn.net/m0_64261982/article/details/134493360