Java代码审计基础之反射
字数 835 2025-08-15 21:31:25

Java反射机制深入解析与实战应用

一、反射基础概念

反射(Reflection)是Java语言的一种强大特性,它允许程序在运行时动态地:

  • 装载类
  • 查看类的信息
  • 生成对象
  • 操作生成的对象

核心思想:类在运行时可以获取自身信息,并能动态修改这些信息。

二、获取Class对象的三种方式

1. 直接通过类名获取

Class a = Cat.class;

2. 通过Class.forName获取

Class a = Class.forName("org.xiaopan.test.Cat");

注意:需要处理ClassNotFoundException异常

3. 通过实例化对象获取

Class a = (new Cat()).getClass();

三、反射构造方法

示例类定义

class Cat {
    public Cat() {
        System.out.println("Cat->nullCat");
    }
    
    public Cat(String a) {
        System.out.println("Cat->aCat,a=" + a);
    }
    
    private Cat(String a, Integer b) {
        System.out.println("Cat->abCat,a=" + a + "b=" + b.toString());
    }
    
    public Cat(String[] aa, Map bb) {
        System.out.println("Cat->aabbCat");
        System.out.println("aa=" + Arrays.toString(aa));
        System.out.println("bb=" + bb);
    }
}

1. 无参构造方法调用

try {
    Class a = Cat.class;
    Constructor constructor1 = a.getConstructor(null);
    constructor1.newInstance(null);
} catch (Exception e) {
    System.out.println(e);
}

2. 单参数构造方法调用

try {
    Class a = Cat.class;
    Constructor constructor1 = a.getConstructor(String.class);
    constructor1.newInstance("testvalue");
} catch (Exception e) {
    System.out.println(e);
}

3. 私有构造方法调用

try {
    Class a = Class.forName("org.xiaopan.test.Cat");
    Constructor c = a.getDeclaredConstructor(String.class, Integer.class);
    c.setAccessible(true);  // 设置强制反射
    c.newInstance(new Object[]{"abcd", 123456});
} catch (Exception e) {
    System.out.println(e);
}

注意:JDK版本差异处理

  • JDK1.4:数组每个元素对应一个参数
  • JDK1.5+:整个数组是一个参数,需要用Object包裹

4. 数组和Map参数的构造方法调用

try {
    Class a = (new Cat()).getClass();
    Constructor c = a.getConstructor(String[].class, Map.class);
    Map m = new HashMap();
    m.put("a_key", "a_value");
    c.newInstance(new Object[]{new String[]{"a","b","c"}, m});
} catch (Exception e) {
    System.out.println(e);
}

四、反射方法

示例类定义

class Cat {
    public void a() {
        System.out.println("a invoke");
    }
    
    public String[] b(String[] b) {
        return b;
    }
    
    public static void c() {
        System.out.println("cccccc");
    }
}

1. 无参数方法调用

try {
    Class a = Class.forName("org.xiaopan.test.Cat");
    Cat cat = (Cat) a.newInstance();
    Method m = a.getMethod("a", null);
    m.invoke(cat, null);
} catch (Exception e) {
    System.out.println(e);
}

2. 有参数有返回值方法调用

try {
    Class a = Class.forName("org.xiaopan.test.Cat");
    Cat cat = (Cat) a.newInstance();
    Method m = a.getMethod("b", String[].class);
    String[] strs = (String[]) m.invoke(cat, new Object[]{new String[]{"str1","str2","str3"}});
    for (String str : strs) {
        System.out.println(str);
    }
} catch (Exception e) {
    System.out.println(e);
}

3. 静态方法调用

try {
    Class a = Class.forName("org.xiaopan.test.Cat");
    Method m = a.getMethod("c");
    m.invoke(null);
} catch (Exception e) {
    System.out.println(e);
}

五、反射属性

示例类定义

class Cat {
    public String name = "maomao";
    public static Boolean sex = true;
    private Integer age = 10;
}

1. 公共属性访问

try {
    Class a = Class.forName("org.xiaopan.test.Cat");
    Cat cat = (Cat) a.newInstance();
    Field m = a.getField("name");
    String name = (String) m.get(cat);
    System.out.println(name);
} catch (Exception e) {
    System.out.println(e);
}

2. 公共静态属性访问

try {
    Class a = Class.forName("org.xiaopan.test.Cat");
    Field m = a.getField("sex");
    Boolean b = (Boolean) m.get(null);
    System.out.println(b);
    m.set(null, false);
    b = (Boolean) m.get(null);
    System.out.println(b);
} catch (Exception e) {
    System.out.println(e);
}

3. 私有属性访问

try {
    Class a = Class.forName("org.xiaopan.test.Cat");
    Cat cat = (Cat) a.newInstance();
    Field m = a.getDeclaredField("age");
    m.setAccessible(true);
    Integer age = (Integer) m.get(cat);
    System.out.println(age.toString());
} catch (Exception e) {
    System.out.println(e);
}

六、反射执行系统命令

1. 常规命令执行方式

byte[] a = new byte[1024];
Process cmd = Runtime.getRuntime().exec("whoami");
InputStream input = cmd.getInputStream();
input.read(a);
String res = new String(a);
System.out.println(res);

2. 反射方式一:反射私有构造方法

byte[] a = new byte[1024];
try {
    Class runtime = Class.forName("java.lang.Runtime");
    Constructor c_runtime = runtime.getDeclaredConstructor();
    c_runtime.setAccessible(true);
    Runtime r = (Runtime) c_runtime.newInstance();
    Method m = runtime.getMethod("exec", String.class);
    Process p = (Process) m.invoke(r, "whoami");
    p.getInputStream().read(a);
    System.out.println(new String(a));
} catch (Exception e) {
    System.out.println(e);
}

3. 反射方式二:通过getRuntime方法

byte[] a = new byte[1024];
try {
    Class runtime = Class.forName("java.lang.Runtime");
    Method m = runtime.getMethod("getRuntime");
    Runtime r = (Runtime) m.invoke(null);
    Process p = r.exec("ifconfig");
    InputStream res = p.getInputStream();
    res.read(a);
    System.out.println(new String(a));
} catch (Exception e) {
    System.out.println(e);
}

七、常见问题与注意事项

  1. 异常处理:反射操作需要处理多种异常,如ClassNotFoundExceptionNoSuchMethodException

  2. 私有成员访问:访问私有构造方法、字段或方法时,必须先调用setAccessible(true)

  3. JDK版本差异:特别是数组参数的处理方式在不同JDK版本中有差异

  4. 性能考虑:反射操作比直接调用性能低,应避免在性能敏感场景过度使用

  5. 安全限制:反射可能绕过访问控制,使用时需注意安全影响

  6. 包引用问题:IDE可能自动引入错误包,需检查import语句是否正确

通过掌握这些反射技术,开发者可以实现高度灵活的Java程序,但也应注意合理使用,避免滥用带来的性能和安全问题。

Java反射机制深入解析与实战应用 一、反射基础概念 反射(Reflection)是Java语言的一种强大特性,它允许程序在运行时动态地: 装载类 查看类的信息 生成对象 操作生成的对象 核心思想:类在运行时可以获取自身信息,并能动态修改这些信息。 二、获取Class对象的三种方式 1. 直接通过类名获取 2. 通过Class.forName获取 注意:需要处理 ClassNotFoundException 异常 3. 通过实例化对象获取 三、反射构造方法 示例类定义 1. 无参构造方法调用 2. 单参数构造方法调用 3. 私有构造方法调用 注意:JDK版本差异处理 JDK1.4:数组每个元素对应一个参数 JDK1.5+:整个数组是一个参数,需要用Object包裹 4. 数组和Map参数的构造方法调用 四、反射方法 示例类定义 1. 无参数方法调用 2. 有参数有返回值方法调用 3. 静态方法调用 五、反射属性 示例类定义 1. 公共属性访问 2. 公共静态属性访问 3. 私有属性访问 六、反射执行系统命令 1. 常规命令执行方式 2. 反射方式一:反射私有构造方法 3. 反射方式二:通过getRuntime方法 七、常见问题与注意事项 异常处理 :反射操作需要处理多种异常,如 ClassNotFoundException 、 NoSuchMethodException 等 私有成员访问 :访问私有构造方法、字段或方法时,必须先调用 setAccessible(true) JDK版本差异 :特别是数组参数的处理方式在不同JDK版本中有差异 性能考虑 :反射操作比直接调用性能低,应避免在性能敏感场景过度使用 安全限制 :反射可能绕过访问控制,使用时需注意安全影响 包引用问题 :IDE可能自动引入错误包,需检查import语句是否正确 通过掌握这些反射技术,开发者可以实现高度灵活的Java程序,但也应注意合理使用,避免滥用带来的性能和安全问题。