app逆向-Java反射

一、前言

Java反射是指在运行时动态获取类的信息、调用类的方法、访问类的属性等能力。通过反射,可以在运行时检查类的方法、字段和构造函数,而不需要在编译时知道这些类的具体信息。

Class类:代表了一个Java类。在运行时,JVM会为每个加载的类(无论是系统类还是自定义类)创建一个Class对象,通过这个对象可以获取类的各种信息。

Constructor类:代表类的构造函数,可以用于创建新的类实例。

Field类:代表类的字段,可以用于读取或设置字段的值。

Method类:代表类的方法,可以用于调用类的方法。

通过这些类,可以实现在运行时动态地加载类、创建类的实例、调用类的方法、访问和修改类的属性等操作。这种动态性提供了更大的灵活性,但也增加了代码的复杂度和运行时性能开销。因此,在使用反射时需要慎重考虑。

二、运用

先编写一个盲盒类,java代码如下:

package com.example.myapplication;

import java.util.Random;

public class MysteryBox {
    // 使用final修饰的变量表示该变量只能被赋值一次,一旦赋值后,其值就不能再改变
    private final String content;
    private boolean isOpened;
    public final int price;
    private final String brand;

    // 构造方法
    public MysteryBox(){
        this.brand = "泡泡玛特";
        this.price = 10;
        isOpened = false;
        int random = new Random().nextInt();
        if(random % 100 == 1){
            content = "隐藏款";
        }else {
            content = "普通款";
        }
    }

    // 私有构造方法
    private MysteryBox(String brand){
        this.brand = brand;
        this.price = 10;
        isOpened = false;
        int random = new Random().nextInt();
        if(random % 100 == 1){
            content = "隐藏款";
        }else {
            content = "普通款";
        }
    }

    // 公有构造方法
    public MysteryBox(int price){
        this.brand = "泡泡玛特";
        this.price = price;
        isOpened = false;
        int random = new Random().nextInt();
        int p = 100;
        if(price > 100){
            p = 10;
        }
        if(random % p == 1){
            content = "隐藏款";
        }else {
            content = "普通款";
        }
    }

    // 公有构造方法
    public MysteryBox(int price, String brand){
        this.brand = brand;
        this.price = price;
        isOpened = false;
        int random = new Random().nextInt();
        int p = 100;
        if(price > 100){
            p = 10;
        }
        if(random % p == 1){
            content = "隐藏款";
        }else {
            content = "普通款";
        }
    }

    // 实例方法
    public void open(){
        isOpened = true;
    }

    private void close(){
        isOpened = false;
    }

    public String getContent(){
        if(isOpened){
            return content;
        }else {
            return "这个盲盒没有打开哦;";
        }
    }
}

1、获取类class对象

// 获取Class对象
@Test
public void getClassDemo() throws Exception{
    // 1.通过类名获取 类名.class
    // Class<?>表示一个未知类型的Class对象,即可以表示任意类型的类。
    Class<?> class1 = MysteryBox.class;
    System.out.println("通过类名获取 类名.class: " + class1);

    // 2.通过对象获取 对象.getClass()
    // 创建了一个名为box的MysteryBox对象实例
    MysteryBox box = new MysteryBox();
    Class<?> class2 = box.getClass();
    System.out.println("通过对象获取 对象.getClass(): " + class2);

    // 3.通过全类名获取 Class.forName(全类名) 或者 classLoader.loadClass(全类名)
    Class<?> class3 = Class.forName("com.example.myapplication.MysteryBox");
    System.out.println("通过全类名获取 Class.forName(全类名): " + class3);

    // 获取当前线程的类加载器
    ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
    Class<?> class4 = classLoader.loadClass("com.example.myapplication.MysteryBox");
    System.out.println("通过全类名获取 classLoader.loadClass(全类名): " + class4);
}

输出效果:

通过类名获取 类名.class: class com.example.myapplication.MysteryBox
通过对象获取 对象.getClass(): class com.example.myapplication.MysteryBox
通过全类名获取 Class.forName(全类名): class com.example.myapplication.MysteryBox
通过全类名获取 classLoader.loadClass(全类名): class com.example.myapplication.MysteryBox

2、如何判断是否为某个类的实例

@Test
public void checkInstanceOf(){
    MysteryBox box = new MysteryBox();
    // instanceof 关键字
    System.out.println(box instanceof MysteryBox);

    // class.instanceof
    System.out.println(MysteryBox.class.isInstance(box));

    // isAssignableFrom
    System.out.println(box.getClass().isAssignableFrom(MysteryBox.class));
}

效果:

@Test
public void checkInstanceOf(){
    MysteryBox box = new MysteryBox();
    // instanceof 关键字
    System.out.println(box instanceof MysteryBox);

    // class.instanceof
    System.out.println(MysteryBox.class.isInstance(box));

    // isAssignableFrom
    System.out.println(box.getClass().isAssignableFrom(MysteryBox.class));
}

3、创建类的实例/对象

    @Test
    public void createInstance() throws Exception{
        Class<?> class1 = MysteryBox.class;

        // 使用newInstance得到MysteryBox的实例/对象box1,最终访问实例方法
        MysteryBox box1 = (MysteryBox) class1.newInstance();
        System.out.println(box1);
        System.out.println(box1.getContent());

        // 通过Constructor构造器得到MysteryBox的实例/对象box1,最终访问实例方法
        Constructor<?> constructor = class1.getConstructor();
        Object box2 = constructor.newInstance();
        MysteryBox mysteryBox2 = (MysteryBox) box2;
        System.out.println(mysteryBox2);
        System.out.println(mysteryBox2.getContent());
    }

打印效果:

@Test
public void createInstance() throws Exception{
    Class<?> class1 = MysteryBox.class;

    // 使用newInstance得到MysteryBox的实例/对象box1,最终访问实例方法
    MysteryBox box1 = (MysteryBox) class1.newInstance();
    System.out.println(box1);
    System.out.println(box1.getContent());

    // 通过Constructor构造器得到MysteryBox的实例/对象box1,最终访问实例方法
    Constructor<?> constructor = class1.getConstructor();
    Object box2 = constructor.newInstance();
    MysteryBox mysteryBox2 = (MysteryBox) box2;
    System.out.println(mysteryBox2);
    System.out.println(mysteryBox2.getContent());
}

4、获取构造器信息

    @Test
    public void getConstructor() throws Exception{
        //1.getConstructor
        Constructor<?> constructor = MysteryBox.class.getConstructor();
        System.out.println(constructor);
        //1.1打印int参数的构造函数
        Constructor<?> constructorInt = MysteryBox.class.getConstructor(int.class);
        System.out.println(constructorInt);

        //2.getConstructors获取全部的构造函数,此方法只能获取public方法修饰的方法
        Constructor<?>[] constructors = MysteryBox.class.getConstructors();
        System.out.println(Arrays.toString(constructors));

        //3.getDeclaredConstructor 获取private修饰的构造函数
        Constructor<?> constructorStr = MysteryBox.class.getDeclaredConstructor(String.class);
        System.out.println(constructorStr);

        //4.getDeclaredConstructors 获取全部的构造函数包括private的构造函数
        Constructor<?>[] constructorsAll = MysteryBox.class.getDeclaredConstructors();
        System.out.println(Arrays.toString(constructorsAll));
    }

输出效果:

public com.example.myapplication.MysteryBox()
public com.example.myapplication.MysteryBox(int)
[public com.example.myapplication.MysteryBox(int,java.lang.String), public com.example.myapplication.MysteryBox(int), public com.example.myapplication.MysteryBox()]
private com.example.myapplication.MysteryBox(java.lang.String)
[public com.example.myapplication.MysteryBox(int,java.lang.String), public com.example.myapplication.MysteryBox(int), private com.example.myapplication.MysteryBox(java.lang.String), public com.example.myapplication.MysteryBox()]

5、获取成员变量/属性

@Test
public void getFields() throws Exception{
    MysteryBox box = new MysteryBox();

    // 获取public修饰的属性
    Field priceField = MysteryBox.class.getField("price");
    System.out.println(priceField.get(box));

    // 获取全部public修饰的属性
    Field[] priceFields = MysteryBox.class.getFields();
    System.out.println(Arrays.toString(priceFields));
    for (Field field: priceFields){
        System.out.println(field.get(box));
    }

    // 获取 private 修饰的属性
    Field contentField = MysteryBox.class.getDeclaredField("content");
    contentField.setAccessible(true);
    System.out.println(contentField.get(box));

    // 获取全部 private 修饰的属性
    Field[] contentFields = MysteryBox.class.getDeclaredFields();
    for (Field contentField1: contentFields){
        contentField1.setAccessible(true);
        System.out.println(contentField1.get(box));
    }
}

输出效果:

10
[public final int com.example.myapplication.MysteryBox.price]
10
普通款
普通款
false
10
泡泡玛特

6、获取实例⽅法

@Test
public void getFun() throws Exception {
    MysteryBox box = new MysteryBox();
    // 获取 public 修饰的方法
    Method getContent = MysteryBox.class.getMethod("getContent");
    Object Content = getContent.invoke(box);
    System.out.println(Content);

    // 获取全部 public 修饰的方法
    Method[] getFunS = MysteryBox.class.getMethods();
    for (Method i: getFunS){
        // 打印所有的方法
        System.out.println(i);
    }

    // 获取 publics 修饰的方法
    Method funClose = MysteryBox.class.getDeclaredMethod("close");
    box.open();
    System.out.println(box.getContent());
    funClose.setAccessible(true);
    funClose.invoke(box);
    System.out.println(box.getContent());

    // 获取全部 publics 修饰的方法
    Method[] funS = MysteryBox.class.getDeclaredMethods();
    for (Method i: funS){
        // 打印所有的方法
        System.out.println(i);
    }
}

输出效果:

这个盲盒没有打开哦;
public java.lang.String com.example.myapplication.MysteryBox.getContent()
public void com.example.myapplication.MysteryBox.open()
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public java.lang.String java.lang.Object.toString()
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()
普通款
这个盲盒没有打开哦;
private void com.example.myapplication.MysteryBox.close()
public java.lang.String com.example.myapplication.MysteryBox.getContent()
public void com.example.myapplication.MysteryBox.open()

三、代码

完整的测试代码如下:

package com.example.myapplication;

import org.junit.Test;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;

import static org.junit.Assert.assertEquals;

/**
 * Example local unit test, which will execute on the development machine (host).
 *
 * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
 */
public class ExampleUnitTest {
    @Test
    public void addition_isCorrect() {
        assertEquals(4, 2 + 2);
    }

    // 获取Class对象
    @Test
    public void getClassDemo() throws Exception{
        // 1.通过类名获取 类名.class
        // Class<?>表示一个未知类型的Class对象,即可以表示任意类型的类。
        Class<?> class1 = MysteryBox.class;
        System.out.println("通过类名获取 类名.class: " + class1);

        // 2.通过对象获取 对象.getClass()
        // 创建了一个名为box的MysteryBox对象实例
        MysteryBox box = new MysteryBox();
        Class<?> class2 = box.getClass();
        System.out.println("通过对象获取 对象.getClass(): " + class2);

        // 3.通过全类名获取 Class.forName(全类名) 或者 classLoader.loadClass(全类名)
        Class<?> class3 = Class.forName("com.example.myapplication.MysteryBox");
        System.out.println("通过全类名获取 Class.forName(全类名): " + class3);

        // 获取当前线程的类加载器
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        Class<?> class4 = classLoader.loadClass("com.example.myapplication.MysteryBox");
        System.out.println("通过全类名获取 classLoader.loadClass(全类名): " + class4);
    }

    // 如何判断是否为某个类的实例
    @Test
    public void checkInstanceOf(){
        MysteryBox box = new MysteryBox();
        // instanceof 关键字
        System.out.println(box instanceof MysteryBox);

        // class.instanceof
        System.out.println(MysteryBox.class.isInstance(box));

        // isAssignableFrom
        System.out.println(box.getClass().isAssignableFrom(MysteryBox.class));
    }

    //创建实例
    @Test
    public void createInstance() throws Exception{
        Class<?> class1 = MysteryBox.class;

        // 使用newInstance得到MysteryBox的实例/对象box1,最终访问实例方法
        MysteryBox box1 = (MysteryBox) class1.newInstance();
        System.out.println(box1);
        System.out.println(box1.getContent());

        // 通过Constructor构造器得到MysteryBox的实例/对象box1,最终访问实例方法
        Constructor<?> constructor = class1.getConstructor();
        Object box2 = constructor.newInstance();
        MysteryBox mysteryBox2 = (MysteryBox) box2;
        System.out.println(mysteryBox2);
        System.out.println(mysteryBox2.getContent());
    }

    //获取构造器信息
    @Test
    public void getConstructor() throws Exception{
        //1.getConstructor
        Constructor<?> constructor = MysteryBox.class.getConstructor();
        System.out.println(constructor);
        //1.1打印int参数的构造函数
        Constructor<?> constructorInt = MysteryBox.class.getConstructor(int.class);
        System.out.println(constructorInt);

        //2.getConstructors获取全部的构造函数,此方法只能获取public方法修饰的方法
        Constructor<?>[] constructors = MysteryBox.class.getConstructors();
        System.out.println(Arrays.toString(constructors));

        //3.getDeclaredConstructor 获取private修饰的构造函数
        Constructor<?> constructorStr = MysteryBox.class.getDeclaredConstructor(String.class);
        System.out.println(constructorStr);

        //4.getDeclaredConstructors 获取全部的构造函数包括private的构造函数
        Constructor<?>[] constructorsAll = MysteryBox.class.getDeclaredConstructors();
        System.out.println(Arrays.toString(constructorsAll));
    }

    // 获取class类的成员变量/属性
    @Test
    public void getFields() throws Exception{
        MysteryBox box = new MysteryBox();

        // 获取public修饰的属性
        Field priceField = MysteryBox.class.getField("price");
        System.out.println(priceField.get(box));

        // 获取全部public修饰的属性
        Field[] priceFields = MysteryBox.class.getFields();
        System.out.println(Arrays.toString(priceFields));
        for (Field field: priceFields){
            System.out.println(field.get(box));
        }

        // 获取 private 修饰的属性
        Field contentField = MysteryBox.class.getDeclaredField("content");
        contentField.setAccessible(true);
        System.out.println(contentField.get(box));

        // 获取全部 private 修饰的属性
        Field[] contentFields = MysteryBox.class.getDeclaredFields();
        for (Field contentField1: contentFields){
            contentField1.setAccessible(true);
            System.out.println(contentField1.get(box));
        }
    }

    // 获取⽅法
    @Test
    public void getFun() throws Exception {
        MysteryBox box = new MysteryBox();
        // 获取 public 修饰的方法
        Method getContent = MysteryBox.class.getMethod("getContent");
        Object Content = getContent.invoke(box);
        System.out.println(Content);

        // 获取全部 public 修饰的方法
        Method[] getFunS = MysteryBox.class.getMethods();
        for (Method i: getFunS){
            // 打印所有的方法
            System.out.println(i);
        }

        // 获取 publics 修饰的方法
        Method funClose = MysteryBox.class.getDeclaredMethod("close");
        box.open();
        System.out.println(box.getContent());
        funClose.setAccessible(true);
        funClose.invoke(box);
        System.out.println(box.getContent());

        // 获取全部 publics 修饰的方法
        Method[] funS = MysteryBox.class.getDeclaredMethods();
        for (Method i: funS){
            // 打印所有的方法
            System.out.println(i);
        }
    }
}
  • 9
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我是花臂不花

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值