Android逆向开发必备技能-Java反射技术详解

news/2024/5/19 2:26:48 标签: 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§;
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§;
constructors.newInstance(24,“HuangLinqing”);
运行打印结果如下:

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

Class[] p = {String.class};
constructors = c4.getDeclaredConstructor§;
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 wlkankan.cn.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);
}

}


http://www.niftyadmin.cn/n/775303.html

相关文章

QQ互联本地测试【QQ互联第一步】

目的&#xff1a;QQ互联本地测试【QQ互联第一步】 注&#xff1a;分两种测试&#xff0c; 1、一种是你没有域名&#xff0c;你是用localhost来测试【不建议】 2、你的域名已经备案了&#xff0c;直接用域名来测试【建议】 第一步、注册 https://connect.qq.com/manage.html#…

redirect uri is illegal(100010)

目的&#xff1a;解决(100010) 网上基本都说是回调地址什么的&#xff0c;没有写对&#xff0c;这是一个原因。还有就是我遇到的这个原因&#xff0c; 我的应用还没有审核通过

java去除重复字符串

如何去除重复的字符串? 可以考虑考虑集合是如何保证元素不重复的。作为参考! package www.wlkankan.cn public class Test { private static final Object object new Object(); public static void main(String[] args) { //利用map的key不能重复 …

QQ互联保存openId到数据库【VUE】

目的&#xff1a;QQ互联保存openId到数据库 方法一 SDK里面提供了一个获取 openId 的方法 我在这个方法里面去 写 ajax 的时候报错了说是未定义。问了别人别人说是作用域不同&#xff0c;要用箭头函数&#xff0c;或者用一个变量接受this。我使用的是后者。代码如下 方法二&a…

setpositivebutton

setPositiveButton表示设置弹框后的确定按钮&#xff0c;setNegativeButton表示设置弹框后的取消按钮。 setPositiveButton是实现android.content.DialogInterface.OnClickListener接口后的方法 普通的onclick()是view下的&#xff0c;完全是两个不同的实现。又在View类中也有…

QQ互联跳转到指定的页面【JS-SDK】

我互联的目的是用来做 留言/评论 功能。那么我就需要跳转两个页面&#xff0c;一个是留言板页面&#xff0c;一个是相关文章页面&#xff08;多个文章按照参数区别&#xff09; 我的回调地址 http://www.xdx97.com/#/messageboard;http://www.xdx97.com/#/single 最后做…

微信SDK非微信ipad协议

微信SDK非微信ipad协议 个人微信号开发sdk非微信ipad协议、非mac协议&#xff0c;非安卓协议 无需扫码登录、可收发朋友圈、查看朋友圈、朋友圈互动点赞、评论、好友列表、微信消息收发、发文本消息、图片消息、名片消息、动图表情、发文件、删好友、 添加好友、微信转账、微信…

QQ互联回调地址的填写【简单明了】

这里简单做个小说明&#xff0c;毕竟文档写的很清楚了 如果你的回调地址是一个 固定的地址&#xff0c;比如首页什么的&#xff0c;这是最简单了直接写 http://www.xdx97.com:3030/#/display 我在做的是一个评论功能&#xff0c;那么我需要在那个页面登陆就跳转到那个页面 …