Java反射机制

一、 前言

哈喽,小白啊里来了~ 我们都知道java反射机制即是重点也算是难点,并不是每个人都很理解。同时,反射机制是java实现动态语言的关键,也是通过反射实现类动态加载,并且框架的底层原理也基于反射。本文啊里将和大家分享自己对反射的理解。

二、通过一个需求引出反射

需求:根据配置文件re.properties指定信息:

classfullpath=com.agli.Cat

method=hi

去创建Cat对象且调用hi方法?

那根据上述需求,你会怎么去解决呢?

传统方式:

1、直接new对象,调用方法这种做法是会不符合OCP原则。(OCP原则即开闭原则:即通过外部文件配置,不修改源码来控制程序。)
2、Properties类读写配置文件:

new  Properties().
load(newFileInputStream(“xx\\re.properties”)).
get(“classfullpath”)

使用配置类是能获取属性值,但实现不了需求,会发现不能调用方法。

反射机制:

通过反射机制是可以解决的:

//加载类,返回类对象。
Class cls =Class.forName(“全类名”)//得到要加载Cat对象
Object o=cls.newInstance();
//获取方法对象
Method mth=cls.getMethod(“方法名”)//通过对象调用方法
mth.invoke(o);
三、反射

那通过上面那个需求可以发现,只有反射是可以在不修改源码就能完成创建对象和调用方法的。然后有小伙伴就会问了什么是反射呢?能不能说的能理解点呢?

那反射即加载完类后,堆中产生Class类型的对象(一个类只有一个Class对象),此对象包含了类的完整结构信息,然后通过类对象操作类。此对象即类似镜子。

四、反射机制原理

了解了反射的概念之后,我们谈谈它的原理,说到原理这个词可能就有些人会产生很蒙的一种状态,但其实认真去学习还是不难的鸭~

那Java程序在计算机中是有三个阶段的,直接上图:

在这里插入图片描述

一:编译阶段:

由源码.java —> 字节码.class

二:Class类阶段(加载阶段):

由类加载器ClassLoader —>(将字节码加载进堆内存中) 产生一个Class类对象 :加载过程即反射的体现

而被加载进来的类成员变量、构造器、成员方法等都被视作对象

三:Runtime运行阶段:

Cat c=new Cat();

c.hi();

Cat对象也会进堆区,且知道他属于哪个Class对象

Ps:当new一个对象时,同时堆区同时进行两步:

先:类加载器加载类对象进堆区(属于jvm底层操作)

后:对应的对象进入堆区

反射机制的原理:即在编译阶段到加载阶段中,类加载的一个过程,经过类加载这一过程,在堆中得到对应的Class对象和方法区中对应的二进制字节流数据。

在反射机制中的得到Class对象后,即可以通过类对象去创建对象、调用方法和操作属性等等。

五、反射的优缺点

凡事都是有两面性的,那反射机制也不例外。

优点:

灵活性:可以动态的创建和使用对象(即是框架底层的核心)。

缺点:

使用反射基本是解释执行,对执行的速度有影响。

对于反射缺点,也自然有优化的方式,这比较重要,面试很有可能会被问到,所以需要注意。

优化:关闭访问检查

通过调用Method、Field和Constructor对象的**setAccessible()**方法去启用或禁用访问安全检查,参数值为true时,取消访问检查,可提高反射效率。

六、类加载

在聊类加载之前我们要知道,反射机制是java实现动态语言的关键,也是通过反射实现类动态加载。

类加载有两种:
  • 静态加载:编译时加载相关的类,若没有则报错,依赖性太强。
  • 动态加载:运行时加载,若运行时不用该类,则不报错,降低依赖性。
类加载时机:
  1. new创建对象
  2. 当子类被加载时,父类也必须加载
  3. 调用类的静态成员时
  4. 反射 (除了反射之外,前三都为静态类加载)
类加载流程:

在这里插入图片描述

在这里插入图片描述

类加载分三个阶段

1.加载(Loading):

将字节码从不同的数据源(可能是class文件、jar包、甚至网络中的字节码)转化为二进制字节流加载到内存中,并生成一个代表该类的java.lang.Class对象。

2.连接(Linking):

2.1验证(verification):

验证文件格式(是否以魔数oxcafebabe开头)、元数据、字节码等

确保Class文件的字节流中包含的信息符合当前虚拟机的要求

对虚拟机没有危害。

注意:可使用-Xverify:none 参数关闭大部分的类验证措施,

缩短虚拟机类加载时间。

2.2准备(Preparation):

静态变量进行默认初始化并分配内存,所使用的的内存都将在方法区分配。

在这里插入图片描述

2.3解析(Resolution):

虚拟机将常量池中的符号引用替换为直接引用。

理解:

此过程中的类没有进入到内存中,不存在地址引用,而是用其他符号代替。

例:A类(符号:#)、B类(符号:%)

当A类里面有引用B类时,不是直接用对象地址引用,而是使用#和%符号去引用。 而转为直接引用,即类加载进内存,有了实际的对象地址。可直接引用对象地址。

3.初始化(initialization):

显示初始化,即源代码里的变量初始化。真正执行java程序代码。

执行clinit()方法:依次自动收集类中所有的静态变量的赋值动作静态代码块中的语句,并进行合并

clinit(): jvm会保证一个类的clinit()方法在多线程环境下被加锁且同步,直到一个线程执行完,其他线程都会成阻塞状态。

因此某个类在内存中只会有一个class对象。

注意:1.2阶段由jvm控制,3.是有程序写代码控制

七、反射的认识、使用及注意
Class类对象:
  1. 也是普通类继承object类。
  2. 不是通过new出来,而是系统构建,通过ClassLoader的loadclass()方法创建。
  3. 对于某个类的Class类对象,在内存中只存在一份。
  4. 每个类的实例都会记录自己属于哪个Class类对象。
  5. 通过Class类对象的api可获得对应类的完整结构,且Class类对象存放在堆。
  6. 类的字节码二进制数据(元数据)存放在方法区(eg:方法代码,变量名,方法名,访问权限)。
获取Class类对象方式:
  1. 编译阶段:Class.forName()

Ps:多用于框架底层,读取配置文件里的全路径类名获取

  1. 加载阶段:类.class

    Ps:多用于参数传递

  2. 运行阶段:对象.getClass()

    Ps:有对象实例时

  3. 进入加载阶段时:通过类加载器获取

  4. 基本数据类型:基本数据类型.class

  5. 基本数据类型对应的包装类:包装类.TYPE

反射机制创建实例:

Class class = Class.forName(“xxx”);

1、通过public的无参构造器:

class.newInstance();

2、通过public的有参构造器:

2.1获得有参构造器:Constructor constructor=class.getConstructor(String.class);

2.2创建实例,传入实参:constructor.newInstance(“sss”)

3、通过非public的有参构造器:

1.1 得到private的构造器对象

Constructor constructor=class.getDeclaredConstructor(int.class,String.class);

3.2设置取消访问检查constructor.setAccessible(true) 即暴力破解

反射机制可访问private的构造器、方法、属性

3.3创建实例:constructor.newInstance(100,”dfdd”)

注意:
  1. 反射机制能生成动态代理。

  2. 当类加载器加载Class类对象进堆区时,也会将对应类的字节码二进制数据加载进方法区,且堆区的Class类对象被防区的字节码二进制数据引用。

  3. 哪些类型有Class类对象:外部类(eg:String.class)、接口(eg:Serializab.class)

    数组(eg:Integer[].class)、二维数组(eg:float[][].class)、注解(eg:Deprecated.class)

    枚举(eg:Thread.State.class)、基本数据类型(eg:int.class)、void数据类型(void.class)

  4. 类名.静态属性:也会导致类加载过程

八、总结

以上就是小白啊里的分享啦,希望对大家有帮助,多多指教~

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值