本篇文章记录学习Java反射 。 JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性
获取Class类
•根据类名:类名.class•根据对象:对象.getClass()•根据全限定类名:Class.forName(全限定类名)
package 反射;
import java.lang.reflect.InvocationTargetException;
public class demo {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Test test = new Test();
System.out.println(test);
// .class根据类名 获取class对象
Class s = Test.class;
System.out.println(s);
// .getClass 根据对象,获取class对象
Class s1 = new Test().getClass();
System.out.println(s1);
// .forName
Class s2 = Class.forName("反射.Test");
System.out.println(s2);
}
}
获取Class类中的构造方法 getConstructor
获取Constructor对象是通过Class类中的方法获取的,Class类与Constructor相关的主要方法如下:
方法名称 | 方法说明 |
forName(String ClassName) | 返回与带有给定字符串名的类或接口相关联的 Class 对象。 |
getConstructor(Class<>.. parameterTypes) | 返回指定参数类型、具有public访问权限的构造函数对象 |
getConstructors() | 返回所有具有public访问权限的构造函数的Constructor对象数组 |
getDeclaredConstructor(Class<>.. parameterTypes) | 返回指定参数类型、所有声明的(包括private)构造函数对象 |
getDeclaredConstructors() | 返回所有声明的(包括private)构造函数对象 |
newInstance() | 调用无参构造器创建此 Class 对象所表示的类的一个新实例。 |
获取一个无参的构造方法
在Test 类中设置了,无参的构造方法
package 反射;
public class Test {
// 定义成员变量
public String name="xiaomi";
public int age = 18;
public Test(){
}
// public Test(String name){
// this.name = name;
// }
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
package 反射;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class demo {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {
try {
// .forName 根据全限名称获取class对象
Class<?> clazz = Class.forName("反射.Test");
// 获取一个无参的构造方法
Object instance = clazz.getConstructor().newInstance();
System.out.println("构造方法的类:"+clazz.getName());
} catch (Exception e) {
e.printStackTrace();
}
}
}
获取一个有参的构造方法
Test类中构造方法,接收了一个String类型的变量
public Test(String name){
this.name = name;
}
在getConstructor 中要定义一个 String.class
package 反射;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class demo {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {
try {
// .forName 根据全限名称获取class对象
Class<?> clazz = Class.forName("反射.Test");
// getConstructor 获取构造方法
Object instance = clazz.getConstructor(String.class).newInstance("我是构造方法");
String name = (String) clazz.getMethod("getName").invoke(instance);
System.out.println(name);
} catch (Exception e) {
e.printStackTrace();
}
}
}
获取Class类中的私有 (private) 构造方法 getDeclaredConstructor
示例
package 反射;
public class Test2 {
// 定义成员变量
public String name="xiaomi";
public int age = 18;
private Test2(){
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
package 反射;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class demo2 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {
try {
Class<?> clazz = Class.forName("反射.Test2");
Constructor<?> constructor = clazz.getDeclaredConstructor();
constructor.setAccessible(true);
Object ins = constructor.newInstance();
String name = (String) clazz.getMethod("getName").invoke(ins);
System.out.println(name);
}catch (Exception e){
e.printStackTrace();
}
}
}
获取class类中 Method 方法
下面是Class类获取Method对象相关的方法:
方法名称 | 方法说明 |
getDeclaredMethod() | 返回一个指定参数的Method对象,该对象反映此 Class 对象所表示的类或接口的指定已声明方法。public private |
getDeclaredMethods() | 返回 Method 对象的一个数组,这些对象反映此 Class 对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。 |
getMethod() | 返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法。public |
getMethods() | 返回一个包含某些 Method 对象的数组,这些对象反映此 Class 对象所表示的类或接口(包括那些由该类或接口声明的以及从超类和超接口继承的那些的类或接口)的公共 member 方法。 |
例如:我需要获取Test类中的getName方法
package 反射;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class demo {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {
try {
// .forName 根据全限名称获取class对象
Class<?> clazz = Class.forName("反射.Test");
// getConstructor 获取构造方法
Object instance = clazz.getConstructor(String.class).newInstance("name 是 getName ");
String name = (String) clazz.getMethod("getName").invoke(instance);
System.out.println(name);
} catch (Exception e) {
e.printStackTrace();
}
}
}
获取class类中的FieId
Class类与Field对象相关方法如下:
方法返回值 | 方法名称 | 方法说明 |
Field | getDeclaredField(String name) | 获取指定name名称的(包含private修饰的)字段,不包括继承的字段 |
Field[] | getDeclaredFields() | 获取Class对象所表示的类或接口的所有(包含private修饰的)字段,不包括继承的字段 |
Field | getField(String name) | 获取指定name名称、具有public修饰的字段,包含继承字段 |
Field[] | getFields() | 获取修饰符为public的字段,包含继承字段 |
package 反射;
import java.lang.reflect.Field;
public class demoFieId {
public static void main(String[] args) {
try {
Class<?> clazz = Class.forName("反射.Test2");
Test2 st= (Test2) clazz.newInstance();
Field name = clazz.getField("name");
// 修改name的值
name.set(st,"wdd");
System.out.println(st.name.toString());
}catch (Exception e){
e.printStackTrace();
}
}
}
使用反射系统执行命令类
获取类的⽅法: forName 实例化类对象的⽅法: newInstance 获取函数的⽅法: getMethod 执⾏函数的⽅法: invoke
getMethod 系列方法获取的是当前类中所有公共方法,包括从父类继承的方法 getDeclaredMethod 系列方法获取的是当前类中“声明”的方法,是实在写在这个类里的,包括私有的方法,但从父类里继承来的就不包含了
invoke 的作用是执行方法,它的第一个参数是:
如果这个方法是一个普通方法,那么第一个参数是类对象
如果这个方法是一个静态方法,那么第一个参数是类
创建恶意的类,用来演示forName 反射加载类
创建执行弹出计算器的类
package reflex.test;
public class calc {
static {
try {
Runtime rt = Runtime.getRuntime();
String[] commands = {"calc.exe"};
Process pc = rt.exec(commands);
pc.waitFor();
} catch (Exception e) {
// do nothing
}
}
}
通过Class.forName 反射加载恶意类,实现命令执行
package reflex.test;
import java.lang.reflect.InvocationTargetException;
public class demo1 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class clazz = Class.forName("reflex.test.calc"); //通过forName 反射通用calc恶意类
}
}
java.lang.Runtime
单列模式 getRuntime
Runtime类就是单例模式,我们只能通过 Runtime.getRuntime() 来获取到 Runtime 对象。
package 反射;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class cmd {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {
try{
// java.lang.Runtime
// 使用反射 java.lang.Runtime 执行calc
Class<?> clazz = Class.forName("java.lang.Runtime");
clazz.getMethod("exec", String.class).invoke(clazz.getMethod("getRuntime").invoke(clazz),"calc");
}catch (Exception e){
e.printStackTrace();
}
}
}
private 私有Runtime
package 反射;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class cmd {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {
try{
Class<?> clazz = Class.forName("java.lang.Runtime");
Constructor<?> m = clazz.getDeclaredConstructor();
m.setAccessible(true);
clazz.getMethod("exec", String.class).invoke(m.newInstance(),"calc");
}catch (Exception e){
e.printStackTrace();
}
}
}
java.lang.ProcessBuilder
ProcessBuilder有两个构造函数
public ProcessBuilder(List<String> command) {
if (command == null)
throw new NullPointerException();
this.command = command;
}
/**
* Constructs a process builder with the specified operating * system program and arguments. This is a convenience * constructor that sets the process builder's command to a string * list containing the same strings as the {@code command} * array, in the same order. It is not checked whether * {@code command} corresponds to a valid operating system * command. * * @param command a string array containing the program and its arguments
*/public ProcessBuilder(String... command) {
this.command = new ArrayList<>(command.length);
for (String arg : command)
this.command.add(arg);
}
正常调用 ProcessBuilder
ProcessBuilder p = new ProcessBuilder();
p.command("calc").start();
反射调用 ProcessBuilder
ProcessBuilder List.class
package reflex.test;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.List;
public class demo4 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {
Class classz = Class.forName("java.lang.ProcessBuilder");
classz.getMethod("start").invoke(classz.getConstructor(List.class).newInstance(Arrays.asList("calc.exe")));
}
}
ProcessBuilder String[].class
package 反射;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class demo3 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {
try{
Class<?> clazz = Class.forName("java.lang.ProcessBuilder");
clazz.getMethod("start").invoke(clazz.getConstructor(String[].class).newInstance(new String[][]{{"calc.exe"}}));
}catch (Exception e){
e.printStackTrace();
}
}
}