【java进阶之反射】

一、什么是反射

Java的反射(reflection)机制是指在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类的成员变量和方法,可以调用任意一个对象的属性和方法。这种动态获取程序信息以及动态调用对象的功能称为Java语言的反射机制。反射被视为动态语言的关键。

二、 为什么会有反射,反射解决了什么问题

Java中编译类型有两种:

  • . 静态编译:在编译时确定类型,绑定对象即通过。
  • 动态编译:运行时确定类型,绑定对象。动态编译最大限度地发挥了Java的灵活性,体现了多态的应用,可以减低类之间的耦合性。

Java反射是Java被视为动态(或准动态)语言的一个关键性质。这个机制允许程序在运行时透过Reflection APIs取得任何一个已知名称的class的内部信息,包括其modifiers(诸如public、static等)、superclass(例如Object)、实现之interfaces(例如Cloneable),也包括fields和methods的所有信息,并可于运行时改变fields内容或唤起methods。

Reflection可以在运行时加载、探知、使用编译期间完全未知的classes。即Java程序可以加载一个运行时才得知名称的class,获取其完整构造,并生成其对象实体、或对其fields设值、或唤起其methods。

反射(reflection)允许静态语言在运行时(runtime)检查、修改程序的结构与行为。
在静态语言中,使用一个变量时,必须知道它的类型。在Java中,变量的类型信息在编译时都保存到了class文件中,这样在运行时才能保证准确无误;换句话说,程序在运行时的行为都是固定的。如果想在运行时改变,就需要反射这东西了。

实现Java反射机制的类都位于java.lang.reflect包中:

  • Class类:代表一个类
  • Field类:代表类的成员变量(类的属性)
  • Method类:代表类的方法
  • Constructor类:代表类的构造方法
  • Array类:提供了动态创建数组,以及访问数组的元素的静态方法
    一句话概括就是使用反射可以赋予jvm动态编译的能力,否则类的元数据信息只能用静态编译的方式实现,例如热加载,Tomcat的classloader等等都没法支持。

三、反射的使用

1、获取Class对象

package com.luyu.test;

import java.lang.Class;
/**
 * @Author luyu
 * @create 2022/02/19
 */
public class test {

    public static void main(String[] args) throws Exception {
        //获取Class的三种方式
        //1.当类没有加载进内存时,通过Class.forName("全类名")-->包名.类名
        //将字节码文件加载进内存,返回class对象
        //*多用于配置文件,将类名定义在配置文件中,读取文件,加载类
        Class cla = Class.forName("com.luyu.test.Cat");
        System.out.println(cla);

        //2.当字节码已经加载进内存了,可以通过类名.class 来获取Class对象
        //*多用于参数传递
        Class catClass = Cat.class;
        System.out.println(catClass);

        //3.已经new 出来对象了,可以通过对象.getClass()方法来获取
        //*多用于对象的获取字节码的方式
        Cat cat = new Cat();
        Class aClass = cat.getClass();
        System.out.println(aClass);

        //三个class对象一样,可以用 == 运算符来判断
        System.out.println(cla == catClass);
        System.out.println(catClass == aClass);
    }
}

结果
在这里插入图片描述

结论:同一个字节码文件(*.class)在一次编译运行过程中,只会加载一次,不论通过哪种方式获取,都是同一个.

2.class对象的功能
(1)获取成员变量们(Field)

package com.luyu.test;

import java.lang.reflect.Field;

/**
* @Author luyu
* @create 2022/2/19 14:17
*/
public class Demo2 {
  public static void main(String[] args) throws Exception {
      Class cls = Cat.class;

      //一.获取成员变量们
      //1.class.getField(String name)通过指定名称获取public修饰成员变量
      Field name = cls.getField("name");
      System.out.println(name);
      System.out.println("-----------");

      //2.class.getFields()获取所有public修饰的成员变量
      Field[] fields = cls.getFields();
      for (Field field : fields) {
          System.out.println(field);
      }
      System.out.println("-----------");

      //获取到成员变量后
      //获取值 参数是一个对象
      Cat cat = new Cat();
      Object o = name.get(cat);
      System.out.println(o);
      //设置值
      name.set(cat,"旺财");
      System.out.println(cat);
      System.out.println("-----------");

      //3.class.getDeclaredFields() 获取所以成员变量,且不考虑修饰符
      Field[] declaredFields = cls.getDeclaredFields();
      for (Field declaredField : declaredFields) {
          System.out.println(declaredField);
      }
      System.out.println("-----------");

      //4.class.getDeclaredField(String values) 获取所以成员变量,且不考虑修饰符
      Field age = cls.getDeclaredField("age");
      //私有成员变量不能直接访问
      //.setAccessible 设置忽略访问权限修饰符的安全检查
      //暴力反射
      age.setAccessible(true);
      Object o1 = age.get(cat);
      System.out.println(age);
      System.out.println(o1);
      System.out.println("-----------");
  }
}

结果:
结果
(2)获取成员方法们(Constructor)

package com.luyu.test;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

/**
* @Author luyu
* @create 2022/2/19 15:02
*/
public class Demo3 {
  public static void main(String[] args) throws Exception {
      Class cls = Cat.class;


      /*
       * *class.getConstructor(类<?>... parameterType);
       * *class.getConstructors();
       *
       * *class.getDeclaredConstructor(类<?>... parameterType);
       * *class.getDeclaredConstructors();
       *
       */
      //通过参数传递获取对应的构造方法,返回对应的构造器
      //构造方法是用来创建对象的
      //有参
      Constructor constructor = cls.getConstructor(String.class, int.class);
      System.out.println(constructor);
      System.out.println("------");

      //创建对象
      Object cat = constructor.newInstance("旺财", 18);
      System.out.println(cat);
      System.out.println("------");

      //无参
      Constructor constructor1 = cls.getConstructor();
      System.out.println(constructor);
      System.out.println("------");

      //创建对象
      Object cat1 = constructor1.newInstance();
      System.out.println(cat1);
      System.out.println("------");

      //无参构造创建对象可以用以下方法快捷创建
      Object o = cls.newInstance();
      System.out.println(o);

  }
}

结果:
反射获取构造方法结果

(3)获取构造方法们(Method)

package com.luyu.test;

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

/**
* @Author luyu
* @create 2022/2/19 15:18
*/
public class Demo4 {
  public static void main(String[] args) throws Exception {
      Class cls = Cat.class;

      /*
       * *class.getMethod(String name, Class<?>... parameterTypes);
       * *class.getMethods();
       *
       * *class.getDeclaredMethod(String name, Class<?>... parameterTypes);
       * *class.getDeclaredMethods();
       *
       */

      //通过方法名获取Method对象,有参数的方法,还需要传参数
      Method say = cls.getMethod("say");
      //执行方法之前需要创建对象
      Cat cat = new Cat();
      say.invoke(cat);
      System.out.println("----------");

      Method say2 = cls.getMethod("say",String.class);
      //执行方法
      say2.invoke(cat,"旺财:");
      System.out.println("----------");

      //获取所有public修饰的方法
      Method[] methods = cls.getMethods();
      //methods里还有继承Object的方法
      //获取方法的名称getName()
      for (Method method : methods) {
          System.out.println(method.getName());
          System.out.println(method);
      }
      
  }
}

结果:
在这里插入图片描述

(4)获取类名
------->获取的类名为全类名

        //获取类名
        System.out.println("----------");
        String name = cls.getName();
        System.out.println(name);

结果:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值