版权声明:转载原创博客请附上原文链接 https://blog.csdn.net/weixin_43495590/article/details/89146671
一:反射的意义
Refliction反射重大意义在于运行时期
的数据信息获取、修改,例如Spring的AOP等经典应用
二:反射入口 – Class
2.1 class对象
// Object提供的本地方法,只适用于引用类型
Class<? extends Singleton> singletonClass1 = new Singleton().getClass();
// Class提供的静态方法,
Class<?> singletonClass2 = Class.forName("com.zsl.Singleton");
// 隐藏属性class
Class<Singleton> singletonClass3 = Singleton.class;
// 封装类常量TYPE
Class<Integer> type = Integer.TYPE;
- Object提供的getClass()以及Class提供的forName()都仅仅针对
引用类型
,基本类型只适用于class隐藏属性
- Class提供的forName()实现如下所示,参数需要
绝对路径
,处理抛出异常ClassNotFoundException
- 八种基本类型的封装类都有一个
TYPE常量
储存Class对象
// 参数需要为绝对路径
// 上层调用需要处理异常
// 利用类加载器组装对象
@CallerSensitive
public static Class<?> forName(String className)
throws ClassNotFoundException {
Class<?> caller = Reflection.getCallerClass();
return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}
2.2 关联类
// 调用类父类
Class<? extends Singleton> singletonClass = new Singleton().getClass();
Class<?> superclass = singletonClass.getSuperclass();
System.out.println(superclass);
// 调用类父类、接口,包括继承
Class<?>[] classes = singletonClass.getClasses();
// 调用类显示声明父类、接口
Class<?>[] declaredClasses = singletonClass.getDeclaredClasses();
// 属性、方法、构造器所在类(采用同一方法)
Field flag = singletonClass.getDeclaredField("flag");
Class<?> declaringClass = flag.getDeclaringClass();
System.out.println(declaringClass);
2.3 :属性、方法、构造
属性、方法、构造函数获取操作按照两个维度划分,继承
、指定
- 继承维度上若需要获取父类信息则限定在
pubic修饰
范围内
// 本类中与继承自父类的属性、方法、构造函数,被public修饰
Field[] fields = fatherClassClass.getFields();
......
// 本类中所有属性、方法、构造函数
Field[] declaredFields = fatherClassClass.getDeclaredFields();
......
- 指定获取某属性
参数为属性名字
,获取方法参数为方法名字与形参类Class对象
,获取构造函数参数为形参类Class对象
// 指定属性
Field name = fatherClassClass.getDeclaredField("name");
// 指定方法
Method test = fatherClassClass.getDeclaredMethod("test", String.class);
// 指定构造函数
Constructor<FatherClass> declaredConstructor = fatherClassClass.getDeclaredConstructor(String.class);
三:访问控制 – AccessibleObject
Field、Method、Constructor反射中分别定义属性、方法、构造函数的类都直接亦或是间接继承该抽象类,反射具备运行过程修改属性值、执行方法的能力,这时需要解决访问权限问题
需要借助AccessibleObject类。类中方法setAccessible()
通过修改访问状态标志flag控制属性、方法、构造函数是否可以被访问
public void setAccessible(boolean flag) throws SecurityException {
SecurityManager sm = System.getSecurityManager();
if (sm != null) sm.checkPermission(ACCESS_PERMISSION);
setAccessible0(this, flag);
}
四:修饰解码 – Modifier
Class类中本地方法getModifiers()
获取类修饰符。Field、Method、Constructor中维护属性modifiers
保存修饰符编码,getModifiers()方法返回该属性值
// 修饰符描述编码
int modifiers = FatherClass.class.getModifiers();
// 调用Modifer类toString()解码修饰符
System.out.println(Modifier.toString(modifiers));
查看Modifer方法toString()源码可以清晰的看到解码过程就是进行不断对比
public static String toString(int mod) {
StringBuilder sb = new StringBuilder();
int len;
if ((mod & PUBLIC) != 0) sb.append("public ");
if ((mod & PROTECTED) != 0) sb.append("protected ");
if ((mod & PRIVATE) != 0) sb.append("private ");
if ((mod & ABSTRACT) != 0) sb.append("abstract ");
if ((mod & STATIC) != 0) sb.append("static ");
if ((mod & FINAL) != 0) sb.append("final ");
if ((mod & TRANSIENT) != 0) sb.append("transient ");
if ((mod & VOLATILE) != 0) sb.append("volatile ");
if ((mod & SYNCHRONIZED) != 0) sb.append("synchronized ");
if ((mod & NATIVE) != 0) sb.append("native ");
if ((mod & STRICT) != 0) sb.append("strictfp ");
if ((mod & INTERFACE) != 0) sb.append("interface ");
if ((len = sb.length()) > 0)
return sb.toString().substring(0, len-1);
return "";
}
五:成员属性 – Field
Class<?> classz = Class.forName("com.zsl.FatherClass");
FatherClass fatherClass = (FatherClass) classz.newInstance();
Field name = classz.getDeclaredField("name");
// 属性设置值,如果是包装类可选择对应方法
name.set(fatherClass,"father");
// 获取属性值,包装类也有对应专用方法
String s = (String)name.get(fatherClass);
// 获取属性类型
System.out.println(name.getType());
Field类继承AccessibleObject
抽象类,实现Member
接口。里面主要实现属性值设置
、属性值获取
、属性类型获取
等操作
六:成员方法 – Method
private String name;
private Class<?> returnType;
private Class<?>[] parameterTypes;
private Class<?>[] exceptionTypes;
test.invoke(fatherClass,"111");
根据Method类属性可看出该类主要提供有关方法名字
、返回值类型
、异常
、参数类型
、参数数量
等操作。方法执行invoke()指定对象与实参
七:实例构造 – Constructor
private Class<?>[] parameterTypes;
private Class<?>[] exceptionTypes;
Object o = classz.getDeclaredConstructor(String.class).newInstance("12");
Constructor类中针对构造器参数
、异常
两方面做实现,方法newInstance()
配合构造器实例进行对象的初始化
八:可变参处理
可变参底层实现采用数组实现,例如方法中存在可变参,反射操作获取方法需要形参Class对象则可以传入可变参类型数组
Class对象
public void test(String ... s){
System.out.println("方法可变参");
}
// 反射获取方法需要传入数组
Method test = classz.getDeclaredMethod("test",String[].class);
String[] sarr = {"123"};
// 方法执行需要将数组转换为Object对象
test.invoke(fatherClass,(Object) sarr);