反射专题笔记
一、反射机制问题(引出反射)
问题:根据配置文件re.properties指定信息,创建cat对象并调用方法
1-1 前期准备工作
1-1-1 创建配置文件re.properties:
classfullpath=com.java.Cat
method=hi
1-1-2 创建Cat类
public class Cat {
//私有及共有成员变量
private String name = "招财猫";
public int age = 10;
//含参及无参构造
public Cat() {}
public Cat(String name){
this.name=name;
}
//成员方法
public void hi(){
//System.out.println("hi" + name);
}
public void cry(){
System.out.println(name + "喵喵叫..." );
}
}
1-2 传统方式解决
1-2-1 方法一:创建对象直接调用
Cat cat = new Cat();
cat.hi();
1-2-2 方法二:通过读取流读取配置文件
//2、通过读取流获取路径名和方法名
//创建配置文件对象
Properties properties = new Properties();
//根据路径加载读取配置文件
properties.load(new FileInputStream("src\\re.properties"));
//获取配置文件中的路径名
String classfullpath = properties.get("classfullpath").toString();
//获取配置文件中的方法名
String methodName = properties.get("method").toString();
System.out.println("classfullpath:" + classfullpath); com.java.Cat
System.out.println("method:" + methodName);// hi
出现了一个问题,就是不能调用其中的方法,只能读取配置文件,要想调用方法,就必须修改源码创建对象。
由此引出反射,解决在不修改源码,只通过修改配置文件实现控制程序,即OCP原则.
二、反射入门案例
//通过反射调用其中方法
//1、通过类路径获取class类
Class cls = Class.forName(classfullpath);
//2、创建class类对象
Object o = cls.newInstance();
System.out.println(o.getClass());//class com.java.Cat
//可以在不知道配置文件方法名的情况下获取方法对象
Method method1 = cls.getMethod(methodName);
//通过方法对象method1传入class对象调用方法,实现在不修改源码的情况下调用不同方法
//只需修改配置文件中的method=...便可调用不同方法
method1.invoke(o);//调用方法 传统方法:o.method1
当我修改re.properties配置文件内的method=cry,会调用Cat中的cry方法
这样就实现了在不修改源代码的情况下,只修改配置文件控制程序
!! 三、反射机制
3-1 原理图

3-2 解释原理图
计算机运行有 编译、加载、运行三个阶段
- 编译:指java编译生成字节码class文件的过程
- 加载:通过编译生成的class字节码文件类通过类加载器加载出class类对象,这个过程也体现了反射,也因此Cat.class字节码文件和class类对象是一一对应的关系
- 运行:当编译与加载完成后的运行阶段
- 过程理解:当new的时候,会先执行编译阶段,产生Cat.class字节码文件,后通过类的加载器通过反射创建出类的对象,这个时候原字节码文件的成员变量,成员方法,构造方法等都会变成对象,以对应的数组类型存储,字节码文件和class对象是一一映射关系。加载完类对象后,我们可以通过创建Class对象(class.forname("类的全路径")),去实现创建对象,调用方法等功能。同时class类对象和cat对象之间也是一一映射关系,new再多Cat对象也只有一个class类对象
3-3 反射机制作用:
- 判断一个对象所属的类
- 运行时创建类的对象
- 得到或调用类的成员变量和方法
- 生成动态代理
3-4 反射相关类

四、反射的优缺点及调优
4-1 优缺点:![]()
4-2 应用实例:反射调优
/**
* 测试反射调用性能,优化方案
*/
public class Reflection02 {
public static void main(String[] args) throws Exception {
m1();
m2();
m3();
}
//一、传统方法调用
public static void m1() {
Cat cat = new Cat();
long start =System.currentTimeMillis();
for ( int i = 0; i < 900000000; i++) {
cat.hi();
}
long end =System.currentTimeMillis();
System.out.println("传统方法调用时间=" + (end-start) );
}
//二、反射方法调用
public static void m2() throws Exception {
//1、获取类对象 三种方式
Class cls = Class.forName("com.hspedu.Cat");
//2、创建类对象
Object o = cls.newInstance();
//3、创建类对象中的方法对象
Method method = cls.getMethod("hi");
long start =System.currentTimeMillis();
for (int i = 0; i < 900000000; i++) {
method.invoke(o);//4、通过方法对象去调用方法,需要传入类对象
}
long end =System.currentTimeMillis();
System.out.println("反射方法调用时间=" + (end-start) );
}
//三、反射调优 +关闭检查访问 小优化优化的不是很多
public static void m3() throws Exception {
//1、获取类对象 三种方式
Class cls = Class.forName("com.hspedu.Cat");
//2、创建类对象
Object o = cls.newInstance();
//3、创建类对象中的方法对象
Method method = cls.getMethod("hi");
method.setAccessible(true);//在反射调用方法时,取消访问检查
long start =System.currentTimeMillis();
for (int i = 0; i < 900000000; i++) {
method.invoke(o);//4、通过方法对象去调用方法,需要传入类对象
}
long end =System.currentTimeMillis();
System.out.println("优化后反射方法调用时间=" + (end-start) );
}
}
运行结果:
Class类
Class分析
哪些类型有Class对象
Class常用方法
获取Class对象
类加载
反射获取类的结构信息
学习资料来源地址:
https://www.bilibili.com/video/BV1g84y1F7df?p=5&spm_id_from=pageDriver


浙公网安备 33010602011771号