反射(一)
开闭原则:不修改源码扩展功能
二.Java Reflection
1.反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息(比如成员表量,构造器,成员方法等),并能操作对象的属性及方法,反射在设计模式和框架底层都会用到。
2.加载完类之后,在堆中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象包含了类的完整结构信息,通过这个对象得到类的结构。这个Class对象就像一面镜子,透过这个镜子看到类的结构,所以称之为反射。(创建对象的时候会加载类,调用子类的时候会加载父类)。
3.Java反射机制可以完成:
1)在运行时判断任意一个对象所属的类
2)在运行时构造任意一个类的对象
3)在运行时得到任意一个类所具有的成员变量和方法
4)在运行时调用任意一个对象的成员变量和方法
5)生成动态代理
三.Java反射机制原理示意图
java程序在计算机中有三个阶段:
详解流程:
现在我们有一个Cat类的源码,探究java程序在计算机中的三个阶段。
① 首先在编译期,JVM检查是否有语法错误,如果没有就将其翻译成字节码文件。即.class文件,生成Cat.class字节码文件。
② 在运行阶段,我们要创建一个Cat对象。
③ 当我们要创建一个Cat对象,这时会将Cat.class字节码文件通过类加载器(ClassLoader)加载到堆中,为Class类对象,这里就体现出了反射,这个Class类对象中包含了完整的Cat类中的数据。
④ 类加载之后生成一个Cat对象,该对象知道它是属于哪个Class对象,而且我们拥有了Class类对象后,也可以使用反射机制进行各种操作。
四.反射相关的主要类
1.java.lang.Class:代表一个类,Class对象表示某个类加载后在堆中的对象
2.java.lang.reflect.Method:代表类的方法,Method对象表示某个类的方法
3.java.lang.reflect.Field:代表类的成员变量,Field对象表示某个类的成员变量
4.java.lang.reflect.Constructor:代表类的构造方法,Constructor对象表示构造器
//创建对象,使用反射机制 //(1)加载类,返回Class类型的对象cls //Class为一个类 Class cls = Class.forName(classfullpath); //(2)通过cls得到你加载的类 com.hspedu.Cat的对象实例 Object obj = cls.newInstance(); //newInstance()方法实际上就是使用对应类的无参构造方法来创建该类的实例 //这里当然可以将obj由Object类型转为Cat类型,然后就能调用其中的hi方法,但是我们的业务要求是我们可能并不知道配置文件中写的是hi方法,所以我们在这也不会 //将hi方法写死,而是利用反射获取Cat中的方法。 //Cat cat1 = (Cat)obj; //cat1.hi(); //(3)通过cls得到你加载的类com.hspedu.Cat的methodName "hi"的方法对象 //在反射中,可以把方法视为对象(万物皆对象) Method method1 = cls.getMethod(method); //(4)通过method1调用方法:即通过方法对象来实现方法调用 System.out.println("=================================================="); method1.invoke(obj);//传统方法:对象.方法(),反射机制方法:方法.invoke(对象) //Field的使用,获取成员变量 Field namefield = cls.getField("name");//报错:NoSuchFieldException: name //getField不能得到非public的成员属性 System.out.println(namefield.get(obj));//传统写法是 对象.成员变量,在反射中:成员变量的对象.get(对象) //Constructor的使用,获取构造器 Constructor constructor1 = cls.getConstructor();//()中可以指定构造器的参数类型.若为空则为无参构造器 Constructor constructor2 = cls.getConstructor(String.class,String.class);//这里传人的String.class就是String这个类的class对象 System.out.println(constructor1);//public com.hspedu.Cat() System.out.println(constructor2);//public com.hspedu.Cat(java.lang.String)
五.反射调用优化
1.反射的优点和缺点
1)优点:可以动态的创建和使用对象(也是框架底层核心),使用灵活,没有反射机制,框架技术就失去底层支持。
2)缺点:使用反射基本是解释执行,对执行速度有影响。
耗时实例:
public class Time_Test { public static void main(String[] args) throws Exception { m1(); m2(); } //传统方法来调用hi public static void m1(){ Cat cat = new Cat(); long start = System.currentTimeMillis(); for(int i = 0;i<1000000000;i++){ cat.hi(); } long end = System.currentTimeMillis(); System.out.println("传统方式耗时:"+(end-start)+"ms"); } //反射机制调用方法hi public static void m2() throws Exception { Class cat = Class.forName("com.hspedu.Cat"); Object obj = cat.newInstance(); Method method = cat.getMethod("hi"); long start = System.currentTimeMillis(); for(int i = 0;i<1000000000;i++){ method.invoke(obj); } long end = System.currentTimeMillis(); System.out.println("反射方式耗时:"+(end-start)+"ms"); } } 输出: 传统方式耗时:8ms 反射方式耗时:4049ms
2.反射调用优化-关闭访问检查
1)Method和Field、Constructor对象都有setAccessible()方法。
2)setAccessible作用是启动和禁用访问安全检查的开关。
3)参数值为true表示反射的对象在使用时取消访问检查,提睾反射效率,参数值为false则表示反射的对象执行访问检查。
由类图可以看出,以Field为例:
AccessibleObject为其父类。
举例:
//反射机制调用方法hi public static void m2() throws Exception { Class cat = Class.forName("com.hspedu.Cat"); Object obj = cat.newInstance(); Method method = cat.getMethod("hi"); method.setAccessible(true);//在反射调用方法时取消访问检查 long start = System.currentTimeMillis(); for(int i = 0;i<1000000000;i++){ method.invoke(obj); } long end = System.currentTimeMillis(); System.out.println("反射方式耗时:"+(end-start)+"ms"); } 输出: 传统方式耗时:5ms 反射方式耗时:2602ms
作者:Noob-Green-Hand
出处:https://www.cnblogs.com/Noob-Green-Hand/p/17306776.html
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 使用C#创建一个MCP客户端
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现