反射 Reflection(反射) 是 Java 程序开发语言的特征之一,反射允许运行中的Java程序在运行时获取一个类的所有信息,可以获取到任何定义的信息(包括成员变量,成员方法,构造器等),并且可以操纵类的字段、方法、构造器等部分,甚至能直接操作程序的私有属性。
 
获取class类对象 我们正常类加载的方式是:
而反射可以利用下面三种方法获取字节码对象:
1 2 3 4 Class.forName("类的全路径"); 类名.class 对象.getClass(); classLoader.loadClass("类的全路径");  
 
实现反射相关API:
1 2 3 4 java.lang.Class           代表一个类 java.lang.reflect.Method  代表类的方法 java.lang.reflect.Field   代表类的成员属性 java.lang.reflect.Constructor  代表类的构造方法 
 
举个例子
Person.java
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 40 41 42 43 44 45 public class Person {     public String name;     private int age;     public Person(){}     public Person(String name, int age) {         this.name = name;         this.age = age;     }     public Person(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;     }     private String show(String name) {         //System.out.println(name+"");         return name+"正在洗澡";     }     private static void teststatic(){         System.out.println("static method start");     }     @Override     public String toString() {         return "Person{" +                 "name='" + name + '\'' +                 ", age=" + age +                 '}';     } } 
 
User.java
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 public class User extends Person{     private int id;     private String username;     private String password;     public int age;     public User(){}     public User(int id, String username, String password, int age) {         this.id = id;         this.username = username;         this.password = password;         this.age = age;     }     public String getUsername() {         return username;     }     public void setUsername(String username) {         this.username = username;     }     private void show(String username,String password) {         System.out.println("用户名:"+username+",密码:"+password);     }     public void study(String username) {         System.out.println(username+"正在学习~");     }     @Override     public String toString() {         return "User{" +                 "id=" + id +                 ", username='" + username + '\'' +                 ", password='" + password + '\'' +                 ", age=" + age +                 '}';     } } 
 
获取class类对象的四种方法
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 public class Test {     public static void main(String[] args) {             //1.获取class对象             User user1 = new User();             Class c1 = user1.getClass();             System.out.println("第一种"+c1);             //2.通过类的方式获取             Class c2 = User.class;             System.out.println("第二种"+c2);             //3.class.forName() 将字节码文件加载到内存             Class c3;             try {                 c3 = Class.forName("User");                 System.out.println("第三种"+c3);             } catch (ClassNotFoundException e) {                 e.printStackTrace();             }             //4. classLoader 类加载器             ClassLoader classLoader = Test.class.getClassLoader();             Class aClass = null;             try {                 aClass = classLoader.loadClass("User");             } catch (ClassNotFoundException e) {                 e.printStackTrace();             }             System.out.print("第四种"+aClass);     } } 
 
获取成员属性 1 2 3 4 getFields()          获取所有public修饰的成员属性,包括父类 getDeclaredFields()  获得当前类的所有属性,包括private getField(变量名) getDeclaredField(变量名) 
 
获取成员属性的四个方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public void geFieldTest() throws ClassNotFoundException, NoSuchFieldException {         System.out.println("getDeclaredFields方法");         Class c = Class.forName("User");         Field[] fields = c.getDeclaredFields();         for (Field f : fields) {             System.out.println(f);         }         System.out.println("getFields方法");         Field[] fields1 = c.getFields();         for (Field field : fields1) {             System.out.println(field);         }         System.out.println("getField方法");         Field name = c.getField("name");         System.out.println( name.toString());         System.out.println("getDeclaredField方法");         Field id2 = c.getDeclaredField("id");         System.out.println( id2.toString());     } 
 
获取构造方法 1 2 3 4 5 获取构造方法定义信息 getConstructor(参数类型列表)//获取公开的构造方法 getConstructors()//获取所有的公开的构造方法 getDeclaredConstructors()//获取所有的构造方法,包括私有 getDeclaredConstructor(int.class,String.class)//获得当前类指定的构造方法 
 
获取构造方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public void getConstructorTest() throws ClassNotFoundException, NoSuchMethodException {         Class clazz = Class.forName("User");         System.out.println("getDeclaredConstructors方法:");         Constructor[] cs = clazz.getDeclaredConstructors();         for (Constructor con : cs) {             System.out.println(con);         }         System.out.println("getConstructors方法:");         Constructor[] cs1 = clazz.getConstructors();         for (Constructor con : cs1) {             System.out.println(con);         }         System.out.println("getConstructor方法:");         Constructor constructor = clazz.getConstructor();         System.out.println(constructor);         System.out.println("getDeclaredConstructor方法:");         Constructor declaredConstructor1 = clazz.getDeclaredConstructor(int.class, String.class, String.class, int.class);         System.out.println(declaredConstructor1);     } 
 
获取父类的构造方法:
1 2 3 4 5 6 7 8 public void getFatherConstructorTest() throws ClassNotFoundException {         Class clazz = Class.forName("User");         Class superclass = clazz.getSuperclass();         Constructor[] cs = superclass.getDeclaredConstructors();         for (Constructor con : cs) {             System.out.println(con);         }     } 
 
获取成员方法 1 2 3 4 getMethods ()getMethod (方法名,参数类型列表)getDeclaredMethods ()getDeclaredMethod ()
 
获取成员方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public void getMethod() throws ClassNotFoundException, NoSuchMethodException {         Class c = Class.forName("User");         System.out.println("getDeclaredMethods方法:");         Method[] method = c.getDeclaredMethods();         for (Method meth : method) {             System.out.println(meth);         }         System.out.println("getDeclaredMethod方法:");         Method show = c.getDeclaredMethod("show", String.class,String.class);         System.out.println(show);         System.out.println("getMethods方法:");         Method[] method1 = c.getMethods();         for (Method meth : method1) {             System.out.println(meth);         }         System.out.println("getMethod方法:");         Method study = c.getMethod("study", String.class);         System.out.println(study);     } 
 
反射调用属性 调用属性:
1 2 3 4 5 6 7 8 9 public void getFieldValue() throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {         Class c = Class.forName("User");         Field agefield = c.getField("age");         User u = new User(1,"jack","123456",18);         System.out.println(agefield.getInt(u));         Field usernamefield = c.getDeclaredField("username");         usernamefield.setAccessible(true);         System.out.println(usernamefield.get(u));     } 
 
反射调用方法 调用方法:
1 2 3 4 5 6 7 8 9 public void getMethodValue() throws ClassNotFoundException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {         Class c = Class.forName("User");         Method study = c.getDeclaredMethod("study", String.class);         User u = new User(1,"jack","123456",18);         study.invoke(u, "jack");         Method show = c.getDeclaredMethod("show", String.class,String.class);         show.setAccessible(true);         show.invoke(u,"test","123");     } 
 
想要访问show()方法,使用getDeclaredMethod()方法,并传入方法名,以及形参。又因为该方法为private,所以需要使用setAccessible()设置访问权限。
注:setAccessible作用是启动和禁止访问安全检查的开关,参数为true表示反射的对象在使用时应该取消java语言访问检查,参数为false则表示反射的对象实施对java语言的访问检查。 
反射创建对象 上面的例子我们是用new的方式来创建的对象,也可以通过反射创建对象
1 2 Class.newInstance()   只能够调用无参的构造方法,即默认的构造方法;要求构造方法必须是public类型的。 Constructor.newInstance() 可以根据传入的参数,调用任意的构造方法; 特定情况下可以调用私有的构造方法。 
 
创建对象:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public void getInstance() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {         // 1. 获得class对象         Class clazz = Class.forName("User");         // 2. 获取无参构造器         Constructor declaredConstructor = clazz.getDeclaredConstructor();         // 3. Constructor.newInstance() 创建对象         Object test = declaredConstructor.newInstance();         User user = (User) test;         // 4. 获取方法         Method study = clazz.getDeclaredMethod("study", String.class);         study.invoke(user, "jack");         Object o = clazz.newInstance();         User user1 = (User) o;         Method show = clazz.getDeclaredMethod("show", String.class, String.class);         show.setAccessible(true);         show.invoke(user, "jack","123");     } 
 
因为User类有两个构造方法,我们尝试用另一个有参构造器
1 2 3 4 5 6 7 8 9 10 11 12 13 public void getInstance1() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { 		// 1. 获得class对象 		Class clazz = Class.forName("User");         // 2. 获取有参构造器         Constructor declaredConstructor2 = clazz.getDeclaredConstructor(int.class,String.class,String.class,int.class);         // 3. Constructor.newInstance() 创建对象         Object test1 = declaredConstructor2.newInstance(1,"jack","123",18);         User user2= (User) test1;         System.out.println(user2.toString());         // 4. 获取方法         Method study1 = clazz.getDeclaredMethod("study", String.class);         study1.invoke(user2,"jack");     } 
 
结论为:在newInstance创建对象的时候,对应有参构造器,传入形参。
再尝试反射创建对象并调用public show() 私有方法
1 2 3 4 5 6 7 8 		Class clazz = Class.forName("User"); 		Constructor declaredConstructor2 = clazz.getDeclaredConstructor(int.class,String.class,String.class,int.class);         Object test1 = declaredConstructor2.newInstance(1,"jack","123",18);         User user2= (User) test1;         System.out.println(user2.toString()); Method show1 = clazz.getDeclaredMethod("show", String.class,String.class);         show1.setAccessible(true);         show1.invoke(user2,"jack","123456"); 
 
应用 反射调用命令执行常用到的Runtime类
正常使用Runtime类执行系统命令为
1 2 3 4 Process p = Runtime.getRuntime().exec("calc"); //使用ProcessBuilder类进行命令执行 new ProcessBuilder(new String[]{"calc.exe"}).start(); 
 
反射的过程首先获得Runtime类,再查看该类的构造方法
1 2 3 4 5 Class clazz = Class.forName("java.lang.Runtime"); Constructor[] declaredConstructors = clazz.getDeclaredConstructors();         for(Constructor con : declaredConstructors){             System.out.print(con);         } 
 
只有一个私有的无参构造器,获取该构造器并通过setAccessible设置访问权限。
1 2 Constructor declaredConstructor = clazz.getDeclaredConstructor(); declaredConstructor.setAccessible(true); 
 
有了构造器,就可以通过构造器创建对象
1 Object o = declaredConstructor.newInstance(); 
 
查看当前类的所有方法
1 2 3 4 Method[] declaredMethods = clazz.getDeclaredMethods(); for(Method meth : declaredMethods){    System.out.println(meth); } 
 
可以看到exec()方法对应的都是public属性,且可以传入String类型,也可以传入String[]类型,比如使用传入String类型的方法,那在getDeclaredMethod()方法后传入的第一个参数为exec()方法名,第二个参数为String.class。
1 Method method = clazz.getDeclaredMethod("exec", String.class); 
 
并使用invoke()方法执行exec()方法
1 method.invoke(o,"calc.exe"); 
 
所以综上,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 public void getRuntimeExec() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {     // 1. 获得class对象     Class clazz = Class.forName("java.lang.Runtime");     // 2. 获取无参构造器     Constructor declaredConstructor = clazz.getDeclaredConstructor();     declaredConstructor.setAccessible(true);     // 3. Constructor.newInstance() 创建对象     Object o = declaredConstructor.newInstance();     //Runtime o1 = (Runtime) o;     // 4. 获取方法     Method show = clazz.getDeclaredMethod("exec", String.class);     show.invoke(o,"calc.exe"); } 
 
也可以调用传入String[] 参数类型的方法
1 2 3 4 5 6 7 8 9 public void getRuntimeExecs() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {         Class clazz = Class.forName("java.lang.Runtime");         Constructor declaredConstructor = clazz.getDeclaredConstructor();         declaredConstructor.setAccessible(true);         Object o = declaredConstructor.newInstance();         String[] cmd = new String[]{"cmd.exe", "-c", "calc.exe"};         Method method = clazz.getDeclaredMethod("exec", String[].class);         method.invoke(o, cmd);     } 
 
同样,ProcessImpl类、ProcessBuilder类也可以反射调用执行系统命令
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  //ProcessBuilder类->获取传入List.class的构造      public void getProcessBuilder1() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, IOException {         Class clazz = Class.forName("java.lang.ProcessBuilder");         Constructor declaredConstructor = clazz.getDeclaredConstructor(List.class);         ArrayList<Object> lists = new ArrayList<>();         lists.add("calc.exe");         Object o = declaredConstructor.newInstance((List) lists);         Method start = clazz.getDeclaredMethod("start");         start.invoke(o);     }      //ProcessBuilder类->获取传入String[].class的构造 public void getProcessBuilder2() throws ClassNotFoundException, IOException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {         new ProcessBuilder().command("calc.exe").start();         Class clazz = Class.forName("java.lang.ProcessBuilder");         String[] cmds = new String[]{"calc.exe"};         Constructor declaredConstructors = clazz.getDeclaredConstructor(String[].class);         Object o = declaredConstructors.newInstance((Object) cmds);         Method command = clazz.getDeclaredMethod("start");         command.invoke(o);     }          //ProcessImpl类     public void getProcessImpl1() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {         Class clazz = Class.forName("java.lang.ProcessImpl");         Constructor[] declaredConstructors = clazz.getDeclaredConstructors();         String[] cmds = new String[]{"calc.exe"};         Method startMethod = clazz.getDeclaredMethod("start", String[].class, Map.class, String.class, ProcessBuilder.Redirect[].class, boolean.class);         startMethod.setAccessible(true);         startMethod.invoke(null, cmds, null, null,null, false);//这里需要的五个参数,第一个参数为null,因为调用的方法是这个类的静态方法     } 
 
方法清单 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 获取包名 类名 clazz.getPackage().getName()//包名 clazz.getSimpleName()//类名 clazz.getName()//完整类名 获取成员变量定义信息 getFields()//获取所有公开的成员变量,包括继承变量 getDeclaredFields()//获取本类定义的成员变量,包括私有,但不包括继承的变量 getField(变量名) getDeclaredField(变量名) 获取构造方法定义信息 getConstructor(参数类型列表)//获取公开的构造方法 getConstructors()//获取所有的公开的构造方法 getDeclaredConstructors()//获取所有的构造方法,包括私有 getDeclaredConstructor(int.class,String.class) 获取方法定义信息 getMethods()//获取所有可见的方法,包括继承的方法 getMethod(方法名,参数类型列表) getDeclaredMethods()//获取本类定义的的方法,包括私有,不包括继承的方法 getDeclaredMethod(方法名,int.class,String.class) 反射新建实例 clazz.newInstance();//执行无参构造创建对象 clazz.newInstance(666,”海绵宝宝”);//执行含参构造创建对象 clazz.getConstructor(int.class,String.class)//获取构造方法 反射调用成员变量 clazz.getDeclaredField(变量名);//获取变量 clazz.setAccessible(true);//使私有成员允许访问 f.set(实例,值);//为指定实例的变量赋值,静态变量,第一参数给null f.get(实例);//访问指定实例变量的值,静态变量,第一参数给null 反射调用成员方法 Method m = Clazz.getDeclaredMethod(方法名,参数类型列表); m.setAccessible(true);//使私有方法允许被调用 m.invoke(实例,参数数据);//让指定实例来执行该方法 
 
参考