「这是我参与2022首次更文挑战的第21天,活动详情查看:2022首次更文挑战」
1.基础概念
<1>反射机制概念
反射的引入
Object obj = new User();
若程序运行时接收到外部传入的一个对象,该对象的编译类型是Object,但程序又需要调用该对象运行类型的方法:
1.若编译和运行类型都知道,使用 instanceof判断后进行强制类型转化
2.编译时根本无法预知该对象属于什么类,程序只能依靠运行时信息来发现对象的真实信息,需要用到反射
3.需要得到对象真正的类型,需要用到反射
反射机制的定义
Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法;这种动态获取的以及动态调用对象的方法的功能称为Java的反射机制
简单的来说,反射机制指的是程序在运行时能够获取自身的信息。在java中,只要给定类的名字,那么就可以通过反射机制来获得类的所有信息
反射机制的优缺点
从“动态”、“静态”的方向分析反射机制的优缺点
静态编译:在编译时确定类型,绑定对象,即通过
动态编译:在运行时确定类型,绑定对象。动态编译最大限度发挥了java的灵活性,体现了多态的应用,用以降低类之间的藕合性
反射机制的优点就是可以实现动态创建对象和编译,具备灵活性(在J2EE开发中可体现),运行期类型的判断、动态类加载、动态代理使用反射;缺点在于对程序的性能有影响(使用反射基本上是一种解释操作,告知JVM要做的事情,这类操作总是慢于只直接执行相同的操作)
反射机制能够获取的信息
在运行时判定任意一个对象所属的类;
在运行时构造任意一个类的对象;
在运行时判定任意一个类所具有的成员变量和方法;
在运行时调用任意一个对象的方法;
生成动态代理;
主要的反射机制类:
java.lang.Class; //类
java.lang.reflect.Constructor;//构造方法
java.lang.reflect.Field; //类的成员变量
java.lang.reflect.Method;//类的方法
java.lang.reflect.Modifier;//访问权限
<2>Class类和Class类实例
Class相关概念
Java程序中的各个Java类属于同一类事物,描述这类事物的Java类就是Class类
一个类被类加载器加载到内存中,占用一片存储空间,这个空间里面的内容就是类的字节码,不同的类的字节码是不同的,所以它们在内存中的内容是不同的(一个类在虚拟机中只有一份字节码);
反射就是得到元数据的行为
用类来描述对象(类:描述数据的结构);用元数据来描述Class(MetaData(元数据):描述数据结构的结构)
class对象的获取
// 方式1:通过对象getClass方法
Person person = new Person();
Class<?> class1 = person.getClass();
// 方式2:通过类的class属性
class1 = Person.class;
try {
// 方式3:通过Class类的静态方法forName()来实现
class1 = Class.forName("club.sscai.Person");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
获取class对象的属性、方法、构造函数等
// 获取class对象的所有属性
Field[] allFields = class1.getDeclaredFields();
// 获取class对象的public属性
Field[] publicFields = class1.getFields();
try {
// 获取class指定属性
Field ageField = class1.getDeclaredField("age");
// 获取class指定的public属性
Field desField = class1.getField("des");
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
// 获取class对象的所有声明方法
Method[] methods = class1.getDeclaredMethods();
// 获取class对象的所有方法 包括父类的方法
Method[] allMethods = class1.getMethods();
// 获取class对象的父类
Class parentClass = class1.getSuperclass();
// 获取class对象的所有接口
Class<?>[] interfaceClasses = class1.getInterfaces();
// 获取class对象的所有声明构造函数
Constructor<?>[] allConstructors = class1.getDeclaredConstructors();
// 获取class对象public构造函数
Constructor<?>[] publicConstructors = class1.getConstructors();
try {
// 获取指定声明构造函数
Constructor<?> constructor = class1.getDeclaredConstructor(new Class[]{String.class});
// 获取指定声明的public构造函数
Constructor publicConstructor = class1.getConstructor(new Class[]{});
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
// 获取class对象的所有注解
Annotation[] annotations = class1.getAnnotations();
// 获取class对象指定注解
Annotation annotation = class1.getAnnotation(Deprecated.class);
// 获取class对象的直接超类的 Type
Type genericSuperclass = class1.getGenericSuperclass();
// 获取class对象的所有接口的type集合
Type[] interfaceTypes = class1.getGenericInterfaces();
2.功能应用
<1>通过反射机制获取泛型类型
示例
// People类
public class People<T> {}
//Person类继承People类
public class Person<T> extends People<String> implements PersonInterface<Integer> {}
//PersonInterface接口
public interface PersonInterface<T> {}
获取泛型类型
private Class<?> getComponentType(Type type) {
Class<?> componentType = null;
if (type instanceof ParameterizedType) {
// getActualTypeArguments()返回表示此类型实际类型参数的 Type 对象的数组
Type[] actualTypeArguments = ((ParameterizedType) type).getActualTypeArguments();
if (actualTypeArguments != null && actualTypeArguments.length > 0) {
componentType = (Class<?>) actualTypeArguments[0];
}
} else if (type instanceof GenericArrayType) {
// 表示一种元素类型是参数化类型或者类型变量的数组类型
componentType = (Class<?>) ((GenericArrayType) type).getGenericComponentType();
} else {
componentType = (Class<?>) type;
}
return componentType;
}
Person<String> person = new Person<>();
// 方式1:通过对象getClass方法
Class<?> class1 = person.getClass();
Type genericSuperclass = class1.getGenericSuperclass();// 获取class对象的直接超类的 Type
Type[] interfaceTypes = class1.getGenericInterfaces();// 获取class对象的所有接口的Type集合
getComponentType(genericSuperclass);
getComponentType(interfaceTypes[0]);
<2>通过反射机制获取注解信息
通过反射机制获取注解信息再AOP中经常使用
try {
// 首先需要获得与该方法对应的Method对象
Method method = class1.getDeclaredMethod("methodName", new Class[]{String.class, String.class});
// 获取所有的方法注解信息
Annotation[] annotations1 = method.getAnnotations();
// 获取指定的注解信息
Annotation annotation1 = method.getAnnotation(RouterUri.class);
TypeVariable[] typeVariables1 = method.getTypeParameters();
// 拿到所有参数注解信息
Annotation[][] parameterAnnotationsArray = method.getParameterAnnotations();
// 获取所有参数class类型
Class<?>[] parameterTypes = method.getParameterTypes();
// 获取所有参数的type类型
Type[] genericParameterTypes = method.getGenericParameterTypes();
// 获取方法的返回类型
Class<?> returnType = method.getReturnType();
// 获取方法的访问权限
int modifiers = method.getModifiers();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
3.应用实例
比较两个实体对象的信息
分析说明:针对两个对象,Member 和 MemberView,需要进行相应的转化,通常使用的方式是把通过手动get、set操作实现,当对象属性较多的时候,代码或显得臃肿
public class TestClass{
public double eachOrtherToAdd(Integer one,Double two,Integer three){
return one + two + three;
}
}
public class ReflectionDemo{
public static void main(String args[]){
String className = "initLoadDemo.TestClass";
String methodName = "eachOrtherToAdd";
String[] paramTypes = new String[]{"Integer","Double","int"};
String[] paramValues = new String[]{"1","4.3321","5"};
// 动态加载对象并执行方法
initLoadClass(className, methodName, paramTypes, paramValues);
}
@SuppressWarnings("rawtypes")
private static void initLoadClass(String className,String methodName,String[] paramTypes,String[] paramValues){
try{
// 根据calssName得到class对象
Class cls = Class.forName(className);
// 实例化对象
Object obj = cls.newInstance();
// 根据参数类型数组得到参数类型的Class数组
Class[] parameterTypes = constructTypes(paramTypes);
// 得到方法
Method method = cls.getMethod(methodName, parameterTypes);
// 根据参数类型数组和参数值数组得到参数值的obj数组
Object[] parameterValues = constructValues(paramTypes,paramValues);
// 执行这个方法并返回obj值
Object returnValue = method.invoke(obj, parameterValues);
System.out.println("结果:"+returnValue);
}catch (Exception e){
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private static Object[] constructValues(String[] paramTypes,String[] paramValues){
Object[] obj = new Object[paramTypes.length];
for (int i = 0; i < paramTypes.length; i++){
if(paramTypes[i] != null && !paramTypes[i].trim().equals("")){
if ("Integer".equals(paramTypes[i]) || "int".equals(paramTypes[i])){
obj[i] = Integer.parseInt(paramValues[i]);
}else if ("Double".equals(paramTypes[i]) || "double".equals(paramTypes[i])){
obj[i] = Double.parseDouble(paramValues[i]);
}else if ("Float".equals(paramTypes[i]) || "float".equals(paramTypes[i])){
obj[i] = Float.parseFloat(paramValues[i]);
}else{
obj[i] = paramTypes[i];
}
}
}
return obj;
}
@SuppressWarnings("rawtypes")
private static Class[] constructTypes(String[] paramTypes){
Class[] cls = new Class[paramTypes.length];
for (int i = 0; i < paramTypes.length; i++){
if(paramTypes[i] != null && !paramTypes[i].trim().equals("")){
if ("Integer".equals(paramTypes[i]) || "int".equals(paramTypes[i])){
cls[i] = Integer.class;
}else if ("Double".equals(paramTypes[i]) || "double".equals(paramTypes[i])){
cls[i] = Double.class;
}else if ("Float".equals(paramTypes[i]) || "float".equals(paramTypes[i])){
cls[i] = Float.class;
}else{
cls[i] = String.class;
}
}
}
return cls;
}
}