Java反射详解

Java反射详解

    • 获取类的字节码
    • 反射获取里的构造器
      • 反射获取类构造器的作用
    • 反射获取成员变量
    • 反射获取成员方法

反射技术,指的是加载类的字节码到内存,并以编程的方法解刨出类中的各个成分(成员变量、方法、构造器等)。

由于Java的设计原则是万物皆对象,获取到的类其实也是以对象的形式体现的,叫字节码对象,用Class类来表示。获取到字节码对象之后,再通过字节码对象就可以获取到类的组成成分了,这些组成成分其实也是对象,其中每一个成员变量用Field类的对象来表示每一个成员方法用Method类的对象来表示每一个构造器用Constructor类的对象来表示

在这里插入图片描述

获取类的字节码

反射的第一步:是将字节码加载到内存,我们需要获取到的字节码对象。

在这里插入图片描述

  • 获取类字节码的方式有三种:

    1. 通过类名获取: 这是最常用的方式,每个类都有一个名为 “class” 的静态成员变量,可以直接通过类名来获取。

      // 1、方法一:通过类名获取类字节码
      Class<Student> stringClass = Student.class;
      System.out.println(stringClass.getName());            //获取全类名
      System.out.println(stringClass.getSimpleName());     //获取简单类名
      
    2. **通过对象获取:**每个对象都有一个getClass()方法,可以通过这个方法获取对象所属的字节码。

      // 2、方法二:通过对象获取
      Student student = new Student();
      Class<? extends Student> aClass = student.getClass();
      System.out.println(aClass.getName());            //获取全类名
      System.out.println(aClass.getSimpleName());     //获取简单类名
      
    3. **通过全限定类名获取:**如果我们只知道类的全限定名,可以使用Class类的静态方法 forName() 来获取字节码。

      // 3、方法三:通过全限定类名获取
      try {
          Class<?> aClass = Class.forName("com.liuyi.test.Student");
          System.out.println(aClass.getName());
          System.out.println(aClass.getSimpleName());
      } catch (ClassNotFoundException e) {
          throw new RuntimeException(e);
      }
      

      这种方式需要抛出 ClassNotFoundException 异常,需要使用try-catcch 语句块来处理。

反射获取里的构造器

获取构造器,需要用到Class类提供的几个方法,如下图所示:

在这里插入图片描述

想要快速记住这个方法的区别,按照规律来记就很方便了。

get:获取
Declared: 有这个单词表示可以获取任意一个,没有这个单词表示只能获取一个public修饰的
Constructor: 构造方法的意思
后缀s: 表示可以获取多个,没有后缀s只能获取一个

1、获取所以类的构造器

1)User类

public class User {
    private int id;
    private String name;
    private String password;

    public User() {
    }

    public User(int id, String name, String password) {
        this.id = id;
        this.name = name;
        this.password = password;
    }
}

2)编写测试方式来获取类中的所有的构造器

    @Test
    public void testGetConstructors(){
        // 1、反射第一步:必须先得到这个类的Class对象
        Class<User> userClass = User.class;

        // 2、获取类的全部构造器
        Constructor<?>[] declaredConstructors = userClass.getDeclaredConstructors();
        // 3、变量数组中的每一个构造器对象
        for (Constructor<?> constructor : declaredConstructors) {
            System.out.println(constructor.getName() + "-->参数个数" + constructor.getParameterCount());
        }
    }

打印输出的结果如下:

在这里插入图片描述

2、获取一个类构造器

    @Test
    public void testGetConstructor(){
        // 1、获取类的Class对象
        Class<User> userClass = User.class;

        // 2、获取类public修饰的构造器
        try {
            Constructor<User> constructor = userClass.getConstructor();
            System.out.println("public 修饰的构造器" + constructor.getName() + "-->参数个数:" + constructor.getParameterCount());
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }

        // 3、获取private修饰的有三个参数的构造器,第一个参数int类型,第二个参数Sting类型,第三个参数Sting类型
        try {
            Constructor<User> declaredConstructor = userClass.getDeclaredConstructor(int.class, String.class, String.class);
            System.out.println("private修饰的有三个参数的构造器:" + declaredConstructor.getName()
             + "-->参数个数:" + declaredConstructor.getParameterCount());;
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
    }

打印输出的结果如下:

在这里插入图片描述

反射获取类构造器的作用

获取到了Cat类中的构造器。获取到构造器后,我们就需要使用类构造器初始化对象并返回

这里我们需要用到如下的两个方法,注意:这两个方法时属于Constructor的,需要用Constructor对象来调用。

在这里插入图片描述

如下图所示,constructor1和constructor2分别表示Cat类中的两个构造器。现在我要把这两个构造器执行起来。

在这里插入图片描述

由于构造器是private修饰的,先需要调用setAccessible(true) 表示禁止检查访问控制,然后再调用newInstance(实参列表) 就可以执行构造器,完成对象的初始化了。

代码如下:为了看到构造器真的执行, 故意在两个构造器中分别加了两个打印语句

在这里插入图片描述

代码的执行结果如下图所示:

在这里插入图片描述

反射获取成员变量

在Class类中提供了获取成员变量的方法,如下图所示:

在这里插入图片描述

这些方法的记忆规则,如下:

get:获取
Declared: 有这个单词表示可以获取任意一个,没有这个单词表示只能获取一个public修饰的
Field: 成员变量的意思
后缀s: 表示可以获取多个,没有后缀s只能获取一个

1、获取成员变量

@Test
public void testGetFields(){
    Class<User> userClass = User.class;
    // 获取所有的成员变量
    Field[] declaredFields = userClass.getDeclaredFields();
    for (Field declaredField : declaredFields) {
        System.out.println(declaredField.getName() + "--->" + declaredField.getType());
    }

    System.out.println("================================");

    // 获取某个指定的成员变量
    try {
        Field name = userClass.getDeclaredField("name");
        System.out.println(name.getName() + "--->" + name.getType());
    } catch (NoSuchFieldException e) {
        throw new RuntimeException(e);
    }
}

在这里插入图片描述

2、使用成员变量

在Filed类中提供给给成员变量赋值和获取值的方法,如下图所示:

在这里插入图片描述

获取值的方法时Filed类的需要用Filed类的对象来调用,而且不管是设置值、还是获取值,都需要依赖于该变量所属的对象。代码如下:

@Test
public void testGetFields(){
    Class<User> userClass = User.class;
    try {
        // 获取类构造器
        Constructor<User> declaredConstructor = userClass.getDeclaredConstructor();
        declaredConstructor.setAccessible(true);   // 禁止访问控制权限
        User user = declaredConstructor.newInstance();
        // 获取指定的成员变量
        Field name = userClass.getDeclaredField("name");
        name.setAccessible(true);    // 禁止访问控制权限
        System.out.println(name.getName() + "--->" + name.getType());
        // 给成员变量赋值
        name.set(user,"张三");
        // 打印赋值的结果
        System.out.println(user);
    } catch (NoSuchFieldException | NoSuchMethodException | InstantiationException | IllegalAccessException |
             InvocationTargetException e) {
        throw new RuntimeException(e);
    }
}

在这里插入图片描述

反射获取成员方法

在Java中反射包中,每一个成员方法用Method对象来表示,通过Class类提供的方法可以获取类中的成员方法对象。如下图所示:

在这里插入图片描述

1、获取成员方法

@Test
public void testGetMethod(){
    Class<User> userClass = User.class;

    // 获取类中的全部成员方法
    Method[] methods = userClass.getDeclaredMethods();

    // 遍历这个数组中的每一个方法对象
    for (Method method : methods) {
        System.out.println(method.getName()+"-->"+method.getParameterCount()+"-->"+method.getReturnType());
    }
}

在这里插入图片描述

2、执行成员方法

在Method类中提供了方法,可以将方法自己执行起来。

在这里插入图片描述

@Test
public void testGetMethod(){
    Class<User> userClass = User.class;

    // 获取类中的全部成员方法
    try {
        // 获取类构造器
        Constructor<User> declaredConstructor = userClass.getDeclaredConstructor();
        declaredConstructor.setAccessible(true);   // 禁止访问控制权限
        User user = declaredConstructor.newInstance();
        Method run = userClass.getDeclaredMethod("run");
        run.setAccessible(true);    // 禁止访问控制权限
        // 执行
        run.invoke(user);
    } catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
        throw new RuntimeException(e);
    }
}

在这里插入图片描述

  • 14
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

‘༺༃修༒罗༃༻’

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值