13.Java的反射

二.Java反射

1.概念:反射是框架设计的灵魂

  • 框架:半成品软件。可以在框架的基础上进行软件开发,简化代码。
  • 反射:将类的各个组成部分封装为其他对象,这就是反射机制。
    • 可以在程序运行过程中操作这些对象。
    • 可以解耦提高程序的可扩展行。

2.Java代码在计算机中经历的三个阶段:

  • Source源代码阶段
  • Class类对象阶段
  • Runtime运行时阶段

3.获取class对象的三种方式:

  • Class.forName("全类名"):将字节码文件加载进内存返回class对象。对应Java代码的Source源代码阶段。
    • 用于配置文件:将类名定义在配置文件中,读取配置文件加载类。
  • 类名.class:通过类名的属性class获取。对应Java代码的Class类对象阶段。
    • 用于参数传递。
  • 对象.getClass():getClass()方法在Object类中定义。对应Java代码的Runtime阶段。
    • 用于对象的获取字节码的方式。
  • 结论:对于同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,不论通过哪种方式获取的Class对象都是同一个。

Person类:

 1 public class Person {
 2 
 3     private String name;
 4     private int age;
 5 
 6     public String a;
 7 
 8     public Person() {
 9  } 10 11 private Person(String name) { 12 this.name = name; 13  } 14 15 public Person(String name, int age) { 16 this.name = name; 17 this.age = age; 18  } 19 20 public Person(String name, int age, String a) { 21 this.name = name; 22 this.age = age; 23 this.a = a; 24  } 25 26 27 public String getName() { 28 return name; 29  } 30 31 public void setName(String name) { 32 this.name = name; 33  } 34 35 public int getAge() { 36 return age; 37  } 38 39 public void setAge(int age) { 40 this.age = age; 41  } 42 43  @Override 44 public String toString() { 45 return "Person{" + 46 "name='" + name + '\'' + 47 ", age=" + age + 48 ", a='" + a + '\'' + 49 '}'; 50  } 51 52 public void publicMethod1() { 53 System.out.println("publicMethod1"); 54  } 55 56 public void publicMethod2(String s) { 57 System.out.println("publicMethod2:参数为" + s); 58  } 59 60 private void privateMethod1() { 61 System.out.println("privateMethod1"); 62  } 63 64 private void privateMethod2(String s) { 65 System.out.println("privateMethod2:参数为" + s); 66  } 67 }

主函数:

 1 public class ReflectDemo1 {
 2 
 3     public static void main(String[] args) throws ClassNotFoundException {
 4 
 5         //1.Class.forName("全类名")
 6         Class cls1 = Class.forName("day08.Person");
 7         System.out.println(cls1);
 8 
 9         //2.类名.class
10         Class cls2 = Person.class;
11  System.out.println(cls2); 12 13 //3.对象.getClass() 14 Person p = new Person(); 15 Class cls3 = p.getClass(); 16  System.out.println(cls3); 17 18 19 //比较三个对象是否为同一对象 20 System.out.println(cls1 == cls2); 21 System.out.println(cls1 == cls3); 22  } 23 }

结果:

1 class day08.Person
2 class day08.Person
3 class day08.Person
4 true
5 true

4.Class对象功能

  • 获取功能:
    1. 获取成员变量们:Field类
      • Field[] getFields():获取所有public修饰的成员变量
      • Field getField(String name):利用成员变量名获取public的成员变量
      • Field[] getDeclaredFields():获取所有的成员变量,不考虑修饰符
      • Field getDeclaredField(String name):利用成员变量名获取任意的成员变量
    2. 获取构造函数们:Constructor类
      • Constructor<?>[] getConstructors():获取空参数public构造函数
      • Constructor<T> getConstructor(类<?>...  parameterTypes):根据参数获取到类的public构造函数
      • Constructor<?>[] getDeclaredConstructors():获取空参数任意构造函数
      • Constructor<T> getDeclaredConstructor(类<?>...  parameterTypes):根据参数获取到类的任意构造函数
    3. 获取成员方法们:Method类
      • Method[] getMethods():获取自己以及基类所有public方法
      • Method getMethod(String name,类<?>... parameterTypes):根据参数获得public方法
      • Method[] getDeclaredMethods():获取自己以及基类所有方法
      • Method getDeclaredMethod(String name,类<?>... parameterTypes):根据参数获得任意方法
    4. 获取类名:
      • String getName()
  • Field:成员变量
    • 操作:
      • 设置值:void set(Object obj, Object value)
      • 获取值:get(Object obj)
      • 忽略访问权限修饰符的安全检查(暴力反射):setAccessible(true) 
  • Constructor:构造方法
    • 创建对象:
      • T newInstance(Object... initargs)
      • 如果使用空参数构造方法,则操作可以简化:Class对象的newInstance方法
    • 忽略访问权限修饰符的安全检查(暴力反射):setAccessible(true) 
  • Method:方法对象
    • 执行方法:Object invoke(Object obj, Object... args)
    • 获取方法名:String getName()
    • 忽略访问权限修饰符的安全检查(暴力反射):setAccessible(true)

Field使用:

 1 public class ReflectDemo2 {
 2 
 3     public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
 4 
 5         Class personClass = Person.class;
 6 
 7         //1.getFields:获取所有public修饰的成员变量
 8         System.out.println("1.getFields:获取所有public修饰的成员变量");
 9         Field[] fields = personClass.getFields();
10         for (Field f :fields) { 11  System.out.println(f); 12  } 13 /**输出: 14 * 1.getFields:获取所有public修饰的成员变量 15 * public java.lang.String day08.Person.a 16 */ 17 18 //2.getField:利用成员变量名获取public的成员变量 19 System.out.println("2.getField:利用成员变量名获取public的成员变量"); 20 Field a = personClass.getField("a"); 21 //获取成员变量值 22 Person p = new Person(); 23 Object aValue = a.get(p); 24  System.out.println(aValue); 25 //设置成员变量值 26 a.set(p,"111"); 27  System.out.println(p); 28 /**输出: 29 * 2.getField:利用成员变量名获取public的成员变量 30 * null 31 * Person{name='null', age=0, a='111'} 32 */ 33 34 //3.getDeclaredFields:获取所有的成员变量,不考虑修饰符 35 System.out.println("3.getDeclaredFields:获取所有的成员变量,不考虑修饰符"); 36 Field[] declaredFields = personClass.getDeclaredFields(); 37 for (Field f :declaredFields) { 38  System.out.println(f); 39  } 40 /**输出: 41 * 3.getDeclaredFields:获取所有的成员变量,不考虑修饰符 42 * private java.lang.String day08.Person.name 43 * private int day08.Person.age 44 * public java.lang.String day08.Person.a 45 */ 46 47 //4.getDeclaredField:利用成员变量名获取任意的成员变量 48 System.out.println("4.getDeclaredField:利用成员变量名获取任意的成员变量"); 49 Field name = personClass.getDeclaredField("name"); 50 //忽略访问权限修饰符的安全检查 51 name.setAccessible(true);//暴力反射 52 Object nameValue = name.get(p); 53  System.out.println(nameValue); 54 name.set(p,"王"); 55  System.out.println(p); 56 /**输出: 57 * 4.getDeclaredField:利用成员变量名获取任意的成员变量 58 * null 59 * Person{name='王', age=0, a='111'} 60 */ 61  } 62 }

Constructor使用:

 1 public class ReflectDemo2 {
 2 
 3     public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
 4 
 5         Class personClass = Person.class;
 6 
 7         //1.getConstructor():获取空参数public构造函数
 8         System.out.println("1.getConstructor(Class<?>... parameterTypes):获取空参数public构造函数");
 9         Constructor constructor1 = personClass.getConstructor();
10  System.out.println(constructor1); 11 //创建对象 12 Object person1 = constructor1.newInstance(); 13  System.out.println(person1); 14 15 //简化空参 16 System.out.println("简化空参"); 17 Object o = personClass.newInstance(); 18  System.out.println(o); 19 /**输出: 20 * 1.getConstructor(Class<?>... parameterTypes):获取空参数构造函数 21 * public day08.Person() 22 * Person{name='null', age=0, a='null'} 23 * 简化空参 24 * Person{name='null', age=0, a='null'} 25 */ 26 27 //2.getConstructor(Class<?>... parameterTypes):根据参数获取到类的public构造函数 28 System.out.println("2.getConstructor(Class<?>... parameterTypes):根据参数获取到类的public构造函数"); 29 Constructor constructor2 = personClass.getConstructor(String.class, int.class); 30  System.out.println(constructor2); 31 //创建对象 32 Object person2 = constructor2.newInstance("王",23); 33  System.out.println(person2); 34 /**输出: 35 * 2.getConstructor(Class<?>... parameterTypes):根据参数获取到类的构造函数 36 * public day08.Person(java.lang.String,int) 37 * Person{name='王', age=23, a='null'} 38 */ 39 40 //3.getDeclaredConstructor(Class<?>... parameterTypes):根据参数获取到类的任意构造函数 41 System.out.println("3.getDeclaredConstructor(Class<?>... parameterTypes):根据参数获取到类的任意构造函数"); 42 Constructor constructor3 = personClass.getDeclaredConstructor(String.class); 43 //忽略访问权限修饰符的安全检查 44 constructor3.setAccessible(true);//暴力反射 45  System.out.println(constructor3); 46 //创建对象 47 Object person3 = constructor3.newInstance("张"); 48  System.out.println(person3); 49 /**输出: 50 * 3.getDeclaredConstructor(Class<?>... parameterTypes):根据参数获取到类的任意构造函数 51 * private day08.Person(java.lang.String) 52 * Person{name='张', age=0, a='null'} 53 */ 54  } 55 }

Method使用:

  1 public class ReflectDemo2 {
  2 
  3     public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
  4 
  5         Class personClass = Person.class;
  6 
  7         //1.getMethods:获取自己以及基类所有public方法
  8         System.out.println("1.getMethods:获取自己以及基类所有public方法");
  9         Method[] methods1 = personClass.getMethods();
 10         for (Method m : methods1) { 11  System.out.println(m); 12  System.out.println(m.getName()); 13  } 14 /**输出: 15 * 1.getMethods:获取自己以及基类所有public方法 16 * public java.lang.String day08.Person.toString() 17 * toString 18 * public java.lang.String day08.Person.getName() 19 * getName 20 * public void day08.Person.setName(java.lang.String) 21 * setName 22 * public void day08.Person.publicMethod2(java.lang.String) 23 * publicMethod2 24 * public void day08.Person.publicMethod1() 25 * publicMethod1 26 * public int day08.Person.getAge() 27 * getAge 28 * public void day08.Person.setAge(int) 29 * setAge 30 * public final void java.lang.Object.wait() throws java.lang.InterruptedException 31 * wait 32 * public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException 33 * wait 34 * public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException 35 * wait 36 * public boolean java.lang.Object.equals(java.lang.Object) 37 * equals 38 * public native int java.lang.Object.hashCode() 39 * hashCode 40 * public final native java.lang.Class java.lang.Object.getClass() 41 * getClass 42 * public final native void java.lang.Object.notify() 43 * notify 44 * public final native void java.lang.Object.notifyAll() 45 * notifyAll 46 */ 47 48 //2.getMethod(String name, Class<?>... parameterTypes):根据参数获得public方法 49 System.out.println("2.getMethod(String name, Class<?>... parameterTypes):根据参数获得任意方法"); 50 //无参 51 Method method2_1 = personClass.getMethod("publicMethod1"); 52 Person p2_1 = new Person(); 53 //执行方法 54  method2_1.invoke(p2_1); 55 56 //有参 57 Method method2_2 = personClass.getMethod("publicMethod2", String.class); 58 Person p2_2 = new Person(); 59 //执行方法 60 method2_2.invoke(p2_2, "这是有参的public方法"); 61 /**输出: 62 * 2.getMethod(String name, Class<?>... parameterTypes):根据参数获得public方法 63 * publicMethod1 64 * publicMethod2:参数为这是有参的public方法 65 */ 66 67 //3.getDeclaredMethods:获取自己以及基类所有方法 68 System.out.println("3.getMethods:获取自己以及基类所有方法"); 69 Method[] methods2 = personClass.getDeclaredMethods(); 70 for (Method m : methods2) { 71  System.out.println(m); 72  System.out.println(m.getName()); 73  } 74 /**输出: 75 * 3.getMethods:获取自己以及基类所有方法 76 * public java.lang.String day08.Person.toString() 77 * toString 78 * public java.lang.String day08.Person.getName() 79 * getName 80 * public void day08.Person.setName(java.lang.String) 81 * setName 82 * private void day08.Person.privateMethod1() 83 * privateMethod1 84 * public void day08.Person.setAge(int) 85 * setAge 86 * public void day08.Person.publicMethod1() 87 * publicMethod1 88 * private void day08.Person.privateMethod2(java.lang.String) 89 * privateMethod2 90 * public void day08.Person.publicMethod2(java.lang.String) 91 * publicMethod2 92 * public int day08.Person.getAge() 93 * getAge 94 */ 95 96 //4.getDeclaredMethod(String name, Class<?>... parameterTypes):根据参数获得任意方法 97 System.out.println("4.getDeclaredMethod(String name, Class<?>... parameterTypes):根据参数获得public方法"); 98 //无参 99 Method method4 = personClass.getDeclaredMethod("privateMethod2", String.class); 100 //忽略访问权限修饰符的安全检查 101 method4.setAccessible(true);//暴力反射 102 Person p4 = new Person(); 103 //执行方法 104 method4.invoke(p4, "这是有参的private方法"); 105 /**输出: 106 * 4.getDeclaredMethod(String name, Class<?>... parameterTypes):根据参数获得public方法 107 * privateMethod2:参数为这是有参的private方法 108 */ 109  } 110 }

获取类名:

 1 public class ReflectDemo2 {
 2 
 3     public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
 4 
 5         Class personClass = Person.class;
 6 
 7         //获取类名
 8         String className = personClass.getName();
 9         System.out.println(className);
10         /**输出:
11          * day08.Person
12          */
13  } 14 }

5.案例:读取配置文件生成类执行方法

主程序类:

 1 public class ReflectDemo2 {
 2 
 3     public static void main(String[] args) throws IOException, ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
 4 
 5         //1.加载配置文件
 6         //1.1创建Properties对象
 7         Properties pro = new Properties();
 8 
 9         //1.2加载配置文件,转换为一个集合
10         //1.2.1获取class目录下的配置文件
11         ClassLoader classLoader = ReflectDemo2.class.getClassLoader();
12         InputStream is = classLoader.getResourceAsStream("config.properties");
13  pro.load(is); 14 15 //2.获取配置文件中定义的数据 16 String className = pro.getProperty("className"); 17 String methodName = pro.getProperty("methodName"); 18 19 //3.加载该类进内存 20 Class cls = Class.forName(className); 21 22 //4.创建对象 23 Object obj = cls.newInstance(); 24 25 //5.获取方法对象 26 Method method = cls.getDeclaredMethod(methodName); 27 method.setAccessible(true); 28 29 //执行方法 30 method.invoke(obj,"执行私有方法"); 31  } 32 }

配置文件:config.properties(放在src下)

1 className=main.java.day08.Person
2 methodName=privateMethod2

猜你喜欢

转载自www.cnblogs.com/zhihaospace/p/12227325.html