2021年8月4日
第5节 - 05-反射_概述
反射用在开发框架中。开发项目,使用框架不会用到反射。
注意:反射的概念,将类的各个组成部分封装为其他对象。华为云:反射,就是把java类中的各种成分映射成一个个java对象。reflection:(n.)映像; 映照出的影像; (声、光、热等的)反射; 反映; 显示; 表达。本来类是描述世间万物的抽象描述,那么类也需要被描述。这个类被描述的意思英文表达为映射。
java代码在计算机中经历的三个阶段:
1、java类经过编译生成字节码文件,字节码包括:类名、成员变量、构造方法、成员变量等描述性内容。java类和字节码文件都在硬盘中存储。称为源代码阶段(source)。
3、先讲第三个阶段,new一个对象后,到达计算机内存中,称为运行时阶段(runtime)。
2、Class类对象阶段(下面详解)。以前没学的第二个阶段。第一阶段到第二阶段,将字节码文件加载进内存,使用的加载工具是类加载器(ClassLoador)。
补充:
在内存中如何描述字节码文件?java中万物皆对象。在内存中有一个对象来描述字节码文件,称为Class类(的)对象。在java中有一个类java.lang.Class类,是用来描述所有字节码物理文件的类。描述这个字节码物理文件一些共同特征和行为的类,同其他普通类一样,但确实所有java类的字节码文件的共同的类。
Class类中,有三部分比较重要的东西(也有其他内容),某类的字节码的成员变量、构造方法、成员方法。Class类中将其封装为Field对象、Contructor对象、Method对象(即:反射机制的概念所表达的),组合成一个Class对象。但因为不仅一个,所以用数组分别描述:Field[] fields、Constructor[] constructors、Method[] methods。
然后就可以通过Class类对象的行为(如方法)来创建需要的对象。
所以可以称第二个阶段为Class类对象阶段。我们使用的所有对象都是通过Class对象类创建出来的,只不过以前没有详细研究这个过程。
反射的好处:
1.可以在程序运行过程中,操作这些(成员)对象。典型的使用例子:Idea等开发软件中(开发软件是在运行中的)通过“对象名”+“.” 来选择对象不同的方法。
细想一下,Idea如何知道这个你使用的这个对象有哪些方法的?反射就是答案,因为这个类的Class类对象描述了对象的类的字节码文件。
2.解耦,来提高程序的可拓展性。比较抽象,后面通过《第11节》案例讲解。
第6节 - 06-反射_获取(类的)字节码Class对象的三种方式
反射是将 类的组成部分 封装成其他对象。获取和操作这些对象最关键的是获取字节码对象(Class类对象)。
这三种方式分别对应java代码的三个阶段。
1.source源代码阶段:意味着java代码只有字节码文件,未进内存。需要手动的将其加载进内存,生成字节码对象
Class.forName("全类名"):将字节码文件加载进内存,返回Class对象。此为静态方法。
2.Class类对象阶段:已经有字节码对象了,但是还没实际的对象。即字节码已经加载进内存了。不需要加载,只需要获取。
类名.class:通过类名的属性class获取。(类名,实际上就是类的字节码对象名?应该不是,因为要获取字节码对象,那么类名是什么呢?字节码文件≠字节码对象=Class类对象=已加载的类≠类名,通过实际代码例子发现类名非字节码对象,但是有了字节码,自然而然有了字节码对象,两者相伴而生(?)。类名.class代表这个类的Class对象,同时也是类的.class文件的名字。Class对象也就是某类在java中的形式,万物皆对象,类也是一种对象。)
3.Runtime运行时阶段。已经有对象了,
对象.getClass():返回运行时类对象(Class类型的类对象、字节码对象)这个方法是封装在Object类里的,被所有的子类继承下来了,意味着所有的对象都有这方法。
代码演示:
注意:java类代码在集成开发环境Idea中一经保存,即已经被自动编译。也就是说保存后就会生成字节码文件。
问题:类名,在java中是个什么类型的数据?
第7节 - 07-反射_(类的)字节码Class对象功能概述
拿到Class对象,就要使用。如何使用?字节码对象有什么功能?通过查看java api发现Class类中大多是getXxx()类型的方法。说明有获取功能。
后面举例使用这些方法,并详细讲解Declared
第8节 - 08-反射_(类的)字节码Class对象功能_获取Field成员变量
第9节 - 09-反射_(类的)字节码Class对象功能_获取成员方法Constructor构造方法
1.获取字节码对象
2.使用字节码对象创建构造器对象
2.1获取无参构造器对象
2.1.1常规步骤
2.1.2简化步骤(已废弃)
2.2获取有参构造器对象
3.使用构造器对象创建需要的对象
4.暴力反射使用私有构造器对象前,需要设置忽略访问权限修饰符的安全检查
第10节 - 10 -反射(类的)字节码Class对象功能_获取成员方法Method方法
方法三要素:方法名、返回值列表、参数列表
确定一个方法,只需要两个要素:方法名、参数列表(方法重载)
获取所有方法:包含了自身类的方法和父类(或Object类)的方法,但无构造方法(构造方法没有返回值)。
包含自身私有类,和继承的父类方法(public)
引申问题,子类能继承并使用父类私有方法吗?(答:可以继承,但不能调用。简言,只是拥有,但不能使用。那么,拥有的意义何在?)
再引申,反射能获取继承自父类的成员方法吗?父类私有成员变量可以继承并使用吗?
方法的反射,同样支持暴力反射。
获取方法名,后期会用到。
获取全类名,包名.类名。
第11节 - 11 -反射_案例
在刚学习反射过程中并为发现反射的优势所在,“框架设计灵活”,“简化代码”。
反射可以让开发者直接写成品框架需要的类(实际功能),再加上配置文件(配置开发者的类),框架运行起来自动调用。而不是需要更改new类的代码、方法名等。
案例需求:写一个“框架“类,可以帮我们任意创建一个类的对象,并执行其中任意方法。
以下过程涉及的知识点:流、集合、properties对象、类加载器。
1.src下定义配置文件
2.加载配置文件
2.1创建properties对象
2.1.1获取class目录下的配置文件的方式,用类加载器来(可以找到src下的class文件,也可以找到src下的配置文件)获取资源路径、或资源字节流
2.1.2调用properties对象的.load()方法,参数为字符流或字节流,来加载配置文件,并得到为一个集合(双列map集合,properties类是一个map子类)
2.2获取配置文件中定义的数据
2.3利用反射加载该类进内存
2.4创建对象
2.5获取方法对象(作为框架来说不知道开发者将来会用什么自定义对象的名字,所以使用反射)
2.6获取方法对象(作为框架来说不知道开发者将来会用什么自定义方法的名字,所以使用反射)
2.7执行方法
2.8更改配置文件,使用其他类和其方法
更换使用的类,直接更改代码和更改配置文件两种方法的区别?
直接更改代码需要重新测试、编译、上线,容易出现新的代码书写错误。而更改配置文件规避了这些问题,而且让程序、框架的扩展性更强。将来的项目中会用到很多配置文件,如果某个地方配置的全类名,那么它应用的就是反射机制。
传统使用一个对象和其方法如下: