摘要:通过反射获取带参无返回值成员方法并使用设置安全检查,访问私有构造函数必须创建实例这种不行,注意和方法需要传递参数测试复制这个功能获取私有方法,同样注意和的区别赋予访问权限调用方法。
反射 目录介绍
1.反射概述
1.1 反射概述
1.2 获取class文件对象的三种方式
1.3 反射常用的方法介绍
1.4 反射的定义
1.5 反射的组成
1.6 反射的作用有哪些
2.反射的相关使用
2.1.1 通过反射获取无参构造方法并使用
2.1.2 通过反射获取带参构造方法并使用
2.1.3 通过反射获取私有构造方法并使用
2.1.4 通过反射获取成员变量并使用
2.1.5 通过反射获取无参无返回值成员方法并使用
2.1.6 通过反射获取带参无返回值成员方法并使用
2.1.7 通过反射获取带参带返回值成员方法并使用
2.1.8 通过反射获取无参带返回值成员方法并使用
3.相关知识点
3.1.1 设置setAccessible(true)暴力访问权限
3.1.2 获取Filed两个方法的区别
3.1.3 获取Field的类型
3.1.4 Method获取方法名,获取方法参数
3.1.5 Method方法的invoke()方法执行
关于链接1.技术博客汇总
2.开源项目汇总
3.生活博客汇总
4.喜马拉雅音频汇总
5.程序员聊天笔记汇总
5.其他汇总
0.问题答疑0.1 被反射的类是否一定需要无参构造方法?为什么?
0.2 反射的使用有什么优势和劣势?为什么说反射可以降低耦合?
0.3 反射比较损耗性能,为什么这样说?能否通过案例对比说明反射机制损耗性能……
0.4 反射是一种具有与类进行动态交互能力的一种机制,为什么要强调动态交互呢?
0.5 Java反射中的setAccessible()方法是否破坏了类的访问规则
0.2 反射的使用有什么优势和劣势?
射的初衷不是方便你去创建一个对象,而是让你在写代码的时候可以更加灵活,降低耦合,提高代码的自适应能力。
0.4 反射是一种具有与类进行动态交互能力的一种机制,为什么要强调动态交互呢
动态加载,也就是在运行的时候才会加载,而不是在编译的时候,在需要的时候才进行加载获取,或者说你可以在任何时候加载一个不存在的类到内存中,然后进行各种交互,或者获取一个没有公开的类的所有信息,换句话说,开发者可以随时随意的利用反射的这种机制动态进行一些特殊的事情。
1.反射概述 1.1 反射概述JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;
对于任意一个对象,都能够调用它的任意一个方法和属性;
这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
要想解剖一个类,必须先要获取到该类的字节码文件对象。
而解剖使用的就是Class类中的方法,所以先要获取到每一个字节码文件对应的Class类型的对象
1.2 获取class文件对象的三种方式1.2.1 这三种方式为:
a:Object类的getClass()方法
b:静态属性class
c:Class类中静态方法forName()
1.2.2 第一种方法【Object类的getClass()方法】
1.在内存中新建一个Person的实例,对象p对这个内存地址进行引用
2.对象p调用getClass()返回对象p所对应的Class对
3.调用newInstance()方法让Class对象在内存中创建对应的实例,并且让p2引用实例的内存地址
Person p = new Person(); Class> cls=p.getClass(); Person p2=(Person)cls.newInstance();
1.2.3 第二种方法【静态属性class】
1.获取指定类型的Class对象,这里是Person
2.调用newInstance()方法在让Class对象在内存中创建对应的实例,并且让p引用实例的内存地址
Class> cls=Person.Class(); Person p=(Person)cls.newInstance();
1.2.4 第三种方法【Class类中静态方法forName()】
1.通过JVM查找并加载指定的类(上面的代码指定加载了com.fanshe包中的Person类)
2.调用newInstance()方法让加载完的类在内存中创建对应的实例,并把实例赋值给p
注意:如果找不到时,它会抛出 ClassNotFoundException 这个异常,这个很好理解,因为如果查找的类没有在 JVM 中加载的话,自然要告诉开发者。
Class> cls=Class.forName("com.yc.Person"); //forName(包名.类名) Person p= (Person) cls.newInstance();1.3 通过反射获取无参构造方法并使用
A:获取所有构造方法
public Constructor>[] getConstructors()
public Constructor>[] getDeclaredConstructors()
B:获取单个构造方法
public Constructor
public Constructor
方法关键字
getDeclareMethods() 获取所有的方法
getReturnType() 获取方法的返回值类型
getParameterTypes() 获取方法的传入参数类型
getDeclareMethod("方法名,参数类型.class,....") 获得特定的方法
构造方法关键字
getDeclaredConstructors() 获取所有的构造方法
getDeclaredConstructors(参数类型.class,....) 获取特定的构造方法
成员变量
getDeclaredFields 获取所有成员变量
getDeclaredField(参数类型.class,....) 获取特定的成员变量
父类和父接口
getSuperclass() 获取某类的父类
getInterfaces() 获取某类实现的接口
1.4 反射的定义JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制
1.5 反射的组成
由于反射最终也必须有类参与,因此反射的组成一般有下面几个方面组成:
1.java.lang.Class.java:类对象;
2.java.lang.reflect.Constructor.java:类的构造器对象;
3.java.lang.reflect.Method.java:类的方法对象;
4.java.lang.reflect.Field.java:类的属性对象;
反射中类的加载过程
根据虚拟机的工作原理,一般情况下,类需要经过:加载->验证->准备->解析->初始化->使用->卸载这个过程,如果需要反射的类没有在内存中,那么首先会经过加载这个过程,并在在内存中生成一个class对象,有了这个class对象的引用,就可以发挥开发者的想象力,做自己想做的事情了。
1.6 反射的作用有哪些
前面只是说了反射是一种具有与Java类进行动态交互能力的一种机制,在Java和Android开发中,一般情况下下面几种场景会用到反射机制.
需要访问隐藏属性或者调用方法改变程序原来的逻辑,这个在开发中很常见的,由于一些原因,系统并没有开放一些接口出来,这个时候利用反射是一个有效的解决方法
自定义注解,注解就是在运行时利用反射机制来获取的。
在开发中动态加载类,比如在Android中的动态加载解决65k问题等等,模块化和插件化都离不开反射,离开了反射寸步难行。
2.反射的相关使用 2.1.4 通过反射获取成员变量[包含私有]并使用clazz = Class.forName("com.ycbjie.ycpaidian.four.ReflexUtils"); Constructor constructor = clazz.getDeclaredConstructor(Context.class); //设置安全检查,访问私有构造函数必须 constructor.setAccessible(true); Object[] obj = new Object[]{mContext}; //创建实例 ReflexUtils clazzObj = (ReflexUtils) constructor.newInstance(obj); //反射修改私有变量 // 获取声明的 code 字段,这里要注意 getField 和 getDeclaredField 的区别 Field gradeField = clazz.getDeclaredField("code"); // 如果是 private 或者 package 权限的,一定要赋予其访问权限 gradeField.setAccessible(true); // 修改 student 对象中的 Grade 字段值 gradeField.set(clazzObj, 2); LogUtils.e("点击3----"+clazzObj.getCode());2.1.5 通过反射获取无参无返回值成员方法[包含私有]并使用
clazz = Class.forName("com.ycbjie.ycpaidian.four.ReflexUtils"); Constructor constructor = clazz.getDeclaredConstructor(Context.class); //设置安全检查,访问私有构造函数必须 constructor.setAccessible(true); Object[] obj = new Object[]{mContext}; //创建实例 ReflexUtils clazzObj = (ReflexUtils) constructor.newInstance(obj); // 获取私有方法,同样注意 getMethod 和 getDeclaredMethod 的区别 Method goMethod = clazz.getDeclaredMethod("getMethod"); // 赋予访问权限 goMethod.setAccessible(true); // 调用 goToSchool 方法。 goMethod.invoke(clazzObj);2.1.6 通过反射获取带参无返回值成员方法并使用
clazz = Class.forName("com.ycbjie.ycpaidian.four.ReflexUtils"); Constructor constructor = clazz.getDeclaredConstructor(Context.class); //设置安全检查,访问私有构造函数必须 constructor.setAccessible(true); Object[] obj = new Object[]{mContext}; //创建实例 ReflexUtils clazzObj = (ReflexUtils) constructor.newInstance(obj); //这种不行,注意getDeclaredMethod和invoke方法需要传递参数 /*Method copyText = clazz.getDeclaredMethod("copyText"); copyText.setAccessible(true); copyText.invoke(clazzObj,"测试复制这个功能");*/ // 获取私有方法,同样注意 getMethod 和 getDeclaredMethod 的区别 Method copyText = clazz.getDeclaredMethod("copyText",String.class); // 赋予访问权限 copyText.setAccessible(true); // 调用 copyText 方法。 copyText.invoke(clazzObj,"测试复制这个功能");2.1.7 通过反射获取带参带返回值成员方法并使用
clazz = Class.forName("com.ycbjie.ycpaidian.four.ReflexUtils"); Constructor constructor = clazz.getDeclaredConstructor(Context.class); //设置安全检查,访问私有构造函数必须 constructor.setAccessible(true); Object[] obj = new Object[]{mContext}; //创建实例 ReflexUtils clazzObj = (ReflexUtils) constructor.newInstance(obj); //这种不行,注意getDeclaredMethod和invoke方法需要传递参数 /*Method copyText = clazz.getDeclaredMethod("copyText"); copyText.setAccessible(true); copyText.invoke(clazzObj,"测试复制这个功能");*/ // 获取私有方法,同样注意 getMethod 和 getDeclaredMethod 的区别 Method copyText1 = clazz.getDeclaredMethod("copyText",String.class,String.class); // 赋予访问权限 copyText1.setAccessible(true); // 调用 copyText 方法 boolean isSuccess = (boolean) copyText1.invoke(clazzObj,"测试复制这个功能","1111");3.相关知识点
一般情况下,我们并不能对类的私有字段进行操作,利用反射也不例外,但有的时候,例如要序列化的时候,我们又必须有能力去处理这些字段,这时候,我们就需要调用AccessibleObject上的setAccessible()方法来允许这种访问,而由于反射类中的Field,Method和Constructor继承自AccessibleObject,因此,通过在这些类上调用setAccessible()方法,我们可以实现对这些字段的操作。
Field gradeField = clazz.getDeclaredField("code"); // 如果是 private 或者 package 权限的,一定要赋予其访问权限 gradeField.setAccessible(true); Method goMethod = clazz.getDeclaredMethod("getMethod"); // 赋予访问权限 goMethod.setAccessible(true);3.1.2 获取Filed两个方法的区别
两者的区别就是 getDeclaredField() 获取的是 Class 中被 private 修饰的属性。 getField() 方法获取的是非私有属性,并且 getField() 在当前 Class 获取不到时会向祖先类获取。
//获取所有的属性,但不包括从父类继承下来的属性 public Field[] getDeclaredFields() throws SecurityException {} //获取自身的所有的 public 属性,包括从父类继承下来的。 public Field[] getFields() throws SecurityException {}3.1.3 获取Field的类型
可以看到 getGenericType() 确实把泛型都打印出来了,它比 getType() 返回的内容更详细。
public Type getGenericType() {} public Class> getType() {} Field[] filed2 = clazz.getFields(); for ( Field f : filed2 ) { System.out.println("Field :"+f.getName()); System.out.println("Field type:"+f.getType()); System.out.println("Field generic type:"+f.getGenericType()); System.out.println("-------------------"); } //打印值 07-31 17:20:41.027 8700-8700/com.ycbjie.ycpaidian I/System.out: Field :cars 07-31 17:20:41.027 8700-8700/com.ycbjie.ycpaidian I/System.out: Field type:interface java.util.List 07-31 17:20:41.028 8700-8700/com.ycbjie.ycpaidian I/System.out: Field generic type:java.util.List3.1.4 Method获取方法名,获取方法参数07-31 17:20:41.028 8700-8700/com.ycbjie.ycpaidian I/System.out: Field :map 07-31 17:20:41.028 8700-8700/com.ycbjie.ycpaidian I/System.out: Field type:class java.util.HashMap 07-31 17:20:41.028 8700-8700/com.ycbjie.ycpaidian I/System.out: Field generic type:java.util.HashMap 07-31 17:20:41.028 8700-8700/com.ycbjie.ycpaidian I/System.out: Field :name 07-31 17:20:41.028 8700-8700/com.ycbjie.ycpaidian I/System.out: Field type:class java.lang.String 07-31 17:20:41.028 8700-8700/com.ycbjie.ycpaidian I/System.out: Field generic type:class java.lang.String
//获取方法名 //获取方法参数 //返回的是一个 Parameter 数组,在反射中 Parameter 对象就是用来映射方法中的参数。 public Parameter[] getParameters() {} //Method获取方法名 Method[] declaredMethods1 = clazz.getDeclaredMethods(); for ( Method m : declaredMethods1 ) { System.out.println("method name:"+m.getName()); } //获取方法参数 for ( Method m : declaredMethods1 ) { System.out.println("获取方法参数method name:"+m.getName()); //获取参数 Parameter[] paras; if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { paras = m.getParameters(); for (Parameter c : paras ) { System.out.println("获取参数parameter :"+c.getName()+" "+c.getType().getName()); } } //获取所有的参数类型 Class[] pTypes = m.getParameterTypes(); for ( Class c : pTypes ) { System.out.print("参数类型method para types:"+ c.getName()); } System.out.println(); System.out.println("=========================================="); } //打印日志如下所示: 07-31 19:23:13.191 4022-4022/com.ycbjie.ycpaidian I/System.out: ========================================== 07-31 19:23:13.191 4022-4022/com.ycbjie.ycpaidian I/System.out: 获取方法参数method name:copyText 07-31 19:23:13.191 4022-4022/com.ycbjie.ycpaidian I/System.out: 获取参数parameter :arg0 java.lang.String 07-31 19:23:13.191 4022-4022/com.ycbjie.ycpaidian I/System.out: 参数类型method para types:java.lang.String 07-31 19:23:13.191 4022-4022/com.ycbjie.ycpaidian I/System.out: ========================================== 07-31 19:23:13.191 4022-4022/com.ycbjie.ycpaidian I/System.out: 获取方法参数method name:copyText 07-31 19:23:13.191 4022-4022/com.ycbjie.ycpaidian I/System.out: 获取参数parameter :arg0 java.lang.String 07-31 19:23:13.191 4022-4022/com.ycbjie.ycpaidian I/System.out: 获取参数parameter :arg1 java.lang.String 07-31 19:23:13.191 4022-4022/com.ycbjie.ycpaidian I/System.out: 参数类型method para types:java.lang.String参数类型method para types:java.lang.String 07-31 19:23:13.191 4022-4022/com.ycbjie.ycpaidian I/System.out: ========================================== 07-31 19:23:13.191 4022-4022/com.ycbjie.ycpaidian I/System.out: 获取方法参数method name:getCode 07-31 19:23:13.192 4022-4022/com.ycbjie.ycpaidian I/System.out: ========================================== 07-31 19:23:13.192 4022-4022/com.ycbjie.ycpaidian I/System.out: 获取方法参数method name:getUserInfo 07-31 19:23:13.192 4022-4022/com.ycbjie.ycpaidian I/System.out: 获取参数parameter :arg0 java.lang.String 07-31 19:23:13.192 4022-4022/com.ycbjie.ycpaidian I/System.out: 参数类型method para types:java.lang.String 07-31 19:23:13.192 4022-4022/com.ycbjie.ycpaidian I/System.out: ========================================== 07-31 19:23:13.192 4022-4022/com.ycbjie.ycpaidian I/System.out: 获取方法参数method name:setCode 07-31 19:23:13.192 4022-4022/com.ycbjie.ycpaidian I/System.out: 获取参数parameter :arg0 int 07-31 19:23:13.192 4022-4022/com.ycbjie.ycpaidian I/System.out: 参数类型method para types:int 07-31 19:23:13.192 4022-4022/com.ycbjie.ycpaidian I/System.out: ==========================================3.1.5 Method方法的invoke()方法执行
Method 调用 invoke() 的时候,存在许多细节:
invoke() 方法中第一个参数 Object 实质上是 Method 所依附的 Class 对应的类的实例,如果这个方法是一个静态方法,那么 ojb 为 null,后面的可变参数 Object 对应的自然就是参数。
invoke() 返回的对象是 Object,所以实际上执行的时候要进行强制转换。
在对Method调用invoke()的时候,如果方法本身会抛出异常,那么这个异常就会经过包装,由Method统一抛InvocationTargetException。而通过InvocationTargetException.getCause() 可以获取真正的异常。
我的个人站点:www.yczbj.org,www.ycbjie.cn
github:https://github.com/yangchong211
知乎:https://www.zhihu.com/people/...
简书:http://www.jianshu.com/u/b7b2...
csdn:http://my.csdn.net/m0_37700275
喜马拉雅听书:http://www.ximalaya.com/zhubo...
开源中国:https://my.oschina.net/zbj161...
泡在网上的日子:http://www.jcodecraeer.com/me...
邮箱:yangchong211@163.com
阿里云博客:https://yq.aliyun.com/users/a... 239.headeruserinfo.3.dT4bcV
segmentfault头条:https://segmentfault.com/u/xi...
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/76581.html
摘要:使用反射可以在运行时检视类。类名类修饰符等包信息超类所实现的接口构造函数方法属性注解类中附加了很多信息,你可以在获得一个完整列表。全限定名包含所有的包名。构造函数你可以访问类的构造函数,代码如下构造函数的详细教程在章节。 使用反射可以在运行时检视Java类。检视类通常是使用反射时所做的第一件事情。从类中可以获得下面的信息。 类名 类修饰符(private、public、synchro...
摘要:本文是作者自己对中线程的状态线程间协作相关使用的理解与总结,不对之处,望指出,共勉。当中的的数目而不是已占用的位置数大于集合番一文通版集合番一文通版垃圾回收机制讲得很透彻,深入浅出。 一小时搞明白自定义注解 Annotation(注解)就是 Java 提供了一种元程序中的元素关联任何信息和着任何元数据(metadata)的途径和方法。Annotion(注解) 是一个接口,程序可以通过...
摘要:动态代理有多种不同的用途,例如,数据库连接和事务管理用于单元测试的动态模拟对象其他类似的方法拦截。调用序列和下面的流程类似单元测试动态对象模拟利用动态代理实现单元测试的动态存根代理和代理。框架把包装成动态代理。 使用反射可以在运行时动态实现接口。这可以使用类java.lang.reflect.Proxy。这个类的名称是我将这些动态接口实现称之为动态代理的原因。动态代理有多种不同的用途,...
阅读 3054·2021-11-24 09:38
阅读 1313·2021-09-22 15:27
阅读 2936·2021-09-10 10:51
阅读 1446·2021-09-09 09:33
阅读 889·2021-08-09 13:47
阅读 2036·2019-08-30 13:05
阅读 858·2019-08-29 15:15
阅读 2380·2019-08-29 12:21