news 2026/7/31 17:40:46

快速了解什么是反射

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
快速了解什么是反射

朋友,希望能帮助到你

  • 1.反射的主要类
  • 2.反射调用优化
  • 3.Class类分析
  • 4.Class常用方法
  • 5.获取Class对象的方式
  • 6.那些类型有Class对象
  • 7.类加载
  • 8.类加载阶段

1.反射的主要类

  • Java.lang.Class:代表一个类,Class对象表示某个类加载后在堆中的对象
  • Java.lang.reflect.Method:代表类的方法,Method对象表示某个类的方法
  • Java.lang.reflect.Field:代表类的成员变量,File对象表示某个类的成员变量
  • Java.lang.reflect.Constructor:代表类的构造方法,Constructor对象表示构造器
packagecom.polar;importjava.io.File;importjava.io.FileInputStream;importjava.lang.reflect.Constructor;importjava.lang.reflect.Field;importjava.lang.reflect.Method;importjava.util.Properties;publicclassApplication{@SuppressWarnings({"all"})publicstaticvoidmain(String[]args)throwsException{StringfilePath="src\\re.properties";//File file = new File(filePath);//file.createNewFile();Propertiesproperties=newProperties();properties.load(newFileInputStream(filePath));Stringclassfullpath=properties.get("classfullpath").toString();Stringmethod=properties.get("method").toString();/** * Java.lang.Class:代表一个类,Class对象表示某个类加载后在堆中的对象 * Java.lang.reflect.Method:代表类的方法,Method对象表示某个类的方法 * Java.lang.reflect.Field:代表类的成员变量,File对象表示某个类的成员变量 * Java.lang.reflect.Constructor:代表类的构造方法,Constructor对象表示构造器 *///ClassClassaClass=Class.forName(classfullpath);Objecto=aClass.newInstance();//MethodMethodmethod1=aClass.getMethod(method);System.out.print("java.lang.reflect.Method调用方法:");method1.invoke(o);//FieldFieldname=aClass.getField("name");System.out.print("java.lang.reflect.Field获取成员变量:");System.out.println(name.get(o));//ConstructorConstructorconstructor=aClass.getConstructor();System.out.print("java.lang.reflect,Constructor获取无参构造器:");System.out.println(constructor);Constructorconstructor1=aClass.getConstructor(String.class);System.out.print("java.lang.reflect.Constructor获取含参构造器:");System.out.println(constructor1);}}

2.反射调用优化

  • 反射的优点:可以动态创建和使用对象(也是框架底层核心),使用灵活,没有反射机制,框架技术就失去可底层支持
  • 反射的缺点:使用反射基本是解释执行,对执行速度有影响

代码演示传统方法和反射机制运行速度得差别

packagecom.polar;importjava.lang.reflect.Method;publicclassV{publicstaticvoidmain(String[]args)throwsException{V1();V2();}//传统调用publicstaticvoidV1(){//创建对象Bearbear=newBear();//使用System计时longstart=System.currentTimeMillis();for(inti=0;i<99999;i++){bear.Test();}longend=System.currentTimeMillis();System.out.println("传统方法耗时:"+(end-start));}//反射调用publicstaticvoidV2()throwsException{ClassaClass=Class.forName("com.polar.Bear");Objecto=aClass.newInstance();Methodtest=aClass.getMethod("Test");longstart=System.currentTimeMillis();for(inti=0;i<99999;i++){test.invoke(o);}longend=System.currentTimeMillis();System.out.println("反射方法耗时:"+(end-start));}}

运行结果可知反射的确运行速度慢

对反射调用进行优化

  • Method、Field、Constructor都可以使用setAccessible进行优化
  • setAccessible作用是启动和禁用访问安全的开关
  • 当setAccessible方法参数为true时,反射的对象在使用时关闭访问检查提高反射效率
  • 当setAccessible方法参数为false时,反射的对象在使用时开启访问检查降低反射效率

代码演示反射优化

packagecom.polar;importjava.lang.reflect.Method;publicclassV{publicstaticvoidmain(String[]args)throwsException{V1();V2();V3();}//传统调用publicstaticvoidV1(){//创建对象Bearbear=newBear();//使用System计时longstart=System.currentTimeMillis();for(inti=0;i<99999;i++){bear.Test();}longend=System.currentTimeMillis();System.out.println("传统方法耗时:"+(end-start));}//反射调用publicstaticvoidV2()throwsException{ClassaClass=Class.forName("com.polar.Bear");Objecto=aClass.newInstance();Methodtest=aClass.getMethod("Test");longstart=System.currentTimeMillis();for(inti=0;i<99999;i++){test.invoke(o);}longend=System.currentTimeMillis();System.out.println("反射方法耗时:"+(end-start));}//反射调用优化publicstaticvoidV3()throwsException{ClassaClass=Class.forName("com.polar.Bear");Objecto=aClass.newInstance();Methodtest=aClass.getMethod("Test");test.setAccessible(true);//在调用方法时,关闭访问检查longstart=System.currentTimeMillis();for(inti=0;i<99999;i++){test.invoke(o);}longend=System.currentTimeMillis();System.out.println("反射优化后耗时:"+(end-start));}}

优化后(优化效果。。。。。),但好歹也优化了,对,优化了。。。。。>_<

3.Class类分析

  • Class也是类,因此也继承Object类
  • Class类对象不是new出来的,而是系统创建的
  • 一个Class对象在内存中只会存在一份,因为类只会加载一次,可通过比较哈希值
  • 每个类的实例都会记得自己由那个Class实例生成
  • 通过Class对象可以完整的得到一个类的完整结构,通过一系列的API方法
  • Class对象是放在堆的
  • 类的字节码二进制数据,是放在方法区的,有的地方称为类的元数据(方法、变量名、方法名、访问权限等等)

4.Class常用方法

  • 代码演示
packagecom.polar;importjava.lang.reflect.Field;publicclassmethodTest{publicstaticvoidmain(String[]args)throwsException{//Bear类所在路径StringclassFullPath="com.polar.Bear";//创建对应的Class对象Class<?>aClass=Class.forName(classFullPath);//输出Class类对象的归属System.out.println(aClass);//输出运输类型System.out.println(aClass.getClass());//输出包名System.out.println(aClass.getPackage().getName());//输出全类名System.out.println(aClass.getName());//创建对象实例Objecto=aClass.newInstance();System.out.println(o);//通过反射获取属性Fieldname=aClass.getField("name");System.out.println(name.get(o));//通过反射对属性进行复制name.set(o,"Polarbear");System.out.println(name.get(o));//通过反射获取所有字段得属性Field[]fields=aClass.getFields();//字段属性for(Fieldfield:fields){System.out.println(field.getName());}//字段属性的值for(Fieldfield:fields){System.out.println(field.get(o));}}}

5.获取Class对象的方式

  • Class.forName(编译阶段):已知类的全类名,多用于配置文件、读取类的全路径、加载类
  • 类名.class(加载阶段):用于参数传递
  • 对象.getClass(运行阶段):有对象实例
  • 类的加载器阶获取对象
  • 基本数据类型获取对对象
  • 基本数据类型的包装类获取对象
packagecom.polarBear;publicclassDemo01{publicstaticvoidmain(String[]args)throwsException{//处于编译阶段,已知全类名StringclassAllPath="com.polarBear.Bear";Class<?>aClass=Class.forName(classAllPath);System.out.println(aClass);//处于加载阶段,多用于参数传递Class<Bear>bearClass=Bear.class;System.out.println(bearClass);//处于运行阶段,有对象实例Bearbear=newBear();Class<?extendsBear>aClass1=bear.getClass();System.out.println(aClass1);//通过加载器获取类的对象/** * 先得到类加载器 * 通过类加载得到Class对象 */ClassLoaderclassLoader=bear.getClass().getClassLoader();Class<?>aClass2=classLoader.loadClass(classAllPath);System.out.println(aClass2);System.out.println(aClass.hashCode());System.out.println(bearClass.hashCode());System.out.println(aClass1.hashCode());System.out.println(aClass2.hashCode());//基本数据类型获得Class类对象Class<Integer>integerClass=int.class;System.out.println(integerClass);//基本数据类型的包装类,通过 .TYPR 得到Class对象Class<Integer>type=Integer.TYPE;System.out.println(type);}}

通过比较他们的哈希值可知是否为同一个对象

6.那些类型有Class对象

  • 外部类、内部类
  • interface:接口
  • 数组
  • enum:枚举
  • annotation:注解
  • 基本数据类型
  • Void

7.类加载

  • 反射机制是Java实现动态语言的关键,也就是通过反射实现类动态加载
  • 动态加载:运行时加载需要类,如果运行时不用该类,则不报错,降低了依赖性
  • 静态加载:编译时加载相关的类,如果没有则报错,依赖性太强

8.类加载阶段

  • 加载Loading:JVM在该阶段的主要目的是将字节码文件从不同的数据源(class文件、jar包、网络)转化为二进制字节流加载到内存中,并生成一个代表该类的java.lang.Class对象
  • 连接Linking:
    1.验证Verifica:相当于连接得子阶段,目的是确保class文件字节流中包含得信息符合当前虚拟机的要求,使其不会威胁当前虚拟机的安全。验证内容包括:文件格式验证、元数据验证、字节码验证、符号引用验证。可以考虑关闭大部分的类验证,来缩短虚拟机类加载得时间。
    2.准备Preparation:JVM会在该阶段对静态变量分配内存并进行默认初始化(0、0L、null、false)。这些变量所使用的内存都将在方法区中进行分配
    3.解析Resolution:虚拟机将常量池内的符号引用替换为直接引用的过程
  • 初始化Initialization:到了初始化阶段才真正开始执行类中定义的java程序,依次自动收集类中所有静态变量的赋值动作和静态代码块的语句,并进行合并
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/31 17:40:21

MusicFree插件架构深度解析与开发实战指南

MusicFree插件架构深度解析与开发实战指南 【免费下载链接】MusicFreePlugins MusicFree播放插件 项目地址: https://gitcode.com/gh_mirrors/mu/MusicFreePlugins 引言&#xff1a;开源音乐插件的技术演进 在数字音乐生态系统中&#xff0c;MusicFree插件系统代表了开…

作者头像 李华
网站建设 2026/7/31 17:40:01

Keil MDK软件仿真实现STM32虚拟串口调试全攻略

1. 从硬件依赖到纯软件调试&#xff1a;为什么我们需要无实物仿真 作为一名在嵌入式开发一线摸爬滚打了十来年的老工程师&#xff0c;我敢说&#xff0c;几乎每个搞STM32开发的人都经历过这样的窘境&#xff1a;项目进度紧&#xff0c;硬件板子还没打样回来&#xff0c;或者手头…

作者头像 李华
网站建设 2026/7/31 17:38:47

免费开源桌面分区神器:3分钟打造整洁高效工作空间

免费开源桌面分区神器&#xff1a;3分钟打造整洁高效工作空间 【免费下载链接】NoFences &#x1f6a7; Open Source Stardock Fences alternative 项目地址: https://gitcode.com/gh_mirrors/no/NoFences 还在为杂乱的Windows桌面而烦恼吗&#xff1f;每天面对几十个图…

作者头像 李华
网站建设 2026/7/31 17:38:40

百度网盘Mac版SVIP破解终极教程:免费解锁高速下载限制

百度网盘Mac版SVIP破解终极教程&#xff1a;免费解锁高速下载限制 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘Mac版的龟速下载而烦恼…

作者头像 李华
网站建设 2026/7/31 17:37:06

APK解析终极指南:如何用Java轻松破解Android应用内部秘密

APK解析终极指南&#xff1a;如何用Java轻松破解Android应用内部秘密 【免费下载链接】apk-parser Apk parser for java 项目地址: https://gitcode.com/gh_mirrors/ap/apk-parser 你是否曾经好奇Android应用内部到底隐藏着什么&#xff1f;想要了解一个APK文件的完整结…

作者头像 李华