反射调用
1 2 3 4 5 6 7 8 9 10 11 12 13
| public void reflectMethod() { System.out.println("反射测试成功!!!"); } public static void main(String[] args) { try { Class c = Class.forName("com.reflect.ReflectTest"); // 创建Class对象 Object m = c.newInstance(); // 创建类实例对象 Method method = c.getMethod("reflectMethod"); // 获取reflectMethod方法 method.invoke(m); // 调用类实例对象方法 } catch (Exception e) { e.printStackTrace(); } }
|

Java-反射-利用反射构造Runtime类执行
可以看到先创建class对象再创建实例对象,再获取对应方法,最后再调用就可以成功调用了ReflectTemo方法,那么Runtime是否也可以这样反射呢?
按照该思路,进行编写代码
1 2 3 4 5 6
| public static void main(String[] args) throws Exception { Class c1 = Class.forName("java.lang.Runtime"); Object m = c1.newInstance(); Method method = c1.getMethod("exec", String.class); method.invoke(m,"/System/Applications/Calculator.app/Contents/MacOS/Calculator"); }
|
发现报错,原因是因为Runtime类的构造方法是私有的,这里就涉及到了单例模式。比如当web应用来说,数据库连接只用建立连接一次就可以,而不是每次用到都新建连接,此时就可以将数据库连接使用的构造方法设置为私有,使用静态方法来获取

此时不能newIntance创建类对象,就可以使用getMethod通过反射获取Runtime类下的exec方法

可以看到exec有六个重载方法,第一个最简单,尝试获取第一个。
这里再说下invoke,invoke作用是执行方法,
1 2 3 4 5 6 7
| public static void main(String[] args) throws Exception { Class clazz = Class.forName("java.lang.Runtime"); Method execMethod = clazz.getMethod("exec", String.class); Method getRuntimeMethod = clazz.getMethod("getRuntime"); Object runtime = getRuntimeMethod.invoke(clazz); execMethod.invoke(runtime, "/System/Applications/Calculator.app/Contents/MacOS/Calculator"); }
|

精简一下代码
1 2
| Class c1 = Class.forName("java.lang.Runtime"); c1.getMethod("exec", String.class).invoke(c1.getMethod("getRuntime").invoke(c1),"/System/Applications/Calculator.app/Contents/MacOS/Calculator");
|
总结一下invoke,invoke第一个参数:
如果这个方法是一个普通方法,那么第一个参数是类对象。
如果这个方法是一个静态方法,那么第一个参数就是类。
Java-反射-设置setAccessible(true)暴力访问权限
在一般情况下,我们使用反射机制不能对类的私有private字段进行操作,绕过私有权限的访问。但一些特殊场景存在例外的时候,比如我们进行序列化操作的时候,需要去访问这些受限的私有字段,这时我们可以通过调用AccessibleObject上的setAccessible()方法来允许访问。
Java.lang.reflect.AccessibleObject类是Field,Method和Constructor类对象的基类,可以提供将反射对象标记为使用它抑制摸人Java访问控制检查的功能,同时上述的反射类中的Field,Method和Constructor继承自AccessibleObject。所以我们在这些类方法基础上调用setAccessible()方法,既可对这些私有字段进行操作。
所有我们最开始的代码再修改简略下,就能成功命令执行了。
1 2 3 4 5 6
| public static void main(String[] args) throws Exception { Class c1= Class.forName("java.lang.Runtime"); Constructor m = c1.getDeclaredConstructor(); m.setAccessible(true); c1.getMethod("exec", String.class).invoke(m.newInstance(), "/System/Applications/Calculator.app/Contents/MacOS/Calculator"); }
|