文章目录
java反射机制详细解析
基本概念
通常情况下编写代码都是固定的,无论运行多少次执行的结果也是固定的,在某些特殊场合中编写代码时不确定要创建什么类型的对象,也不确定要调用什么样的方法,这些都希望通过运行时传递的参数来决定,该机制叫做动态编程技术,也就是反射机制。
通俗来说,反射机制就是用于动态创建对象并且动态调用方法的机制。
目前主流的框架底层都是采用反射机制实现的。
如:
Person p = new Person(); - 表示声明Person类型的引用指向Person类型的对象
p.show(); - 表示调用Person类中的成员方法show
Class类
基本概念
java.lang.Class类的实例可以用于描述Java应用程序中的类和接口,也就是一种数据类型。
该类没有公共构造方法,该类的实例由Java虚拟机和类加载器自动构造完成,本质上就是加载到内存中的运行时类。
获取Class对象的方式
-
使用数据类型.class的方式可以获取对应类型的Class对象(掌握)。
// 1.使用数据类型.class的方式可以获取对应的Class对象 // 1.1 获取字符串类型来获取Class对象并打印 Class aClass = String.class; System.out.println(aClass); // 自动调用 toString 方法 打印结果是 class 或者 interface 完全限定名(包名.类名) // 1.2 获取基本数据类型的class对象并打印 aClass = int.class; System.out.println(aClass); // int // 1.3 获取 void 类型的class对象并打印结果 aClass = void.class; System.out.println(aClass); // void
-
使用引用/对象.getClass()的方式可以获取对应类型的Class对象。
// 2.使用 对象.getClass() 方法来获取Class队形 // 2.1 使用 对象.getClass() 方法获取字符串类型的Class对象并打印 String str = new String(); aClass = str.getClass(); System.out.println(aClass); // class java.lang.Integer // 2.2 使用 对象.getClass() 获取保障类的Class对象并打印 Integer integer = Integer.valueOf(5); aClass = integer.getClass(); System.out.println(aClass); // class java.lang.Integer // 2.3使用基本数据类型调用该方法并打印 int num = 10; // num.getClass(); 编译报错 没有该方法 所以基本数据类型不能调用该方法
-
使用包装类.TYPE的方式可以获取对应基本数据类型的Class对象。
// 3.使用包装类中的type()方法获取Class对象 // 3.1获取Integer类型的Class对象 aClass = Integer.TYPE; System.out.println(aClass); // int // 3.2获取Character类型的Class对象 aClass = Character.TYPE; System.out.println(aClass); // char // 3.3获取Boolean类型的Class对象 aClass = Boolean.TYPE; System.out.println(aClass); // boolean
-
使用Class.forName()的方式来获取参数指定类型的Class对象(掌握)。
// 4.使用Class类的中方法forName的方式来获取参数指定类型的Class对象 // 4.1 获取String类型的Class对象并打印 // aClass = Class.forName("String"); ClassNotFoundException aClass = Class.forName("java.lang.String"); System.out.println(aClass); // class java.lang.String // 4.2传入基本数据类型 获取Class对象 // aClass = Class.forName("int"); // ClassNotFoundException 因为基本数据类型不是对象
-
使用类加载器ClassLoader的方式获取指定类型的Class对象。
// 5.使用类加载器ClassLoader获取Class类型的对象 ClassLoader classLoader = ClassTest.class.getClassLoader(); aClass = classLoader.loadClass("java.lang.String"); System.out.println(aClass); // class java.lang.String
-
注意事项
- 包装类使用type方法获取的是对应的基本数据类型 而 使用 包装类的对象.getClass() 方法获取的对应包装类的对象
- 通过 .class类获取的对象 调用toString的方法时 打印结果有三种
- 如果对象是引用数据类型 返回值是 class 完全限定名称
- 如果对象是基本数据类型 返回值是 基本数据类型
- 如果对象为 void 则返回值为 void
- 基本数据类型不能通过getClass的方法获取Class对象 因为基本数据类型不是对象
- 通过Class.forname() 方式获取Class对象 要求参数是完全限定名 否则会报ClassNotFountException 类找不到异常
- 通过Class.forName() 方式获取Class对象 不能获取基本数据类型的Class对象
常用的方法(掌握)
方法声明 | 功能介绍 |
---|---|
static Class<?> forName(String className) | 用于获取参数指定类型对应的Class对象并返回 |
T newInstance() | 用于创建该Class对象所表示类的新实例(已过时 使用Constructor 中的 newInstance()方法) |
方法演示
-
动态创建指定类型的对象
// 1.使用原始方式以无参的形式构造 Person 类型的对象 并打印 Person person = new Person(); System.out.println(person); // null 0 // 2.使用反射机制以无参形式构造 person 类型的对象 并打印 // 2.1 指定类型的动态创建对象 Class c1 = Class.forName("cn.junnsunny.modal4.day05.Person"); System.out.println(c1.newInstance()); // null 0
-
从键盘输入创建类型的对象
// 2.2 创建用户从键盘输入的对象 Scanner sc = new Scanner(System.in); String str = sc.next(); // cn.junnsunny.modal4.day05.Person // Class c1 = Class.forName("cn.junnsunny.modal4.day05.Person"); Class c1 = Class.forName(str); System.out.println(c1.newInstance()); // Person{name='null', age=0} sc.close();
-
读取配置文件动态创建配置文件的对象
// 2.3 创建从配置文件a.txt中的对象 // 文件中存放的字符是 cn.junnsunny.modal4.day05.Person // 2.3.1创建BufferedReader 类型的输入流对象 并与 z:/a.txt 关联 BufferedReader reader = new BufferedReader(new FileReader("z:/a.txt")); // 2.3.2读取配置文件a.txt中一行数据 String str = reader.readLine(); // 2.3.3使用Class.forName() 创建该全限定名的Class对象 Class c1 = Class.forName(str); // 2.3.4使用newInstance() 创建该class类型的实例化对象并打印 // newInstance方法中的实参适用于给有参构造方法的形参进行初始化的 也就是给name和age进行初始化的 System.out.println(c1.newInstance()); // Person{name='null', age=0} }
Constructor类(构造方法)
基本概念
java.lang.reflect.Constructor类主要用于描述获取到的构造方法信息
Class类的常用方法
方法声明 | 功能介绍 |
---|---|
Constructor getConstructor(Class… parameterTypes) | 用于获取此Class对象所表示类型中参数指定的 公共构造方法 |
Constructor[] getConstructors() | 用于获取此Class对象所表示类型中所有的公共 构造方法 |
Constructor类的常用方法
方法声明 | 功能介绍 |
---|---|
T newInstance(Object…initargs) | 使用此Constructor对象描述的构造方法来构造Class对象代表类型的新实例 |
int getModifiers() | 获取方法的访问修饰符 |
String getName() | 获取方法的名称 |
Class<?>[]getParameterTypes() | 获取方法所有参数的类型 |
Constructor类的常用方法的使用
-
使用 Constructor 创建无参构造Person类
// 1.读取配置文件 获取创建Person类型的全限定类名 文件在 z:/a.txt BufferedReader reader = new BufferedReader(new FileReader("z:/a.txt")); // 2.读取配置文件中的内容并返回 String s = reader.readLine(); // 3.通过获取的全限定类名使用Class.forName的方法获取Class对象 Class c = Class.forName(s); // 4.通过Class类型的对象使用getConstructor获取对应的无参Person类型的无参构造 Constructor constructor = c.getConstructor(); // 5.通过Constructor的对象创建Person的无参构造 并打印 System.out.println(constructor.newInstance()); // Person{name='null', age=0}
-
使用 Constructor 创建有参构造Person类
// 2.使用原始的方式以有参的方式构造Person类型的对象并打印 Person person1 = new Person("张三", 20); System.out.println(person1); // Person{name='张三', age=20} // 3.使用反射机制以有参的方式获取Person类型的对象 // 3.1读取配置文件 获取创建Person类型的全限定类名 文件在 z:/a.txt BufferedReader reader = new BufferedReader(new FileReader("z:/a.txt")); // 3.2读取配置文件中的内容并返回 String s = reader.readLine(); // 3.3通过获取的全限定类名使用Class.forName的方法获取Class对象 Class c = Class.forName(s); // 3.4通过Class类型的对象使用getConstructor获取对应的无参Person类型的无参构造 // 相当于获取Class对象对应类中的有参构造方法 也就是Person类中的有参构造 Constructor constructor = c.getConstructor(String.class, int.class); // 3.5通过Constructor的对象创建Person的有参构造 并打印 System.out.println(constructor.newInstance("张三",20)); // Person{name='张三', age=20}
-
使用 Constructor 获取Person类所有的构造方法并打印
// 4.使用反射机制获取Person类中所有的公共构造方法并打印 // 4.1读取配置文件 获取创建Person类型的全限定类名 文件在 z:/a.txt BufferedReader reader = new BufferedReader(new FileReader("z:/a.txt")); // 4.2读取配置文件中的内容并返回 String s = reader.readLine(); // 4.3通过获取的全限定类名使用Class.forName的方法获取Class对象 Class c = Class.forName(s); // 4.4通过Class类型的对象使用getConstructor获取对应的无参Person类型的全部的构造方法 Constructor[] constructors = c.getConstructors(); // 4.5遍历数组集合 使用f增强for的方式 for (Constructor ct: constructors){ // 4.6 打印权限修饰符 System.out.println("构造方法的权限修饰符是: " + ct.getModifiers()); // 1 java中的常量值 代表public修饰 // 4.7 打印方法名 // 打印结果是 cn.junnsunny.modal4.day05.Person 全限定类名 System.out.println("构造方法的方法名称是: " + ct.getName()); // 4.8 打印参数列表 // 打印结果是 无参构造为 空 有参构造是 class java.lang.String int System.out.print("构造方法的所有参数类型是: "); Class[] parameterTypes = ct.getParameterTypes(); for (Class sc : parameterTypes){ System.out.print(sc + " "); } System.out.println(); }
Field类(成员变量)
基本概念
java.lang.reflect.Field类主要用于描述获取到的单个成员变量信息。
Class类的常用方法
方法声明 | 功能介绍 |
---|---|
Field getDeclaredField(String name) | 用于获取此Class对象所表示类中参数指定的单个成员变量信息 |
Field[] getDeclaredFields() | 用于获取此Class对象所表示类中所有成员变量信息 |
Field类的常用方法
方法声明 | 功能介绍 |
---|---|
Object get(Object obj) | 获取参数对象obj中此Field对象所表示成员变量的数值 |
void set(Object obj, Object value) | 将参数对象obj中此Field对象表示成员变量的数值修改为参数 value的数值 |
void setAccessible(boolean flag) | 当实参传递true时,则反射对象在使用时应该取消 Java 语言访 问检查 |
int getModifiers() | 获取成员变量的访问修饰符 |
Class<?> getType() | 获取成员变量的数据类型 |
String getName() | 获取成员变量的名称 |
Field类的常用方法的使用
-
使用反射机制并获取成员变量的返回值信息并打印
public static void main(String[] args) throws Exception { // 1.使用原始的方式构造对象以及获取成员变量的数值并打印 Person person = new Person("张三", 20); System.out.println(person.name); // 张三 // 2.使用反射机制构造方法并获取成员变量的返回值信息 // 2.1 获取对应的Class对象 Class c = Class.forName("cn.junnsunny.modal4.day05.Person"); // 2.2通过Class对象来获取有参构造方法 Constructor constructor = c.getConstructor(String.class, int.class); // 2.3使用有参构造方法来创建对应的实例 Object obj = constructor.newInstance("张三", 20); // 2.4使用class对象获取成员变量信息 // 获取成员的字段信息只能用public修饰 否则会报 IllegalAccessException 非法访问异常 // 解决方法: 设置取消语言访问检查 暴力反射 field.setAccessible(true); Field field = c.getDeclaredField("name"); // 2.5打印Person类中的对象获取到的成员信息 System.out.println(field.get(obj)); // 张三 }
-
使用反射机制修改成员变量的值信息并打印修改之后的数据
// 2.使用原始的方式修改指定成员变量的数值并再次打印 Person person = new Person("张三", 20); person.name = "李四"; System.out.println(person.name); // 李四 // 3.使用反射机制修改指定的成员变量信息并打印修改后的信息 // 3.1获取对应的Class的对象 Class c = Class.forName("cn.junnsunny.modal4.day05.Person"); // 3.2通过Class对象获取对应的有参构造方法 Constructor constructor = c.getConstructor(String.class, int.class); // 3.3通过构造方法创建对应的对象 Object obj = constructor.newInstance("张三", 20); // 3.4通过Class获取对应的对应的成员变量 Field field = c.getDeclaredField("name"); // 获取成员的字段信息只能用public修饰 否则会报 IllegalAccessException 非法访问异常 // 解决方法: 设置取消语言访问检查 field.setAccessible(true); // 3.5通过对象修改成员变量的信息 field.set(obj,"李四"); // 3.6打印对象中成员变量修改的数值 System.out.println(field.get(obj)); // 李四
-
使用反射机制所有的获取成员信息并打印
// 3.使用反射机制所有的获取成员信息并打印 // 3.1获取对应的Class的对象 Class c = Class.forName("cn.junnsunny.modal4.day05.Person"); // 3.2通过Class对象获取对应的有参构造方法 Constructor constructor = c.getConstructor(String.class, int.class); // 3.3通过构造方法创建对应的对象 Object obj = constructor.newInstance("张三", 20); // 3.4通过Class对应获取所有的成员信息 Field[] declaredFields = c.getDeclaredFields(); // 3.5变量数组并打印数组中的信息 for (Field declaredField : declaredFields) { System.out.println("成员变量的权限修饰是:" + declaredField.getModifiers()); // 2 2 System.out.println("成员变量的数据类型是:" + declaredField.getType()); // class java.lang.String int System.out.println("成员变量的名称是:" + declaredField.getName()); // name age }
Method类(成员方法)
基本概念
java.lang.reflect.Method类主要用于描述获取到的单个成员方法信息。
Class类的常用方法
方法声明 | 功能介绍 |
---|---|
Method getMethod(String name, Class<?>… parameterTypes) | 用于获取该Class对象表示类中名字为name参数为parameterTypes的指定公共成员方法 |
Method[] getMethods() | 用于获取该Class对象表示类中所有公共成员方法 |
Method类的常用方法
方法声明 | 功能介绍 |
---|---|
Object invoke(Object obj, Object… args) | 使用对象obj来调用此Method对象所表示的成员方法,实 参传递args |
int getModifiers() | 获取方法的访问修饰符 |
Class<?> getReturnType() | 获取方法的返回值类型 |
String getName() | 获取方法的名称 |
Class<?>[] getParameterTypes() | 获取方法所有参数的类型 |
Class<?>[] getExceptionTypes() | 获取方法的异常信息 |
Method类的常用方法的使用
-
使用反射机制构造对象 调用成员方法并打印结果
// 1.使用原始方式构造对象并打印结果 Person person = new Person("张三", 20); System.out.println("调用方法的返回值是: " + person.getName()); // 张三 // 2.使用反射机制构造对象并打印结果 // 2.1获取对应的Class对象 Class c = Class.forName("cn.junnsunny.modal4.day05.Person"); // 2.2通过Class对象获取有参的构造方法 Constructor constructor = c.getConstructor(String.class, int.class); // 2.3通过有参的方式实例化对象 Object obj = constructor.newInstance("张三", 20); // 2.4通过Class对象获取对象的方法 // 2.4.1获取设置姓名的方法(有参方法) Method setName = c.getMethod("setName",String.class); // 2.4.2获取修改姓名的方法(无参方法) Method getName = c.getMethod("getName"); // 2.5通过Method对象调用该方法并打印返回值 System.out.println("调用方法的返回值是: " + getName.invoke(obj)); // 张三 setName.invoke(obj,"李四"); System.out.println("调用方法的返回值是: " + getName.invoke(obj)); // 李四
-
使用反射机制获取Class对象中的所有公共方法并打印
// 2.使用反射机制获取Class对象中的所有公共方法并打印 // 2.1获取对应的Class对象 Class c = Class.forName("cn.junnsunny.modal4.day05.Person"); // 2.2通过Class对象获取有参的构造方法 Constructor constructor = c.getConstructor(String.class, int.class); // 2.3通过有参的方式实例化对象 Object obj = constructor.newInstance("张三", 20); // 2.4通过Class对象获取对象的所有方法 Method[] methods = c.getMethods(); // 2.5变量Method集合并打印 方法的返回值类型 方法名 权限修饰符 形式参数 for (Method method : methods) { System.out.println("成员方法的权限修饰符是: " + method.getModifiers()); System.out.println("成员方法的方法名称是: " + method.getName()); System.out.println("成员方法的返回值类型是: " + method.getReturnType()); System.out.print("成员方法的形式参数是: "); Class<?>[] parameterTypes = method.getParameterTypes(); for (Class<?> parameterType : parameterTypes) { System.out.print(parameterType + ", "); } System.out.println(); System.out.println("获取的异常信息是: "); Class<?>[] exceptionTypes = method.getExceptionTypes(); for (Class<?> exceptionType : exceptionTypes) { System.out.print(exceptionType+ ", "); } System.out.println(); }
获取其它结构信息(class类)
方法声明 | 功能介绍 |
---|---|
Package getPackage() | 获取所在的包信息 |
Class<? super T> getSuperclass() | 获取继承的父类信息 |
Class<?>[] getInterfaces() | 获取实现的所有接口 |
Annotation[] getAnnotations() | 获取注解信息 |
Type[] getGenericInterfaces() | 获取泛型信息 |