Java反射技术详解

目录
  • 前言
  • 一、基本反射技术
    • 1.1 根据一个字符串得到一个类
      • getClass方法
      • Class.forName
      • Type属性
  • 二、获取类的成员
    • 获取类中特定的构造方法
    • 调用构造方法
    • 调用类的私有方法
    • 获取类的私有字段并修改值
  • 总结

前言

相信很多人都知道反射可以说是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 < constructors.length; i++) {
        System.out.print(Modifier.toString(constructors[i].getModifiers()) + "参数:");
        Class[] parametertypes = constructors[i].getParameterTypes();
        for (int j = 0; j < parametertypes.length; j++) {
             System.out.print(parametertypes[j].getName() + " ");
       }
      System.out.println("");
  }

运行结果如下所示:

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

获取类中特定的构造方法

我们可以通过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 < parametertypes.length; j++) {
            System.out.print(parametertypes[j].getName() + " ");
          }
       } catch (NoSuchMethodException e) {
            e.printStackTrace();
     }

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

调用构造方法

从这里开始慢慢到了关键的一步,得到类的实例,我们主要借助于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,"代码男人");

是我们上面通过反射构造方法获取的实例, 打印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);
    }
}

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注我们的更多内容!

(0)

相关推荐

  • Java反射(JDK)与动态代理(CGLIB)详解

    目录 一.反射 二.动态代理 1.JDK代理 2.CGLIB代理 3.JDK代理与CGLIB代理对比 总结 一.反射 概念:在运行状态中,对于任意的一个类,都能够知道这个类的所有字段和方法,对任意一个对象都能够通过反射机制调用一个类的任意方法 实现方法:JVM在第一次加载某个类时会生成一个Class对象,里面记录了这个类的信息 链接:类加载机制(留坑) 二.动态代理 动态代理的作用:在不改变原代码的基础上增加新的功能,如日志.权限检验等 反射在动态代理中的应用:由于知道原类的字段.方法等信息,才

  • Java 反射(Reflect)详解

    目录 一 首先我们的去知道什么是反射? 二(刨根问底)知道是什么还需要知道什么"成分"组成反射? 2.1 Class 对象的获取及使用 2.2 拿到碗筷就得去盛饭,拿到了Class就得去操作,获得属性 2.3 吃饱饭,我还想学做饭,找到Class,但是我想去获取Class对象的实例. 2.4 调用Class的实例对象的方法 2.5 修改类的私有属性,由于是私有属性,所以需要去关闭程序的安全监测. 三反射的性能 3 .1 走了不同的路,就得比较不同路的对比(性能对比): 四反射的的优缺点

  • Java反射机制在Spring IOC中的应用详解

    目录 Java反射机制在Spring IOC的应用 下面是Spring通过配置进行实例化对象 Spring的配置如下所示 实现一下Spring底层处理原理 反射机制.反射机制的作用.反射机制的功能 1.反射机制的作用 2.Java反射机制的功能 3.反射机制相关的重要的类有哪些? Java反射机制在Spring IOC的应用 IOC:即"控制反转",不是什么技术,而是一种思想.使用IOC意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制. 本篇文章主要讲解一下IOC

  • Java中的反射机制基本运用详解

    目录 Java中的反射机制基本运用 1.什么是反射(reflect) 2.反射机制提供的功能 3.反射->获取类对象 4.反射->利用无参构造实例化对象 5.反射->利用有参构造实例化对象 6.反射->调用无参方法 7.反射->调用有参方法 8.反射->访问私有方法 9.反射->类加载路径 总结 Java中的反射机制基本运用 看完反射可以了解一下注解 注解annotation://www.jb51.net/article/221276.htm 1.什么是反射(re

  • java反射机制最详解

    目录 java反射机制 什么是反射? 反射的功能: 反射常用类: 1.Class枚举类 2.Constructor构造器 3.Method方法类 4.Field变量类 反射运行指示图 通过反射获取对象 总结 java反射机制 什么是反射? 在java开发中有一个非常重要的概念就是java反射机制,也是java的重要特征之一.反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问.检测和修改它本身状态或行为的一种能力,通过反射可以调用私有方法和私有属性,大部分框架也都是运用反射原理的

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

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

  • Java反射技术详解

    目录 前言 一.基本反射技术 1.1 根据一个字符串得到一个类 getClass方法 Class.forName Type属性 二.获取类的成员 获取类中特定的构造方法 调用构造方法 调用类的私有方法 获取类的私有字段并修改值 总结 前言 相信很多人都知道反射可以说是Java中最强大的技术了,它可以做的事情太多太多,很多优秀的开源框架都是通过反射完成的,比如最初的很多注解框架,后来因为java反射影响性能,所以被运行时注解APT替代了,java反射有个开源框架jOOR相信很多人都用过,不过我们还

  • Java 反射机制详解及实例

    Java 反射机制详解及实例 反射,当时经常听他们说,自己也看过一些资料,也可能在设计模式中使用过,但是感觉对它没有一个较深入的了解,这次重新学习了一下,感觉还行吧!            一,先看一下反射的概念: 主要是指程序可以访问,检测和修改它本身状态或行为的一种能力,并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义. 反射是Java中一种强大的工具,能够使我们很方便的创建灵活的代码,这些代码可以再运行时装配,无需在组件之间进行源代码链接.但是反射使用不当会成本很高

  • Java HttpClient技术详解

    目录 一.HttpClient 1.1. 前台系统访问后台接口的方式 1.2. 什么是HttpClient 1.3. HttpClient入门案例 1.3.1. 发起Get请求 1.3.2. 带参数的Get请求 1.3.3. 发起POST请求 1.3.4. 带参数POST请求 二.项目整合HttpClient-与SpringBoot整合 1.导入maven坐标 2.在项目中创建HttpClientConfig类–类似util 3.在application.properties添加如下配置: 4.

  • Java WebService技术详解

    目录 WebService WebService简介 WebService原理 JAVA WebService规范 (1)JAX-WS: (2)JAXM&SAAJ: (3)JAX-RS: WebService入门案例 服务端的实现 客户端的实现 WSDL 文档结构 阅读方式 SOAP SOAP结构 UDDI Webservice的客户端调用方式 一:生成客户端调用方式 二:service编程调用方式 三:HttpURLConnection调用方式 使用注解修改WSDL内容 WebService

  • Java 反射机制详解及实例代码

    Java反射详解 本篇文章依旧采用小例子来说明,因为我始终觉的,案例驱动是最好的,要不然只看理论的话,看了也不懂,不过建议大家在看完文章之后,在回过头去看看理论,会有更好的理解. 下面开始正文. [案例1]通过一个对象获得完整的包名和类名 package Reflect; /** * 通过一个对象获得完整的包名和类名 * */ class Demo{ //other codes... } class hello{ public static void main(String[] args) {

  • Java反射机制详解

    本文较为详细的分析了Java反射机制.分享给大家供大家参考,具体如下: 一.预先需要掌握的知识(java虚拟机) java虚拟机的方法区: java虚拟机有一个运行时数据区,这个数据区又被分为方法区,堆区和栈区,我们这里需要了解的主要是方法区.方法区的主要作用是存储被装载的类 的类型信息,当java虚拟机装载某个类型的时候,需要类装载器定位相应的class文件,然后将其读入到java虚拟机中,紧接着虚拟机提取class 中的类型信息,将这些信息存储到方法区中.这些信息主要包括: 1.这个类型的全

  • Java反射机制详解_动力节点Java学院整理

    一.先看一下反射的概念: 主要是指程序可以访问,检测和修改它本身状态或行为的一种能力,并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义. 反射是Java中一种强大的工具,能够使我们很方便的创建灵活的代码,这些代码可以再运行时装配,无需在组件之间进行源代码链接.但是反射使用不当会成本很高! 看概念很晕的,继续往下看. 二.反射机制的作用: 1.反编译:.class-->.java 2.通过反射机制访问java对象的属性,方法,构造方法等: 这样好像更容易理解一些,下边我们具

  • Java基础篇之反射机制详解

    目录 1.反射概述 1.1什么是反射 1.2.反射能干什么 2.解剖类 2.1反射构造方法 2.1.1反射无参的构造函数 2.1.2反射“一个参数”的构造函数 2.1.3反射“多个参数”的构造函数 2.1.4反射“私有”的构造函数 2.1.5反射得到类中所有的构造函数 2.2反射类中的方法 2.3反射类中的属性字段 思考:在讲反射之前,先思考一个问题,java中如何创建一个对象,有哪几种方式? Java中创建对象大概有这几种方式: 1.使用new关键字:这是我们最常见的也是最简单的创建对象的方式

随机推荐