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);
}
七、常见问题与注意事项
-
异常处理:反射操作需要处理多种异常,如
ClassNotFoundException、NoSuchMethodException等 -
私有成员访问:访问私有构造方法、字段或方法时,必须先调用
setAccessible(true) -
JDK版本差异:特别是数组参数的处理方式在不同JDK版本中有差异
-
性能考虑:反射操作比直接调用性能低,应避免在性能敏感场景过度使用
-
安全限制:反射可能绕过访问控制,使用时需注意安全影响
-
包引用问题:IDE可能自动引入错误包,需检查import语句是否正确
通过掌握这些反射技术,开发者可以实现高度灵活的Java程序,但也应注意合理使用,避免滥用带来的性能和安全问题。