>>分享Java编程技术,对《Java面向对象编程》等书籍提供技术支持 书籍支持  卫琴直播  品书摘要  在线测试  资源下载  联系我们
发表一个新主题 开启一个新投票 回复文章 您是本文章第 23614 个阅读者 刷新本主题
 * 贴子主题:  Java反射技术详解 回复文章 点赞(0)  收藏  
作者:日月光华    发表时间:2019-12-20 17:05:49     消息  查看  搜索  好友  邮件  复制  引用

Java反射技术详解

版权声明:本文遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文转自:https://blog.csdn.net/huangliniqng/article/details/88554510

前言

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

一、基本反射技术

      1.1 根据一个字符串得到一个类
        getClass方法
String name = "Huanglinqing";

Class c1 = name.getClass();

System.out.println(c1.getName());

     打印结果如下:
    点击在新窗口中浏览原图
CTRL+鼠标滚轮放大或缩小
    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) {

  }

    这里也通过捕获异常,因为我们传的这个字符串可能不合法,字符串合法命名是类的命名空间和类的名称组成
    打印结果如下:
    点击在新窗口中浏览原图
CTRL+鼠标滚轮放大或缩小
    
   我们还可以通过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("");

  }

    运行结果如下所示:
     点击在新窗口中浏览原图
CTRL+鼠标滚轮放大或缩小
    这样我们就得到了类中所有构造方法和构造方法中的参数,那么我们如何获取特定的构造方法呢?
    
    获取类中特定的构造方法
    
    我们可以通过getConstructors方法获取类中 所有的public类型的构造方法,代码和上面一样就不演示了。
    我们可以通过getDeclaredConstructor()方法传参获取特定参数类型的构造方法,这里注意是getDeclaredConstructor()不是  getDeclaredConstructors() ,所以返回的是一个Class对象而不是一个Class数组。
    获取无参构造方法直接不传参数,如下所示:

  


try {

          constructors = c4.getDeclaredConstructor();

          System.out.print(Modifier.toString(constructors.getModifiers()) + );

        } catch (NoSuchMethodException e) {

            e.printStackTrace();

      }

    这里要进行异常捕获,因为可能不存在对应的构造方法,打印结果如下:  
   点击在新窗口中浏览原图
CTRL+鼠标滚轮放大或缩小

   如果我们想获取有两个参数分别为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();

     }

  这里我们同样打印出构造方法的参数:
点击在新窗口中浏览原图
CTRL+鼠标滚轮放大或缩小
  
  
  调用构造方法

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

运行打印结果如下:
点击在新窗口中浏览原图
CTRL+鼠标滚轮放大或缩小

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

  


Class[] p = {String.class};

  constructors = c4.getDeclaredConstructor(p);

  constructors.setAccessible(true);

  constructors.newInstance("HuangLinqing");

  打印结果如下:

   点击在新窗口中浏览原图
CTRL+鼠标滚轮放大或缩小
调用类的私有方法

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

  


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方法。打印结果如下:
点击在新窗口中浏览原图
CTRL+鼠标滚轮放大或缩小
    
获取类的私有字段并修改值

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


Field field = c4.getDeclaredField("name");

field.setAccessible(true);

field.set(o,"代码男人");

   o是我们上面通过反射构造方法获取的实例,  打印field.get(o).toString()的值如下:
  点击在新窗口中浏览原图
CTRL+鼠标滚轮放大或缩小
  
   不过要注意的是我们修改了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);

    }

}

程序猿的技术大观园:www.javathinker.net


[这个贴子最后由 日月光华 在 2019-12-20 17:05:49 重新编辑]
  Java面向对象编程-->集合(下)
  JavaWeb开发-->自定义JSP标签(Ⅱ)
  JSP与Hibernate开发-->立即检索和延迟检索策略
  Java网络编程-->通过JavaMail API收发邮件
  精通Spring-->Vue Router路由管理器
  Vue3开发-->虚拟DOM和render()函数
  类连接阶段的验证原理
   JAVA进阶之IO模型深入解析
  Java中保留数字的若干位小数位数的方法
  JDK自带JVM调优工具的用法
  java.util.logging.Logger使用详解
  十分钟带你搞懂 Java AQS 核心设计与实现!
  Java的对象的拷贝方式集合
  靠一个HashMap的讲解打动了头条面试官
  Java设计模式:抽象工厂模式
  Java设计模式:解释器模式
  Java入门实用代码:100以内整数求和运算
  Java入门实用代码:文件重命名
  Java 入门实用代码:数组扩容
  通过java.net.URL类连接HTTP服务器时获取响应结果的头部信息
  JAVA设计模式之备忘录模式原理与用法详解
  更多...
 IPIP: 已设置保密
楼主      
1页 1条记录 当前第1
发表一个新主题 开启一个新投票 回复文章


中文版权所有: JavaThinker技术网站 Copyright 2016-2026 沪ICP备16029593号-2
荟萃Java程序员智慧的结晶,分享交流Java前沿技术。  联系我们
如有技术文章涉及侵权,请与本站管理员联系。