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 < 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,"代码男人");

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反射技术示例详解内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Java对类私有变量的暴力反射技术讲解

    Java对类私有变量的暴力反射 假设有一个类,他有一个私有变量: package com.howlaa.day04; public class ReflectPoint { private int priVar; public ReflectPoint(int priVar){ this.priVar =priVar; } } 如果我们直接采用.get的方式,是不可能看到私有变量的. 我们可以这样: package com.howlaa.day04; import java.lang.refle

  • java反射技术与类使用示例

    复制代码 代码如下: package com.java.db;import java.lang.reflect.Constructor;import java.lang.reflect.Field;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.util.ArrayList;import java.util.Arrays;import java.util.

  • Java反射技术原理与用法实例分析

    本文实例讲述了Java反射技术原理与用法.分享给大家供大家参考,具体如下: 本文内容: 产生反射技术的需求 反射技术的使用 一个小示例 首发日期:2018-05-10 产生反射技术的需求: 项目完成以后,发现需要增加功能,并且希望增加功能并不需要停止项目运行. 在希望不关停项目运行的情况下,于是考虑到将功能都放到一个单独的项目之外的模块中,每一个功能实现都从这个模块中获取[实际上这个考虑应该是项目开始前就考虑,这个例子可能不是很好].于是就有了反射的产生.(这种思想有点类似工厂模式,如果学过设计

  • 基于Java反射技术实现简单IOC容器

    前言 首先思考一个问题,如果你正在做一个复杂的系统,一个系统模块内有几百个功能业务类,这些类需要使用同一些对象来进行工作.那么,你会怎样去管理这些通用且一样的对象呢? 学习过Spring的朋友会知道,Spring框架为此提供了一种非常先进的思想,即IOC(控制反转).Spring可以理解为一个工厂,负责对象的创建和对象间关系的维护.IoC即控制反转,简单说就是之前需要使用new的方式创建对象,而Spring框架会从XML文件中根据配置的信息来创建对象,然后放进它自己的容器之中.在程序要使用到该对

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

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

  • Java 反射机制详解及实例

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

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

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

  • Java反射技术详解

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

  • java多线程编程技术详解和实例代码

     java多线程编程技术详解和实例代码 1.   Java和他的API都可以使用并发. 可以指定程序包含不同的执行线程,每个线程都具有自己的方法调用堆栈和程序计数器,使得线程在与其他线程并发地执行能够共享程序范围内的资源,比如共享内存,这种能力被称为多线程编程(multithreading),在核心的C和C++语言中并不具备这种能力,尽管他们影响了JAVA的设计. 2.   线程的生命周期 新线程的生命周期从"新生"状态开始.程序启动线程前,线程一直是"新生"状态:

  • 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 泛型的详解及实例

    java 泛型的详解及实例 Java在1.5版本中增加了泛型,在没有泛型之前,从集合中读取每一个对象都需要进行强转,如果一不小心插入了类型错误的对象,在运行时就会报错,给日常开发带来了很多不必要的麻烦,比如以下代码: public class TestGeneric { public static void main(String[] args) { List list = new ArrayList(); list.add(" name:"); list.add(" zer

  • java @interface 注解详解及实例

    java @interface 注解详解及实例 1 简介 在Java中,定义注解其实和定义接口差多不,只需要在interface前添加一个@符号就可以,即 @interface Zhujie{ },这就表明我们定义了一个名为 @Zhujie 的注解.注解中的每一个方法定义了这个注解类型的一个元素,特别注意:注解中方法的声明中一定不能包含参数,也不能抛出异 常:方法的返回值被限制为简单类型.String.Class.emnus.注释,和这些类型的数组,但方法可以有一个缺省值. 注解相当于一种标记,

  • 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中双向链表详解及实例 写在前面: 双向链表是一种对称结构,它克服了单链表上指针单向性的缺点,其中每一个节点即可向前引用,也可向后引用,这样可以更方便的插入.删除数据元素. 由于双向链表需要同时维护两个方向的指针,因此添加节点.删除节点时指针维护成本更大:但双向链表具有两个方向的指针,因此可以向两个方向搜索节点,因此双向链表在搜索节点.删除指定索引处节点时具有较好的性能. Java语言实现双向链表: package com.ietree.basic.datastructure.dublin

随机推荐