反射是Java语言中非常重要的一个基础知识点,它的应用往往在于代码的封装上和框架的设计上,对于一般的码农和初级工程师来说,在日常的编码工作中很少直接使用反射,所以不少Java小伙伴对反射是既熟悉又陌生。,熟悉是都听说过,听说是一个很牛掰的技术,是封装框架,走向架构的必修课,陌生在于日常开发很少直接使用,反正不影响哥们施展CV大法。,如果企业没有编程规范要求和来自领导的review,优化程序是不可能的,重构,向上封装?想都不要想。如果想要让自己的编程功力提高,提升自己的架构思维,那么在日常编码过程中,一定要多去思考,我的代码能否再精简?能否再通用?能否变成一个团队插件?想要实现这个目的,反射就可能派上用场了。,本文会从以下几点为小伙伴解密反射,保障看完神清气爽,直呼哇塞:,Reflection(反射)是Java程序开发语言的重要特性之一,通过反射机制允许在程序运行期间,可以根据任意一个.class【字节码文件】文件获取到这个类的所有信息,包括(成员变量,成员方法,构造器等),并可以通过相应的方式操纵类的字段、方法、构造器,基于反射机制,Java实现在程序运行期间,动态获取信息和动态调用对象的方法,提高了程序的扩展性,使用反射的前提是必须有字节码文件,也就是.class文件,.class文件就是通过.java文件编译而来的。Java作为面向对象的编程语言,提供了为反射准备的字节码文件对象java.lang.Class<T>,,反射机制相关的包都在,一些反射中的常用类:,还可以通过字节码对象【Class对象】获取注解以下信息,这些信息不在java.lang.reflect包中,所以单独列出来,反射是将运行中的class文件读取到并封装进反射类【Class<T>】中,并且可以根据反射类获取类中的构造方法,普通方法和属性,接下来根据案例依次演示,咱们写的代码是存储在后缀名是 .java的文件里的,但是它会被编译,最终真正去执行的是编译后的 .class文件。Java是面向对象的语言,一切皆对象,所以java认为这些编译后的 class文件也是一种对象,给抽象成了一种类,这个类就是Class,获取反射类有三种方式:,需求:有以下Student类,我们通过三种方式获取该类的Class对象,并根据Class对象的getName方法,输出类的全路径,student类:,获取反射类:,输出结果:,,改造Student类,增加四个构造方法,默认有一个无参的构造方法,运行结果:,,将无参的构造方法设置为私有,获取所有构造方法:,输出结果:,可以获取所有的公开构造方法,私有构造获取不到,,小贴士:通过反射获取私有的构造函数时,用普通的getConstructor()会报错,因为它是私有的,所以提供了专门反射私有构造函数的方法 getDeclaredConstructor(int.class);,如果要调用这个方法还需要设置一下暴力反射才可以,即调用构造器对象的setAccessible(true);方法,获取所有私有方法:,运行结果:,,仅仅获取到调用会出现 IllegalAccessException 异常,报错:,,设置暴力破解即可访问:也就是调用一下 setAccessible(true)方法,运行结果:,,在Student类中添加以下普通方法,获取方法,通过 Method 类型对象封装,如下图:获取到了所有的非私有方法,包括父类中的方法,,通过调用getDeclaredMethods方法获取所有方法,,如下,获取了包括私有方法,但是不包括父类中的方法,,我们可以通过 getMethod(String name, Class<?>… parameterTypes) 方法,根据方法名和参数获取方法,在通过Method对象的 invoke(Object obj, Object… args)方法调用方法,如果是私有方法,你懂的,需要暴力破解一下再调用,和构造器一样,,方式和调用私有构造器一致,首先通过 getDeclaredMethod 获取私有方法,其次调用 setAccessible(true) 设置可访问为true,参数维数组有点特殊,这是因为 jdk1.4和jdk1.5处理invoke方法有区别,1.5:public Object invoke(Object obj,Object…args):1.5参数为Object类型的可变参数,1.4:public Object invoke(Object obj,Object[] args):1.4参数为一个Object类型数组,在反射方法时,如果方法的参数是一个数组,考虑到向下兼容问题,会按照JDK1.4的语法来对待(JVM会把传递的数组参数拆开,拆开就会报参数的个数不匹配的错误) 解决办法:防止JVM拆开你的数组 方式一:把数组看做是一个Object对象 方式二:重新构建一个Object数组,那个参数数组作为唯一的元素存在。,错误调用:如果直接传进数组,则会出现IllegalArgumentException【非法参数异常】报错,,设置name属性为public,相关方法:,获取属性并通过get方法获取属性值,运行结果:,,使用Servlet编写web应用时,往往都有一个web.xml文件,,该文件会交给Tomcat运行:,就还比如spring框架的xml文件的bean配置,都是通过读取class属性值,通过反射创建对象,代理模式就是为某对象创建一个代理对象,然后通过代理对象代替原对象执行程序,已达到增强对象的作用,在程序运行之前,代理类.class文件就已经被创建了,Java中提供的动态代理就是通过反射实现,动态代理的重要实现接口 InvocationHandler就要求代理类重写 invoke 方法,我们这里可以实现一个PersonService类的代理对象,接口:,PersonService类,PersonService代理对象,测试类,由此实现,在调用speak方法之前和之后都可以执行一些其他操作,,之前做的项目中也应用到反射,来导出指定字段的数据,需求如下:,此时我的实现方式就是在字段上添加自定义注解 @Excel,注解的name属性就是该字段在excel表中的名字,其次,在接口中获取前端传过来的字段名字,后端通过反射匹配,在获取到字段上的 @Excel注解的name属性去生成excel表格,以次来实现,生成excel表时的列名,这就是反射在我的项目中的一个应用,我们这里分别通过反射和new分别创建 10000000 个对象,查看耗时两者差异,运行结果:发现调用空参构造,反射耗时147毫秒,new仅仅需要2毫秒,调用有参的构造方法耗时几乎一致,仅仅是赋值,并没有复杂的构造,由此发现反射的性能其实是比较低的,,文章出自:石添的编程哲学,如有转载本文请联系【石添的编程哲学】今日头条号。
文章版权声明
1 原创文章作者:cmcc,如若转载,请注明出处: https://www.52hwl.com/22005.html
2 温馨提示:软件侵权请联系469472785#qq.com(三天内删除相关链接)资源失效请留言反馈
3 下载提示:如遇蓝奏云无法访问,请修改lanzous(把s修改成x)
4 免责声明:本站为个人博客,所有软件信息均来自网络 修改版软件,加群广告提示为修改者自留,非本站信息,注意鉴别