二.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对象功能
- 获取功能:
- 获取成员变量们:Field类
- Field[] getFields():获取所有public修饰的成员变量
- Field getField(String name):利用成员变量名获取public的成员变量
- Field[] getDeclaredFields():获取所有的成员变量,不考虑修饰符
- Field getDeclaredField(String name):利用成员变量名获取任意的成员变量
- 获取构造函数们:Constructor类
- Constructor<?>[] getConstructors():获取空参数public构造函数
- Constructor<T> getConstructor(类<?>... parameterTypes):根据参数获取到类的public构造函数
- Constructor<?>[] getDeclaredConstructors():获取空参数任意构造函数
- Constructor<T> getDeclaredConstructor(类<?>... parameterTypes):根据参数获取到类的任意构造函数
- 获取成员方法们:Method类
- Method[] getMethods():获取自己以及基类所有public方法
- Method getMethod(String name,类<?>... parameterTypes):根据参数获得public方法
- Method[] getDeclaredMethods():获取自己以及基类所有方法
- Method getDeclaredMethod(String name,类<?>... parameterTypes):根据参数获得任意方法
- 获取类名:
- String getName()
- 获取成员变量们:Field类
- 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