个人博客
http://www.milovetingting.cn 
 
Java中的注解和反射 注解 Java注解(Annotation)又称Java标注,是JDK5.0引入的一种注释机制。
注解定义 通过@interface来声明一个注解
1 2 3 public  @interface  Anno {     } 
元注解 对注解进行注解的类就是元注解(meta-annotation),在自定义时,一般需要指定两个元注解
@Target 限制可以应用注解的Java元素类型,包括以下几种:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 public  enum  ElementType  {         TYPE,          FIELD,          METHOD,          PARAMETER,          CONSTRUCTOR,          LOCAL_VARIABLE,          ANNOTATION_TYPE,          PACKAGE,          TYPE_PARAMETER,          TYPE_USE } 
TYPE:作用于类、接口或者枚举
FIELD:作用于字段
METHOD:作用于方法
PARAMETER:作用于方法参数
CONSTRUCTOR:作用于构造方法
LOCAL_VARIABLE:作用于局部变量
ANNOTATION_TYPE:作用于注解
 
@Retention 指定注解的保留阶段,有以下几种
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public  enum  RetentionPolicy  {         SOURCE,          CLASS,          RUNTIME } 
注解类型元素 1 2 3 4 5 6 7 8 9 10 @Retention(RetentionPolicy.SOURCE) @Target(ElementType.TYPE) public  @interface  Anno {         String value () ;          int  age ()  default  18 ; } 
注解应用场景 根据Retention的类型,注解的应用场景有以下三种:
SOURCE 作用于源码级别的注解,可提供给IDE语法检查、APT等场景使用。
IDE语法检查 Android中提供了@IntDef注解
1 2 3 4 5 6 7 8 9 @Retention(SOURCE) @Target({ANNOTATION_TYPE}) public  @interface  IntDef {         int [] value() default  {};          boolean  flag ()  default  false ; } 
这个注解的意义在于能够取代枚举,实现如方法入参限制。
如我们要限制参数只能在MONDAY和TUESDAY中的一个,可以先定义常量
1 2 3 4 5 6 7 public  class  WeekDay  {    public  static  final  int  MONDAY  =  1 ;     public  static  final  int  TUESDAY  =  2 ; } 
然后定义注解
1 2 3 4 5 6 @IntDef(value = {WeekDay.MONDAY, WeekDay.TUESDAY}) @Target(ElementType.PARAMETER) @Retention(RetentionPolicy.SOURCE) public  @interface  Week {} 
使用注解
1 2 3 4 5 6 7 8 9 public  void  test (@Week  int  week)  {} protected  void  onCreate (Bundle savedInstanceState)  {    super .onCreate(savedInstanceState);     setContentView(R.layout.activity_main);     test(WeekDay.MONDAY); } 
APT注解处理器 APT全称为:”Anotation Processor Tools”,意为注解处理器。编写好的Java源文
注解处理器是对注解应用最为广泛的场景。在Glide、EventBus、ButterKnife、ARouter等常用框架中都有注解处理器的身影。
CLASS 定义为CLASS的注解,会保留在class文件中,但是会被JVM忽略。应用场景为:字节码增强,通过修改字节码文件来达到修改代码执行逻辑的目的。常用的框架有:AspectJ、热修复Roubust。
RUNTIME 注解保留至运行期,我们可以通过反射获取注解中的所有信息。
反射 反射就是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;并且能改变它的属性。
Class Class是一个类,封装了当前对象所对应的类的信息。
获取Class对象 获取Class对象的三种方法
创建实例 
使用Class对象的newInstance()方法来创建Class对象对应类的实例。 
 
1 2 Class<?> c = String.class; Object  str  =  c.newInstance();
先通过Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法来创建实例。这 
 
1 2 3 4 5 6 7 Class<?> c = String.class; Constructor  constructor  =  c.getConstructor(String.class);Object  obj  =  constructor.newInstance("hello" );System.out.println(obj); 
获取构造器信息 得到构造器的方法
1 2 3 4 Constructor getConstructor (Class[] params)  -- 获得使用特殊的参数类型的public 构造函数(包括父类) Constructor[] getConstructors() -- 获得类的所有公共构造函数 Constructor getDeclaredConstructor (Class[] params)  -- 获得使用特定参数类型的构造函数(包括私有) Constructor[] getDeclaredConstructors() -- 获得类的所有构造函数(与接入级别无关) 
获取类构造器的用法与上述获取方法的用法类似。主要是通过Class类的getConstructor方法得到Constructor类的
1 public  T newInstance (Object ... initargs) 
获取类的成员变量信息 1 2 3 4 Field getField (String name)  -- 获得命名的公共字段 Field[] getFields() -- 获得类的所有公共字段 Field getDeclaredField (String name)  -- 获得类声明的命名的字段 Field[] getDeclaredFields() -- 获得类声明的所有字段 
调用方法 获得方法信息的方法
1 2 3 4 Method getMethod (String name, Class[] params)  -- 使用特定的参数类型,获得命名的公共方法 Method[] getMethods() -- 获得类的所有公共方法 Method getDeclaredMethod (String name, Class[] params)  -- 使用特写的参数类型,获得类声明的命名的方法 Method[] getDeclaredMethods() -- 获得类声明的所有方法 
当我们从类中获取了一个方法后,我们就可以用 invoke() 方法来调用这个方法。 invoke 方法的原型为:
1 public  Object invoke (Object obj, Object... args) 
利用反射创建数组 数组在Java里是比较特殊的一种类型,它可以赋值给一个Object Reference 其中的Array类为
1 public  static  Object newInstance (Class<?> componentType, int  length) ;
反射获取泛型真实类型 1 2 3 Type  genType  =  object.getClass().getGenericSuperclass();Type[] params = ((ParameterizedType) genType).getActualTypeArguments(); return  (Class<?>) params[0 ];
基于注解和反射的简单应用 通常我们获取Intent传过来的extra,是通过这样的形式:
1 2 getIntent().getStringExtra("name" ); getIntent().getIntExtra("age" ,18 ); 
现在,我们通过注解和反射实现自动获取Extra,类似这样:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @InjectExtra private  String name;@InjectExtra("age") private  int  age;@InjectExtra("gender") private  boolean  gender;@Override protected  void  onCreate (@Nullable  Bundle savedInstanceState)  {    super .onCreate(savedInstanceState);     InjectHelper.inject(this );     Log.i(TAG, "name:"  + name + ",age:"  + age + ",gender:"  + gender); } 
实现步骤
定义注解 
 
1 2 3 4 5 @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public  @interface  InjectExtra {    String value ()  default  "" ; } 
定义InjectHelper 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 public  class  InjectHelper  {         public  static  void  inject (Activity activity)  {         try  {             Class<? extends  Activity > clz = activity.getClass();             Field[] declaredFields = clz.getDeclaredFields();             for  (Field field : declaredFields) {                 boolean  annotationPresent  =  field.isAnnotationPresent(InjectExtra.class);                 if  (annotationPresent) {                     InjectExtra  annotation  =  field.getAnnotation(InjectExtra.class);                     String  name  =  annotation.value();                     if  (TextUtils.isEmpty(name)) {                                                  name = field.getName();                     }                     Object  object  =  activity.getIntent().getExtras().get(name);                     field.setAccessible(true );                     field.set(activity, object);                 }             }         } catch  (Exception e) {             e.printStackTrace();         }     } } 
使用 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 public  class  MainActivity  extends  AppCompatActivity  {    @Override      protected  void  onCreate (Bundle savedInstanceState)  {         super .onCreate(savedInstanceState);         setContentView(R.layout.activity_main);         Intent  intent  =  new  Intent (this , TargetActivity.class);         intent.putExtra("name" , "zs" );         intent.putExtra("age" , 18 );         intent.putExtra("gender" , true );         startActivity(intent);     } } public  class  TargetActivity  extends  AppCompatActivity  {    private  static  final  String  TAG  =  InjectHelper.class.getSimpleName();     @InjectExtra      private  String name;     @InjectExtra("age")      private  int  age;     @InjectExtra("gender")      private  boolean  gender;     @Override      protected  void  onCreate (@Nullable  Bundle savedInstanceState)  {         super .onCreate(savedInstanceState);         InjectHelper.inject(this );         Log.i(TAG, "name:"  + name + ",age:"  + age + ",gender:"  + gender);     } } 
输出结果 
 
1 2020-04-27 10:38:22.495 19687-19687/com.wangyz.annotation I/InjectHelper: name:zs,age:18,gender:true 
这里为了演示注解与反射,指定Retentaion为RUNTIME,实际上可以指定为SOURCE级别,通过APT来生成辅助类,来减少手动获取Extra的工作量。