热门标签 | HotTags
当前位置:  开发笔记 > Android > 正文

Java反射技术详解及实例解析

这篇文章主要介绍了Java反射技术详解及实例解析,反射可以说是Java中最强大的技术了,它可以做的事情太多太多,很多优秀的开源框架都是通过反射完成的。如果对JAVA感兴趣来可以学习一下

前言

  相信很多人都知道反射可以说是Java中最强大的技术了,它可以做的事情太多太多,很多优秀的开源框架都是通过反射完成的,比如最初的很多注解框架,后来因为java反射影响性能,所以被运行时注解APT替代了,java反射有个开源框架jOOR相信很多人都用过,不过我们还是要学习反射的基础语法,这样才能自己写出优秀的框架,当然这里所讲的反射技术,是学习Android插件化技术、Hook技术等必不可少的!

一、基本反射技术

      1.1 根据一个字符串得到一个类

        getClass方法

 String name = "Huanglinqing";
 Class c1 = name.getClass();
 System.out.println(c1.getName());

     打印结果如下:

    Class.forName

    比如我们获取java.lang.String的类名 

 String name = "java.lang.String";
 Class c1 = null;
 try {
 c1 = Class.forName(name);
 System.out.println(c1.getName());
 } catch (ClassNotFoundException e) {
 }

这里也通过捕获异常,因为我们传的这个字符串可能不合法,字符串合法命名是类的命名空间和类的名称组成

    打印结果如下:

我们还可以通过c1.getSuperclass()获取到他的父类

   Type属性

    基本类型都有type属性,可以得到这个基本类型的类型,比如:

Class c1 = Boolean.TYPE;
Class c2 = Byte.TYPE;
Class c3 = Float.TYPE;
Class c4 = Double.TYPE;

停停停!这些东西有啥子用,如此鸡肋! 别急,一切都是为后续做准备。

二、获取类的成员

         当类中方法定义为私有的时候我们能调用?不能!当变量是私有的时候我们能获取吗?不能!但是反射可以,比如源码中有你需要用到的方法,但是那个方法是私有的,这个时候你就可以通过反射去执行这个私有方法,并且获取私有变量。

       获取类的构造函数

       为了便于测试,我们定义一个Test类,Test类如下:(省略get和set方法)

       Test类中我们定义是三个私有变量,生成两个公有的含参构造方法和一个私有的含参构造方法以及一个公有的无参构造方法。

public class Test {
 
 private int age;
 private String name;
 private int testint;
 
 public Test(int age) {
 this.age = age;
 }
 
 public Test(int age, String name) {
 this.age = age;
 this.name = name;
 }
 
 private Test(String name) {
 this.name = name;
 }
 
 public Test() {
 }

      下面我们通过反射获取这些构造方法

       获取类的所有构造方法

 Test test = new Test();
 Class c4 = test.getClass();
 Constructor[] constructors ;
 cOnstructors= c4.getDeclaredConstructors();

      通过getDeclaredConstructors可以返回类的所有构造方法,返回的是一个数组因为构造方法可能不止一个,通过getModifiers可以得到构造方法的类型,getParameterTypes可以得到构造方法的所有参数,返回的是一个Class数组,所以我们如果想获取所有构造方法以及每个构造方法的参数类型,可以有如下代码:

 for (int i = 0; i 

    运行结果如下所示:

    

    这样我们就得到了类中所有构造方法和构造方法中的参数,那么我们如何获取特定的构造方法呢?

    获取类中特定的构造方法

    我们可以通过getConstructors方法获取类中 所有的public类型的构造方法,代码和上面一样就不演示了。

    我们可以通过getDeclaredConstructor()方法传参获取特定参数类型的构造方法,这里注意是getDeclaredConstructor()不是  getDeclaredConstructors() ,所以返回的是一个Class对象而不是一个Class数组。

    获取无参构造方法直接不传参数,如下所示:

 try {
 cOnstructors= c4.getDeclaredConstructor();
 System.out.print(Modifier.toString(constructors.getModifiers()) + );
 } catch (NoSuchMethodException e) {
 e.printStackTrace();
 }

    这里要进行异常捕获,因为可能不存在对应的构造方法,打印结果如下:  

 

 如果我们想获取有两个参数分别为int和String类型的构造方法,代码如下:

 Class[] p = {int.class,String.class};
 try {
 cOnstructors= c4.getDeclaredConstructor(p);
 System.out.print(Modifier.toString(constructors.getModifiers()) + "参数:");
 Class[] parametertypes = constructors.getParameterTypes();
 for (int j = 0; j 

  这里我们同样打印出构造方法的参数:

 

  调用构造方法

   从这里开始慢慢到了关键的一步,得到类的实例,我们主要借助于newInstance方法,为了方便演示我们将测试类的两个构造方法打印出来. 

 public Test(int age, String name) {
 this.age = age;
 this.name = name;
 System.out.println("hello" + name + "i am" + age);
 }
 
 
 private Test(String name) {
 this.name = name;
 System.out.println("My Name is" +
 name);
 }

   我们先来调用public的方法,如下所示:

 Class[] p = {int.class,String.class};
 cOnstructors= c4.getDeclaredConstructor(p);
 constructors.newInstance(24,"HuangLinqing");

 运行打印结果如下:

  

 那么调用私有构造方法呢,和上面一样,只是我们要设置constructors.setAccessible(true);代码如下:

 Class[] p = {String.class};
 cOnstructors= c4.getDeclaredConstructor(p);
 constructors.setAccessible(true);
 constructors.newInstance("HuangLinqing");

打印结果如下:


调用类的私有方法

  如何调用类中的私有方法呢,我们先在测试类中编写一个测试的私有方法 如下:

 private void welcome(String tips){
 System.out.println(tips);
 }

  我们知道如果我们要正常的调用类的方法都是通过类.方法调用,所以我们调用私有方法也需要得到类的实例,而我们上面newInstace已经得到了类的实例,这样就好办了。

Class[] p4 = {String.class};
 Method method = c4.getDeclaredMethod("welcome",p4);
 method.setAccessible(true);

   我们首先通过 getDeclaredMethod方法获取到这个私有方法,第一个参数是方法名,第二个参数是参数类型

   然后通过invoke方法执行,invoke需要两个参数一个是类的实例,一个是方法参数。    

Class[] p4 = {String.class};
 Method method = c4.getDeclaredMethod("welcome",p4);
 method.setAccessible(true);
 Object arg1s[] = {"欢迎关注代码男人技术公众号"};
 method.invoke(test,arg1s);

     test类的实例当不能new 获取的时候我们也可以通过反射获取,就是上面的newInstance方法。打印结果如下:


 获取类的私有字段并修改值

  看到这里你可能会说,有了set方法,什么私有不私有,test.set不就可以了,但是这里要注意我们是没有办法得到这个类的实例的,要不然都可以得到实例就没有反射一说了。我们在通过反射得到类的实例之后先获取字段:

Field field = c4.getDeclaredField("name");
field.setAccessible(true);
field.set(o,"代码男人");

   o是我们上面通过反射构造方法获取的实例,  打印field.get(o).toString()的值如下:

   

   不过要注意的是我们修改了name的值只对当前的实例对象有效。

   Java的基本反射语法就是这样了,欢迎加入技术群一起探讨!

  最后反射封装类如下:

package jnidemo.hlq.com.hookdemo;
 
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
 
/**
 * @author Huanglinqing
 * @date 2019/4/28
 */
 
public class Reflex {
 
 /**
 * 获取无参构造函数
 * @param className
 * @return
 */
 public static Object createObject(String className) {
 Class[] pareTyples = new Class[]{};
 Object[] pareVaules = new Object[]{};
 
 try {
 Class r = Class.forName(className);
 return createObject(r, pareTyples, pareVaules);
 } catch (ClassNotFoundException e) {
 e.printStackTrace();
 }
 
 return null;
 }
 
 /**
 * 获取无参构造方法
 * @param clazz
 * @return
 */
 public static Object createObject(Class clazz) {
 Class[] pareTyple = new Class[]{};
 Object[] pareVaules = new Object[]{};
 
 return createObject(clazz, pareTyple, pareVaules);
 }
 
 /**
 * 获取一个参数的构造函数 已知className
 *
 * @param className
 * @param pareTyple
 * @param pareVaule
 * @return
 */
 public static Object createObject(String className, Class pareTyple, Object pareVaule) {
 
 Class[] pareTyples = new Class[]{pareTyple};
 Object[] pareVaules = new Object[]{pareVaule};
 
 try {
 Class r = Class.forName(className);
 return createObject(r, pareTyples, pareVaules);
 } catch (ClassNotFoundException e) {
 e.printStackTrace();
 }
 
 return null;
 }
 
 
 /**
 * 获取单个参数的构造方法 已知类
 *
 * @param clazz
 * @param pareTyple
 * @param pareVaule
 * @return
 */
 public static Object createObject(Class clazz, Class pareTyple, Object pareVaule) {
 Class[] pareTyples = new Class[]{pareTyple};
 Object[] pareVaules = new Object[]{pareVaule};
 
 return createObject(clazz, pareTyples, pareVaules);
 }
 
 /**
 * 获取多个参数的构造方法 已知className
 * @param className
 * @param pareTyples
 * @param pareVaules
 * @return
 */
 public static Object createObject(String className, Class[] pareTyples, Object[] pareVaules) {
 try {
 Class r = Class.forName(className);
 return createObject(r, pareTyples, pareVaules);
 } catch (ClassNotFoundException e) {
 e.printStackTrace();
 }
 
 return null;
 }
 
 
 /**
 * 获取构造方法
 *
 * @param clazz
 * @param pareTyples
 * @param pareVaules
 * @return
 */
 public static Object createObject(Class clazz, Class[] pareTyples, Object[] pareVaules) {
 try {
 Constructor ctor = clazz.getDeclaredConstructor(pareTyples);
 ctor.setAccessible(true);
 return ctor.newInstance(pareVaules);
 } catch (Exception e) {
 e.printStackTrace();
 }
 
 return null;
 }
 
 
 /**
 * 获取多个参数的方法
 * @param obj
 * @param methodName
 * @param pareTyples
 * @param pareVaules
 * @return
 */
 public static Object invokeInstanceMethod(Object obj, String methodName, Class[] pareTyples, Object[] pareVaules) {
 if (obj == null) {
 return null;
 }
 
 try {
 //调用一个private方法 //在指定类中获取指定的方法
 Method method = obj.getClass().getDeclaredMethod(methodName, pareTyples);
 method.setAccessible(true);
 return method.invoke(obj, pareVaules);
 
 } catch (Exception e) {
 e.printStackTrace();
 }
 
 return null;
 }
 
 /**
 * 获取一个参数的方法
 * @param obj
 * @param methodName
 * @param pareTyple
 * @param pareVaule
 * @return
 */
 public static Object invokeInstanceMethod(Object obj, String methodName, Class pareTyple, Object pareVaule) {
 Class[] pareTyples = {pareTyple};
 Object[] pareVaules = {pareVaule};
 
 return invokeInstanceMethod(obj, methodName, pareTyples, pareVaules);
 }
 
 /**
 * 获取无参方法
 * @param obj
 * @param methodName
 * @return
 */
 public static Object invokeInstanceMethod(Object obj, String methodName) {
 Class[] pareTyples = new Class[]{};
 Object[] pareVaules = new Object[]{};
 
 return invokeInstanceMethod(obj, methodName, pareTyples, pareVaules);
 }
 
 
 /**
 * 无参静态方法
 * @param className
 * @param method_name
 * @return
 */
 public static Object invokeStaticMethod(String className, String method_name) {
 Class[] pareTyples = new Class[]{};
 Object[] pareVaules = new Object[]{};
 
 return invokeStaticMethod(className, method_name, pareTyples, pareVaules);
 }
 
 /**
 * 获取一个参数的静态方法
 * @param className
 * @param method_name
 * @param pareTyple
 * @param pareVaule
 * @return
 */
 public static Object invokeStaticMethod(String className, String method_name, Class pareTyple, Object pareVaule) {
 Class[] pareTyples = new Class[]{pareTyple};
 Object[] pareVaules = new Object[]{pareVaule};
 
 return invokeStaticMethod(className, method_name, pareTyples, pareVaules);
 }
 
 /**
 * 获取多个参数的静态方法
 * @param className
 * @param method_name
 * @param pareTyples
 * @param pareVaules
 * @return
 */
 public static Object invokeStaticMethod(String className, String method_name, Class[] pareTyples, Object[] pareVaules) {
 try {
 Class obj_class = Class.forName(className);
 return invokeStaticMethod(obj_class, method_name, pareTyples, pareVaules);
 } catch (Exception e) {
 e.printStackTrace();
 }
 
 return null;
 }
 
 /**
 * 无参静态方法
 * @param method_name
 * @return
 */
 public static Object invokeStaticMethod(Class clazz, String method_name) {
 Class[] pareTyples = new Class[]{};
 Object[] pareVaules = new Object[]{};
 
 return invokeStaticMethod(clazz, method_name, pareTyples, pareVaules);
 }
 
 /**
 * 一个参数静态方法
 * @param clazz
 * @param method_name
 * @param classType
 * @param pareVaule
 * @return
 */
 public static Object invokeStaticMethod(Class clazz, String method_name, Class classType, Object pareVaule) {
 Class[] classTypes = new Class[]{classType};
 Object[] pareVaules = new Object[]{pareVaule};
 
 return invokeStaticMethod(clazz, method_name, classTypes, pareVaules);
 }
 
 /**
 * 多个参数的静态方法
 * @param clazz
 * @param method_name
 * @param pareTyples
 * @param pareVaules
 * @return
 */
 public static Object invokeStaticMethod(Class clazz, String method_name, Class[] pareTyples, Object[] pareVaules) {
 try {
 Method method = clazz.getDeclaredMethod(method_name, pareTyples);
 method.setAccessible(true);
 return method.invoke(null, pareVaules);
 } catch (Exception e) {
 e.printStackTrace();
 }
 
 return null;
 }
 
 
 public static Object getFieldObject(String className, Object obj, String filedName) {
 try {
 Class obj_class = Class.forName(className);
 return getFieldObject(obj_class, obj, filedName);
 } catch (ClassNotFoundException e) {
 e.printStackTrace();
 }
 return null;
 }
 
 public static Object getFieldObject(Class clazz, Object obj, String filedName) {
 try {
 Field field = clazz.getDeclaredField(filedName);
 field.setAccessible(true);
 return field.get(obj);
 } catch (Exception e) {
 e.printStackTrace();
 }
 
 return null;
 }
 
 
 public static void setFieldObject(Class clazz, Object obj, String filedName, Object filedVaule) {
 try {
 Field field = clazz.getDeclaredField(filedName);
 field.setAccessible(true);
 field.set(obj, filedVaule);
 } catch (Exception e) {
 e.printStackTrace();
 }
 }
 
 public static void setFieldObject(String className, Object obj, String filedName, Object filedVaule) {
 try {
 Class obj_class = Class.forName(className);
 setFieldObject(obj_class, obj, filedName, filedVaule);
 } catch (ClassNotFoundException e) {
 e.printStackTrace();
 }
 }
 
 
 public static Object getStaticFieldObject(String className, String filedName) {
 return getFieldObject(className, null, filedName);
 }
 
 public static Object getStaticFieldObject(Class clazz, String filedName) {
 return getFieldObject(clazz, null, filedName);
 }
 
 public static void setStaticFieldObject(String classname, String filedName, Object filedVaule) {
 setFieldObject(classname, null, filedName, filedVaule);
 }
 
 public static void setStaticFieldObject(Class clazz, String filedName, Object filedVaule) {
 setFieldObject(clazz, null, filedName, filedVaule);
 }
}

到此这篇关于Java反射技术详解及实例解析的文章就介绍到这了,更多相关Java反射技术示例详解内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!


推荐阅读
  • 本文探讨了如何通过最小生成树(MST)来计算严格次小生成树。在处理过程中,需特别注意所有边权重相等的情况,以避免错误。我们首先构建最小生成树,然后枚举每条非树边,检查其是否能形成更优的次小生成树。 ... [详细]
  • QUIC协议:快速UDP互联网连接
    QUIC(Quick UDP Internet Connections)是谷歌开发的一种旨在提高网络性能和安全性的传输层协议。它基于UDP,并结合了TLS级别的安全性,提供了更高效、更可靠的互联网通信方式。 ... [详细]
  • 本文详细介绍如何使用arm-eabi-gdb调试Android平台上的C/C++程序。通过具体步骤和实用技巧,帮助开发者更高效地进行调试工作。 ... [详细]
  • 深入理解 Oracle 存储函数:计算员工年收入
    本文介绍如何使用 Oracle 存储函数查询特定员工的年收入。我们将详细解释存储函数的创建过程,并提供完整的代码示例。 ... [详细]
  • 本文总结了2018年的关键成就,包括职业变动、购车、考取驾照等重要事件,并分享了读书、工作、家庭和朋友方面的感悟。同时,展望2019年,制定了健康、软实力提升和技术学习的具体目标。 ... [详细]
  • 在计算机技术的学习道路上,51CTO学院以其专业性和专注度给我留下了深刻印象。从2012年接触计算机到2014年开始系统学习网络技术和安全领域,51CTO学院始终是我信赖的学习平台。 ... [详细]
  • CSS 布局:液态三栏混合宽度布局
    本文介绍了如何使用 CSS 实现液态的三栏布局,其中各栏具有不同的宽度设置。通过调整容器和内容区域的属性,可以实现灵活且响应式的网页设计。 ... [详细]
  • Linux 系统启动故障排除指南:MBR 和 GRUB 问题
    本文详细介绍了 Linux 系统启动过程中常见的 MBR 扇区和 GRUB 引导程序故障及其解决方案,涵盖从备份、模拟故障到恢复的具体步骤。 ... [详细]
  • 本文介绍了如何使用jQuery根据元素的类型(如复选框)和标签名(如段落)来获取DOM对象。这有助于更高效地操作网页中的特定元素。 ... [详细]
  • 本文将详细介绍如何使用剪映应用中的镜像功能,帮助用户轻松实现视频的镜像效果。通过简单的步骤,您可以快速掌握这一实用技巧。 ... [详细]
  • 深入理解Cookie与Session会话管理
    本文详细介绍了如何通过HTTP响应和请求处理浏览器的Cookie信息,以及如何创建、设置和管理Cookie。同时探讨了会话跟踪技术中的Session机制,解释其原理及应用场景。 ... [详细]
  • 本文介绍如何在 Xcode 中使用快捷键和菜单命令对多行代码进行缩进,包括右缩进和左缩进的具体操作方法。 ... [详细]
  • 本文介绍了一款用于自动化部署 Linux 服务的 Bash 脚本。该脚本不仅涵盖了基本的文件复制和目录创建,还处理了系统服务的配置和启动,确保在多种 Linux 发行版上都能顺利运行。 ... [详细]
  • 在Linux系统中配置并启动ActiveMQ
    本文详细介绍了如何在Linux环境中安装和配置ActiveMQ,包括端口开放及防火墙设置。通过本文,您可以掌握完整的ActiveMQ部署流程,确保其在网络环境中正常运行。 ... [详细]
  • Android 渐变圆环加载控件实现
    本文介绍了如何在 Android 中创建一个自定义的渐变圆环加载控件,该控件已在多个知名应用中使用。我们将详细探讨其工作原理和实现方法。 ... [详细]
author-avatar
毛残品_394
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有