前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java反射技术详解

Java反射技术详解

作者头像
黄林晴
发布2019-03-19 16:49:41
4500
发布2019-03-19 16:49:41
举报
文章被收录于专栏:代码男人代码男人

前言

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

一、基本反射技术

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

        getClass方法

代码语言:javascript
复制
 String name = "Huanglinqing";
 Class c1 = name.getClass();
 System.out.println(c1.getName());

     打印结果如下:

    Class.forName

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

代码语言:javascript
复制
   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属性,可以得到这个基本类型的类型,比如:

代码语言:javascript
复制
Class c1 = Boolean.TYPE;
Class c2 = Byte.TYPE;
Class c3 = Float.TYPE;
Class c4 = Double.TYPE;
代码语言:javascript
复制
 停停停!这些东西有啥子用,如此鸡肋! 别急,一切都是为后续做准备。

二、获取类的成员

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

获取类的构造函数

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

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

代码语言:javascript
复制
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() {
    }

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

获取类的所有构造方法

代码语言:javascript
复制
 Test test = new Test();
 Class c4 = test.getClass();
 Constructor[] constructors ;
 constructors = c4.getDeclaredConstructors();

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

代码语言:javascript
复制
  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数组。

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

代码语言:javascript
复制
   try {
          constructors = c4.getDeclaredConstructor();
          System.out.print(Modifier.toString(constructors.getModifiers()) + );
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
      }

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

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

代码语言:javascript
复制
  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方法,为了方便演示我们将测试类的两个构造方法打印出来. 

代码语言:javascript
复制
   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的方法,如下所示:

代码语言:javascript
复制
 Class[] p = {int.class,String.class};
 constructors = c4.getDeclaredConstructor(p);
 constructors.newInstance(24,"HuangLinqing");

 运行打印结果如下:

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

代码语言:javascript
复制
  Class[] p = {String.class};
  constructors = c4.getDeclaredConstructor(p);
  constructors.setAccessible(true);
  constructors.newInstance("HuangLinqing");

  打印结果如下:

调用类的私有方法

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

代码语言:javascript
复制
  private void welcome(String tips){
        System.out.println(tips);
    }

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

代码语言:javascript
复制
   Class[] p4 = {String.class};
   Method method = c4.getDeclaredMethod("welcome",p4);
   method.setAccessible(true);

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

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

代码语言:javascript
复制
     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不就可以了,但是这里要注意我们是没有办法得到这个类的实例的,要不然都可以得到实例就没有反射一说了。我们在通过反射得到类的实例之后先获取字段:

代码语言:javascript
复制
Field field = c4.getDeclaredField("name");
field.setAccessible(true);
field.set(o,"代码男人");

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

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

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

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019年03月14日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 一、基本反射技术
  • 二、获取类的成员
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档