栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

java反射

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

java反射

反射

【文档】
https://www.cnblogs.com/chanshuyi/p/head_first_of_reflection.html
https://www.jianshu.com/p/9ffe9347b087

【反射是啥】
“正射”:在编译期,未运行时就已经确定了要运行的类(Apple)
反射:就是在运行时才知道要操作的类是什么,并且可以在运行时获取类的完整构造,并调用对应的方法

【反射应用】
例如我们经常使用的 Spring 配置中,经常会有相关 Bean 的配置:



当我们在 XML 文件中配置了上面这段配置之后,Spring 便会在启动的时候利用反射去加载对应的 Apple 类。而当 Apple 类不存在或发生启发异常时,异常堆栈便会将异常指向调用的 invoke 方法。从这里可以看出,我们平常很多框架都使用了反射,而反射中最最终的就是 Method 类的 invoke 方法了。

【反射原理】
总:

细节:

在深层的 NativeMethodAccessorImpl 的 invoke 方法里,其会判断调用次数是否超过阀值(numInvocations)。如果超过该阀值,那么就会生成另一个MethodAccessor 对象,并将原来 DelegatingMethodAccessorImpl 对象中的 delegate 属性指向最新的 MethodAccessor 对象。

到这里,其实我们可以知道 MethodAccessor 对象其实就是具体去生成反射类的入口(具体如NativeMethodAccessorImpl、DelegatingMethodAccessorImpl)。通过查看源码上的注释,我们可以了解到 MethodAccessor 对象的一些设计信息,就像注释里说的,实际的 MethodAccessor 实现有两个版本,一个是 Native 版本,一个是 Java 版本:

Native 版本一开始启动快,但是随着运行时间边长,速度变慢。Java 版本一开始加载慢,但是随着运行时间边长,速度变快。正是因为两种存在这些问题,所以第一次加载的时候我们会发现使用的是 NativeMethodAccessorImpl 的实现,而当反射调用次数超过 15 次之后,则使用 MethodAccessorGenerator 生成的 MethodAccessorImpl 对象去实现反射。

【java静态语言但能支持动态】
java最初设计包括到现在的口径都是静态语言,即编译时需要做类型检查,好让一次编译,多次运行。但为了能支持动态,让类型检查在运行时才做的,需要动态绑定支持,虽然Java是静态语言,但是为了支持面向对象的各种特性,特意加入的动态语言的特性,于是就有了多态、继承。

注意的是,这里的动态绑定是指Java判断所引用对象的实际类型,根据其实际类型调用其相应的方法。听起来有点虚,针对下列语句,怎么知道是老爸说话还是儿子说法呢?

//继承或多态
public int exec(Father reference)  {
  reference.talk();
}
Father f = new Son();
Father f2 = new Father();
exec(f);
exec(f2);

上述情景,JVM如何知道是Father.taslk()还是Son.talk()?

  • 在编译时,直接默认是老爸说话(编译时默认父类),就是默认Father.talk()以安全的编译通过。
  • 但是在运行时,在当前线程栈中找到对象引用f的真正内存地址,地址指向堆,这个对象实例在堆中,对象实例中存放着Class信息,所以回去方法区找这个对象对应的Class对象,并在Class对象中找到里面的方法表,如果子类重写了父类的方法表,必定指向子类的方法代码块,这个就是动态绑定的概念。所以不管是多态还是继承,只要确保实际对象的方法调用是对的,java就不会调用错。
    (JDK1.6及以下:Class对象在方法区,JDK1.6以上则在堆)

    上图的红色线就是动态绑定的过程,黑色线是应用启动加载Class对象的过程

【RTTI】
动态绑定需要用到方法区的Class对象,也叫RTTI。

RTTI(run-time type information)指的是Java在运行时能够获得或判断某个对象的类型信息。
RTTI就是基于方法区的Class对象实现的,所谓的获得或判断某个对象的类型信息,就是来自于Class对象。

目前网上大多数的理解结论是错的,但是方向是对的,RTTI机制会分为传统RTTI和反射两大类。

RTTI的核心不在于形式,两者的区别只在于如何去操作Class对象,应该从操作方式作为区分!

  • 传统RTTI:继承,多态和强转,是依赖已经存在的对象实例获得其中的Class对象。
  • 反射:除了可以根据已经存在的对象实例获得其中的Class对象,也可以直接根据名字去方法区直接找Class对象。

【传统RTTI vs 反射】
传统RTTI必须要有对象实例 -> 意味着必须有Class对象 -> 意味着必须对该类有正确的引用 -> 意味着编译期该类文件存在且编译通过,以上种种,反射可以都不需要!(类文件不存在都行,要用的时候才会报错)

【RTTI支撑着反射】
结论:RTTI机制支撑着反射
回过头来看反射的三种实现方式,统统都是需要Class对象支撑的,也就是RTTI机制。

RTTI机制的引入为Java这种静态语言带来了动态语言的特性,在不改变整体设计的情况下,提升了代码抽象能力和灵活性。

一般不要认为Java的反射就是指java.lang.reflect,这个包提供的工具类和接口。其实Java的整个Class对象系统,包括所有类的始祖类Object类,基础类型以及每个对象都附带的Class对象,都是反射机制的一部分。Java最初在设计这个系统的时候就有很深的预谋,反射可以调动着Java核心资源Class对象。

当我们编写完一个Java项目之后,每个.java文件都会被编译成一个.class文件,这些文件承载了这个类的所有信息,包括父类、接口、构造函数、方法、属性等。
这些Class文件在程序运行时会被ClassLoader加载到虚拟机中,Java虚拟机就会在内存中自动产生一个Class对象。
我们通过new的形式创建对象实际上就是通过这些Class对象来创建,只是这个过程对于我们是不透明的而已。
反射的工作原理就是借助Class.java、Constructor.java、Method.java、Field.java这四个类在程序运行时动态访问和修改任何类的行为和状态。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/532054.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号