反射是Java中的一种机制,我的编写好的Java文件是不能直接运行,需要编译成class文件,jvm将Class文件加载进内存,并读取Class文件中的内容(该内容就是我们类中写的东西)封装成一个Class对象,并且类的各个组成部分也都被封装成一个个对象。成员变量会被封装成Field对象,构造方法会被封装成Constructor对象,成员方法会被封装成Method对象,这些对象都统一保存在Class对象身上。Java中的反射机制就是要求我们通过Class对象操作Field、Constructor、Method对象完成数据的封装。
1.2 使用场景反射是框架设计的核心部分。
2、获取Class对象的三种方法及其作用 2.1 三种方式1 通过类名获取Class对象
Class clazz=类名.class;
2 通过对象获取Class对象
Class clazz=对象.getClass();
3 通过Class类型的forName()静态方法获取
Class clazz=Class.forName("全类名"); //报名.类名
2.2 代码演示
public class ReflectClass {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
//1 通过类名获取Class对象
Class userClass = User.class;
System.out.println(userClass);
//2 通过对象获取Class对象
User user=new User();
Class userClass2 = user.getClass();
System.out.println(userClass2);
//3 通过Class类型的forName()静态方法获取
Class userClass3 = Class.forName("com.domain.User");
System.out.println(userClass3);
//userClass、userClass2、userClass3是否是同一个对象? 是的
System.out.println(userClass==userClass2);
System.out.println(userClass==userClass3);
//Class对象的作用?
//1 可以获取成员变量对象(Field)、获取成员方法对象(Method)、获取构造方法对象(Constructor)
//2 可以实例化一个User对象,默认执行的是空参构造
User u = userClass.newInstance();
System.out.println("u = " + u);
//3 获取类上的注解参数值
Resource resource = userClass.getAnnotation(Resource.class);
String name = resource.name();
System.out.println("name = " + name);
}
}
3、获取Constructor对象及其作用
3.1 API
1.获取构造方法对象
Constructor[] getConstructors() 获取所有public修饰的构造方法
Constructor getConstructor(Class... parameterTypes) 获取指定参数类型的public修饰的构造方法
Constructor getDeclaredConstructor(Class... parameterTypes) 获取指定参数类型的任意修饰符类型的构造方法
Constructor[] getDeclaredConstructors() 获取任意修饰符类型所有的构造方法
方法规律:
1 方法带Declared表示获取任意修饰符修饰的对象,否则只能获取public修饰的对象
2 方法带s表示获取多个对象,不带s表示获取指定名称的对象
2.实例化对象
Object obj=constructor.newInstance(Object...param);创建对象,并且传递构造需要的参数
3.2 代码演示
package com.itheima_1;
import com.domain.User;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
/*
1.获取构造方法对象
Constructor[] getConstructors() 获取所有public修饰的构造方法
Constructor getConstructor(Class... parameterTypes) 获取指定参数类型的public修饰的构造方法
Constructor getDeclaredConstructor(Class... parameterTypes) 获取指定参数类型的任意修饰符类型的构造方法
Constructor[] getDeclaredConstructors() 获取任意修饰符类型所有的构造方法
方法规律:
1 方法带Declared表示获取任意修饰符修饰的对象,否则只能获取public修饰的对象
2 方法带s表示获取多个对象,不带s表示获取指定名称的对象
*/
public class ReflectConstructor {
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//1 获取Class对象
Class userClass = User.class;
//2 获取Constructor对象
//Constructor[] getConstructors() 获取所有public修饰的构造方法
// Constructor[] constructors = userClass.getConstructors();
//Constructor[] getDeclaredConstructors() 获取任意修饰符类型所有的构造方法
/*Constructor[] constructors = userClass.getDeclaredConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
*/
//Constructor getConstructor(Class... parameterTypes) 获取指定参数类型的public修饰的构造方法
// Constructor constructor = userClass.getConstructor();
//Constructor getDeclaredConstructor(Class... parameterTypes) 获取指定参数类型的任意修饰符类型的构造方法
Constructor constructor = userClass.getDeclaredConstructor();
System.out.println(constructor);
//3 Constructor的相关操作
//主要就是实例化对象
// User user = constructor.newInstance();
//取消访问权限,又叫暴力访问
constructor.setAccessible(true);
User user = constructor.newInstance("java89期 杨焕"); //User user=new User("java89期 杨焕");
System.out.println(user);
}
}
注意:如果构造是非public修饰的,那么在实例化对象之前调用setAccessible(true);取消访问权限(暴力访问)。
4、获取Field对象及其作用 4.1 API1.获取成员变量对象
Field[] getFields() :获取所有public修饰的成员变量
Field getField(String name) 获取一个指定名称的public修饰的成员变量
Field[] getDeclaredFields() 获取所有的任意修饰符类型成员变量
Field getDeclaredField(String name) 获取任意修饰符类型指定名称的成员变量
方法规律:
1 方法带Declared表示获取任意修饰符修饰的对象,否则只能获取public修饰的对象
2 方法带s表示获取多个对象,不带s表示获取指定名称的对象
2.赋值和取值
field.get(Object obj);获取哪个对象的field成员变量值;
field.set(Object obj, Object value);设置obj对象的field成员变量值为value
4.2 代码演示
public class ReflectField {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, InstantiationException {
//1 获取Class对象
Class userClass = User.class;
//2 获取Field成员变量对象
//Field[] getFields() :获取所有public修饰的成员变量
//Field[] fields = userClass.getFields();
//Field[] getDeclaredFields() 获取所有的任意修饰符类型成员变量
/*Field[] fields = userClass.getDeclaredFields();
for (Field field : fields) {
System.out.println(field);
}*/
//Field getField(String name) 获取一个指定名称的public修饰的成员变量
// Field field = userClass.getField("name");
//Field getDeclaredField(String name) 获取任意修饰符类型指定名称的成员变量
Field field = userClass.getDeclaredField("age");
System.out.println(field);
//3 操作Field对象
//取消访问权限
field.setAccessible(true);
//赋值,field.set(Object obj, Object value);设置obj对象的field成员变量值为value
User user = userClass.newInstance();
field.set(user,20);
System.out.println(user);
//取值,field.get(Object obj);获取哪个对象的field成员变量值;
Object age = field.get(user);
System.out.println("age = " + age);
//其他操作
//获取变量名称
System.out.println(field.getName());
//获取变量类型
System.out.println(field.getGenericType().getTypeName());
//获取修饰符类型
int modifier = field.getModifiers();
System.out.println(Modifier.toString(modifier));
//System.out.println(Modifier.isPrivate(modifier));
}
}
注意:如果构造是非public修饰的,那么在调用set()/get()方法之前调用setAccessible(true)取消访问权限(暴力访问)。
5、获取Method对象及其作用 5.1 API1.获取成员方法对象
Method[] getMethods() 获取所有public修饰的方法(可以获取父类的public修饰的方法)
Method getMethod(String name, Class... parameterTypes) 获取一个指定名称指定参数类型的public修饰成员方法
Method[] getDeclaredMethods() 获取任意修饰符类型所有的成员方法
Method getDeclaredMethod(String Class, 类... parameterTypes) 获取一个指定名称指定参数类型的任意修饰符类型成员方法
方法规律:
1 方法带Declared表示获取任意修饰符修饰的对象,否则只能获取public修饰的对象
2 方法带s表示获取多个对象,不带s表示获取指定名称的对象
2.执行方法
method.invoke(Object obj, Object... args);执行obj对象身上的method方法并给方法传递的参数值为args。
5.2 代码演示
public class ReflectMethod {
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
//1 获取Class对象
Class userClass = User.class;
//2 获取Method对象
//Method[] getMethods() 获取所有public修饰的方法(可以获取父类的public修饰的方法)
//Method[] methods = userClass.getMethods();
//Method[] getDeclaredMethods() 获取任意修饰符类型所有的成员方法
/*Method[] methods = userClass.getDeclaredMethods();
for (Method method : methods) {
System.out.println(method);
}*/
//Method getMethod(String name, Class... parameterTypes) 获取一个指定名称指定参数类型的public修饰成员方法
//Method method = userClass.getMethod("setName", String.class);
//Method getDeclaredMethod(String Class, 类... parameterTypes) 获取一个指定名称指定参数类型的任意修饰符类型成员方法
//Method method = userClass.getDeclaredMethod("show1");
Method method = userClass.getDeclaredMethod("show1", String.class);
System.out.println(method);
//3 操作Method对象
//主要是执行方法
//method.invoke(Object obj, Object... args);执行obj对象身上的method方法并给方法传递的参数值为args。
//暴力访问
method.setAccessible(true);
User user = userClass.newInstance();
Object value = method.invoke(user, "吴文波");
System.out.println("value = " + value);
//其他使用
//获取方法名
System.out.println(method.getName());
//获取返回值类型
System.out.println(method.getReturnType().getSimpleName());
//返回修饰符类型
System.out.println(Modifier.toString(method.getModifiers()));
System.out.println(Modifier.isStatic(method.getModifiers()));
//获取参数类型
Class[] parameterTypes = method.getParameterTypes();
for (Class parameterType : parameterTypes) {
System.out.println(parameterType.getSimpleName());
}
//获取方法上的注解
Resource resource = method.getAnnotation(Resource.class);
System.out.println(resource.name());
}
注意:如果构造是非public修饰的,那么在调用invoke()方法之前调用setAccessible(true)取消访问权限(暴力访问)。
6、反射总结核心:掌握反射操作的基本思路
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RUJ4iWNd-1587303757539)(img/反射知识点结构图.png)]
7、反射案例 7.1 需求 设计一个BeanUtils工具类,该工具类的作用是将Map集合中的数据封装到对应的JavaBean中。
7.2 代码实现public class BeanUtils {
/**
* 将Map集合中的数据封装到对应的bean对象中。
* @param bean 要封装数据的bean对象
* @param map 存储数据的map集合
* 方式1:通过反射Field对象的方式封装
*/
/*public static void populate(Object bean, Map map) throws IllegalAccessException {
//1 获取Class对象
Class aClass = bean.getClass();
//2 获取所有field对象
Field[] fields = aClass.getDeclaredFields();
//3 遍历所有的Field对象
for (Field field : fields) {
//4 遍历map集合,获取所有的key和value
Set<Map.Entry> entries = map.entrySet();
for (Map.Entry entry : entries) {
String key = entry.getKey();
Object value = entry.getValue();
//5 判断key是否和field名称一致,如果一致就封装数据
if(key.equals(field.getName())){
//取消访问权限
field.setAccessible(true);
field.set(bean,value);
}
}
}
}*/
/**
* 将Map集合中的数据封装到对应的bean对象中。
* @param bean 要封装数据的bean对象
* @param map 存储数据的map集合
* 方式2:通过反射setXxx方法的方式封装
*/
/*public static void populate(Object bean, Map map) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
//1 获取Class对象
Class aClass = bean.getClass();
//2 获取所有Method对象
Method[] methods = aClass.getDeclaredMethods();
//3 遍历所有的Method对象
for (Method method : methods) {
//4 遍历map集合,获取所有的key和value
Set<Map.Entry> entries = map.entrySet();
for (Map.Entry entry : entries) {
String key = entry.getKey();//name,age,man,birthday
Object value = entry.getValue();
//5 判断"set"+key是否和Method名称一致,如果一致就封装数据
if(method.getName().equalsIgnoreCase("set"+key)){
//执行方法
method.invoke(bean,value);
}
}
}
}*/
/**
* 将Map集合中的数据封装到对应的bean对象中。
* @param bean 要封装数据的bean对象
* @param map 存储数据的map集合
* 方式3:通过java内省机制的方式封装
*/
public static void populate(Object bean, Map map) throws IllegalAccessException, InvocationTargetException, IntrospectionException {
//1 获取Class对象
Class aClass = bean.getClass();
//2 遍历map集合,获取所有的key和value
Set<Map.Entry> entries = map.entrySet();
for (Map.Entry entry : entries) {
String key = entry.getKey(); //name,age,man,birthday
Object value = entry.getValue();
//3 根据key创建属性描述器对象,获取setXxx属性方法
PropertyDescriptor pd=new PropertyDescriptor(key,aClass);
//获取setXxx属性方法
Method method = pd.getWriteMethod();
//4 执行该方法
method.invoke(bean,value);
}
}
}
8、Java的内省机制
Java的内省机制:Java中提供了一种机制,专门用来获取javabean的属性信息。由三类类操作javabean的属性。
public class IntrospectDemo {
public static void main(String[] args) throws IntrospectionException {
//获取javabean信息
BeanInfo beanInfo = Introspector.getBeanInfo(User.class);
//获取所有的属性方法:setXxx()或者getXxx()
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
//获取setXxx()
System.out.println(propertyDescriptor.getWriteMethod());
//获取getXxx()
System.out.println(propertyDescriptor.getReadMethod());
}
//获取指定名称的setXxx()和getXxx()方法
PropertyDescriptor propertyDescriptor=new PropertyDescriptor("name",User.class);
System.out.println(propertyDescriptor.getWriteMethod());
System.out.println(propertyDescriptor.getReadMethod());
}
}