IOC反射注解框架
IOC 反射注解框架
本文地址:https://blog.csdn.net/xiaowu_zhu/article/details/83019525
IOC 反射框架包含了java反射、注解(运行时)、Android相关的控件注入等
Java反射
在Android中反射无处不在,当我们观看Android源码的时候,你就会发现官方用了好多反射,我们反射构造方法、方法、成员变量、静态字段和类型等。
由于篇幅有限,就不详细讲解了,就讲讲我经常用到的吧。
反射会影响性能,请按需使用
注意: 在反射私有的时候,需要设置setAccessible(true)
,不然会报错
通过反射获取构造方法
-
带有参数的构造方法
//开放的构造方法 public Constructor<T> getConstructor(Class<?>... parameterTypes){} //私有的构造方法 public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes){}
-
获取所有的构造方法
//获取所有开放的构造方法 @CallerSensitive public Constructor<?>[] getConstructors() throws SecurityException {} //获取私有的构造方法 public Constructor<?>[] getDeclaredConstructors() throws SecurityException {}
-
用法
-
创建一个对象T实例
T.class.get...(...) //根据类的实际构造方法、参数来调用
-
如果我们要实例话的类中有无参的构造方法,我们可以通过以下方式创建
T.class.newInstance() //创建一个对象实例
-
通过反射获取变量
- 通过字段的名字获取成员变量的Field
//根据name获取公开的成员变量
public Field getField(String name){}
//根据name获取私有的成员变量(是个navtive方法)
public native Field getDeclaredField(String name) throws NoSuchFieldException;
- 获取某个类中所有的成员变量Field
//获取公有的
@CallerSensitive
public Field[] getFields() throws SecurityException {}
//获取私有的
@FastNative
public native Field[] getDeclaredFields();
- 通过获取到的Field,调用
get
andset
方法获取值和设置值
//t为某个对象实例
Field field = t.getClass().getField("name");
//通过调用Field中的get方法,获取到相应的值
Object object = field.get(t);
//通过Field中的set方法,设置值
field.set(t, "张三");
//如果field是静态的变量,获取值的时候get参数为null
Object object = field.get(null);
知识点:
在基本数据类型的包装类
需要获取它们的基本类型
时,通过查看源码可用:
- 如需要通过反射将
Integer.class
–>int.class
时, 其余类似:
Class<?> intClass = Integer.class.getField("TYPE").get(null);
通过反射执行某个方法
-
通过方法名和参数获取方法
//获取公开的方法 @CallerSensitive public Method getMethod(String name, Class<?>... parameterTypes) throws NoSuchMethodException, SecurityException { } //获取私有的方法 @CallerSensitive public Method getDeclaredMethod(String name, Class<?>... parameterTypes) throws NoSuchMethodException, SecurityException { }
-
获取所有的方法
//获取有的公开方法 @CallerSensitive public Method[] getMethods() throws SecurityException { } //获取所有的私有方法 public Method[] getDeclaredMethods() throws SecurityException { }
-
通过获取到的方法反射执行
//通过方法名获取T对象中公开的setName方法 Method method =T.class.getMethod("setName"); //反射执行方法,setName(name), t为T对象的实例,“name”是参数 method.invoke(t, "name");
以上几种方式都是比较常用的,但是反射不仅仅只是于此,我们还可以用途来获取类,接口,修饰符等等
获取泛型的类型
//获取当前运行类的泛型对象
public static <T> Type analysisClassType(T t) {
Type type = t.getClass().getGenericSuperclass();
Type[] typeArguments = ((ParameterizedType) type).getActualTypeArguments();
return typeArguments[0];
}
使用反射的优化
我们都知道使用反射会影响性能,但是这点性能相对于手机渲染UI等来说,并没有多严重。但是我们也需要做一些优化,来减少影响。
-
善用API
尽量直接获取,不要遍历,比如: 尽量使用
getMethod("")
来获取方法,而少用getMethods()
-
常用的缓存
比如,需要多次动态创建一个类的实例的时候,有缓存的写法会比没有缓存要快很多:
// 1. 没有缓存 void createInstance(String className){ return Class.forName(className).newInstance(); } // 2. 缓存forName的结果 void createInstance(String className){ cachedClass = cache.get(className); if (cachedClass == null){ cachedClass = Class.forName(className); cache.set(className, cachedClass); } return cachedClass.newInstance(); }
注解
注解可以向编译器、虚拟机等解释说明一些事情。
系统注解
系统提供了很多注解,比如我们常见的@Overried
,它作用于某个方法上,表示此方法复写了父类的某个方法。在这里就不一一介绍了。
自定义注解
注解用@interface
定义一个注解。下面是一个自定义注解:
@Target(ElementType.TYPE) //注解作用于位置
@Retention(RetentionPolicy.RUNTIME) //注解的生命期
public @interface ContentView {
@LayoutRes int value() default -1; //可选
}
解释:
-
@Target
修饰,表示当前这个注解作用于那种类型,他有如下几种类型:public enum ElementType { /** Class, interface (including annotation type), or enum declaration */ TYPE, //类 /** Field declaration (includes enum constants) */ FIELD, //字段 /** Method declaration */ METHOD, //方法 /** Formal parameter declaration */ PARAMETER, //参数 /** Constructor declaration */ CONSTRUCTOR, //构造方法 /** Local variable declaration */ LOCAL_VARIABLE, //局部变量 /** Annotation type declaration */ ANNOTATION_TYPE,//注解类型 /** Package declaration */ PACKAGE, //包上 /** * Type parameter declaration * @since 1.8 */ TYPE_PARAMETER, //类类型 /** * Use of a type * @since 1.8 */ TYPE_USE // }
-
@Retention
修饰,表示当前注解的生命周期,可以分为运行时注解
和编译时注解。
有如下类型:
public enum RetentionPolicy { /** * Annotations are to be discarded by the compiler. */ SOURCE, //作用于源码 /** * Annotations are to be recorded in the class file by the compiler * but need not be retained by the VM at run time. This is the default * behavior. */ CLASS, //作用于类,编译时 /** * Annotations are to be recorded in the class file by the compiler and * retained by the VM at run time, so they may be read reflectively. * * @see java.lang.reflect.AnnotatedElement */ RUNTIME //运行时 }
自定义注解的处理方式
-
运行时注解
运行时注解,表示该注解在程序运行时才会起作用,
@Retention(RetentionPolicy.RUNTIME)
/** * 寻找@ContentView()标注的注解 */ private static ContentView findContentView(Class<?> clazz) { //判断当前的class是不是有contentView标识 boolean annotationPresent = clazz.isAnnotationPresent(ContentView.class); if (annotationPresent) { return clazz.getAnnotation(ContentView.class); //有就取出,返回 } findContentView(clazz.getSuperclass());//没有继续查找 return null; }
-
编译时注解
编译时注解是在程序编译时由java提供的
AbstractProcessor
类,生成一些方法,目前没有手动去写过,感兴趣的可以去参考ButterKinfe的开源库。
例子
具体使用的例子,请查看:github–> IOC