Java中的反射机制

1.反射是什么

Java反射是框架的灵魂,大量框架底层都用到了反射机制

,例如Spring....

Java反射是在运行状态时,可以构造任何一个类的对象,获取到任意一个对象所属的类信息,以及这个类的成员变量或者方法,可以调用任意一个对象的属性或者方法。可以理解为具备了动态加载对象以及对对象的基本信息进行剖析和使用的能力的一种机制。

 Class 是 java JDK 提供的一个类,完整路径为 java.lang.Class,本质上与 Math, String 或者你自己定义各种类没什么区别

对于每一种类,Java 虚拟机都会初始化出一个 Class 类型的实例,每当我们编写并且编译一个新创建的类就会产生一个对应 Class 对象,并且这个 Class 对象会被保存在同名 .class 文件里。当我们 new 一个新对象或者引用静态成员变量时,Java 虚拟机(JVM)中的类加载器系统会将对应 Class 对象加载到 JVM 中,然后 JVM 再根据这个类型信息相关的Class 对象创建我们需要实例对象或者提供静态变量的引用值。
比如创建编译一个 Shapes 类,那么,JVM 就会创建一个 Person 对应 Class 类的 Class实例,该 Class 实例保存了 Person 类相关的类型信息,包括属性,方法,构造方法等等,通过这个 Class 实例可以在运行时访问 Person 对象的属性和方法等。另外通过 Class类还可以创建出一个新的 Person 对象。这就是反射能够实现的原因,可以说 Class 是反射操作的基础。
需要特别注意的是,每个 class(注意 class 是小写,代表普通类)类,无论创建多少个实例对象,在 JVM 中都对应同一个 Class 对象。
 
举个例子来帮助理解:假设有一个名为Person的类,我们可以通过Person.class来获取表示Person类的Class对象。无论我们创建多少个Person类的实例,比如person1、person2,它们都共享同一个Person.class对象。这意味着Person.class对象包含了Person类的结构信息,如字段、方法等,而不是特定实例对象的数据。这种设计使得Java的反射机制能够在运行时获取和操作类的信息。
 
作者:Shepherd
链接:https://www.zhihu.com/question/640160670/answer/3410651673
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

2.反射的实现

1)获取Class对象的三种方式:

  • Class.forName("全类名"):将字节码文件加载进内存,返回Class对象
  • 类名.class:通过类名的属性
  • class获取对象.getClass():getClass()方法在Object类中定义着。
        /**
         获取Class对象的方式:
         1.Class.forName("全类名"):将字节码文件加载进内存,返回Class对象
         2.类名.class:通过类名的属性class获取
         3.对象.getClass():getClass()方法在Object类中定义着。
         */
        //1.Class.forName("全类名")
        Class cls1 = Class.forName("com.shepherd.reflect.Person");
        System.out.println(cls1);
        //2.类名.class
        Class cls2 = Person.class;
        System.out.println(cls2);
        //3.对象.getClass()
        Person p = new Person();
        Class cls3 = p.getClass();
        System.out.println(cls3);
        //==比较三个对象
        System.out.println(cls1==cls2);//true
        System.out.println(cls1==cls3);//true
Class  c = Student.class;
        System.out.println(c);
        System.out.println(c==cls1);//false
这里需要注意:xxx.getFields()方法默认情况下,会返回本类、父类、父接口的公有属性,而xxx.getDeclaredFields()返回本类的所有属性,包括私有的属性。同理,反射API中其他getXXX和getDeclaredXXX的用法类似。

对于 Member 接口可能会有人不清楚是干什么的,但如果提到实现它的三个实现类,估计用过反射的人都能知道。我们知道类成员主要包括构造函数,变量和方法,Java 中的操作基本都和这三者相关,而 Member 的这三个实现类就分别对应他们。

java.lang.reflect.Field :对应类变量
java.lang.reflect.Method :对应类方法
java.lang.reflect.Constructor :对应类构造函数

反射的缺点

  • 性能开销
    反射涉及类型动态解析,所以 JVM 无法对这些代码进行优化。因此,反射操作的效率要比那些非反射操作低得多。我们应该避免在经常被执行的代码或对性能要求很高的程序中使用反射。
  • 安全限制
    使用反射技术要求程序必须在一个没有安全限制的环境中运行。如果一个程序必须在有安全限制的环境中运行,如 Applet,那么这就是个问题了。
  • 内部曝光
    由于反射允许代码执行一些在正常情况下不被允许的操作(比如访问私有的属性和方法),所以使用反射可能会导致意料之外的副作用--代码有功能上的错误,降低可移植性。反射代码破坏了抽象性,因此当平台发生改变的时候,代码的行为就有可能也随着变化。
posted @ 2024-03-01 14:09  予真  阅读(2)  评论(0编辑  收藏  举报