注解 反射

注解分类

分为标准注解和元注解

标准注解

  • @Override 对覆盖超类中的方法进行标记
  • @Deprecated 标记方法将被抛弃。如果某个类成员的提示中出现了个词,就表示这个并不建议使用这个类成员
  • @SuppressWarnings 取消特定代码中的警告

元注解

用来注解其他注解,有以下几种

  • @Target 注解所修饰的对象范围
  • @Inherited 表示注解的内容可以被子类继承
  • @Documented 表示这个注解应该被JavaDoc工具记录
  • @Retention 注解的保留策略

Target有以下取值范围

ElementType 能修饰 说明
TYPE 类、接口或枚举类型
FIELD 成员变量
METHOD 方法
PARAMETER 参数
CONSTRUCTOR 构造器
LOCAL_VARIABLE 局部变量
ANNOTATION_TYPE 注解
PACKAGE

Retention 自定义注解的有效范围

  • RetentionPolicy.SOURCE: 源码级注解 只在源代码中保留 一般都是用来增加代码的理解性或者帮助代码检查之类的,比如我们的Override;
  • RetentionPolicy.CLASS: 编译时注解 默认的选择,能把注解保留到编译后的字节码class文件中,仅仅到字节码文件中,运行时是无法得到的;
  • RetentionPolicy.RUNTIME: 运行时注解,注解不仅 能保留到class字节码文件中,还能在运行通过反射获取到,这也是我们最常用的。

注解代替枚举

通过View.VISIBLE的源码,我们可以发现VISIBLE,INVISIBLE和GONE是用注解来实现枚举的作用的

    @IntDef({VISIBLE, INVISIBLE, GONE})
    @Retention(RetentionPolicy.SOURCE)
    public @interface Visibility {}
    
    public static final int VISIBLE = 0x00000000;
    public static final int INVISIBLE = 0x00000004;
    public static final int GONE = 0x00000008;

Android注解

在android.support.annotation包中也提供了许多资源的注解

name exp
AnimRes 动画
AnimatorRes animator资源类型
AnyRes 任何资源类型
ArrayRes 数组资源
AttrRes attr
BoolRes bool资源
ColorRes 颜色资源
DimenRes 尺寸资源
DrawableRes 图片资源
IdRes id资源
InterpolatorRes 插值器资源
LayoutRes 布局资源
MenuRes 菜单资源
RawRes raw资源
StringRes 字符资源
StyleRes 风格资源
StyleableRes styleable资源
TransitionRes transition资源类型
XmlRes xml资源

资源注解是为了防止我们在使用程序资源的时候,错误传递资源类型给函数,导致程序错误

Null注解

  • @NonNull:不能为空
  • @Nullable:可以为空

线程注解

  • @UiThread
  • @BinderThread只在绑定线程上
  • @WorkerThread子线程
  • @AnyThread任意

其他

  • IntDef
  • StringDef
  • LongDef
  • RequiresApi 表示注释的元素只应在给定API级别或更高级别上调用。
  • RequiresPermission
   @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
   public abstract Location getLastKnownLocation(String provider);
   
   @RequiresPermission(allOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
   public abstract Location getLastKnownLocation(String provider);
 
  • IntRange
private void testDo(@IntRange(from = 1,to = 100)int s){
        Log.e("tag","-------->"+s);
    }
  • Size 表示注释的元素应该具有给定的大小或长度。注意“-1”的意思是“未设置”
  • floatRange
    可以在google文档中查看

注解处理器

是javac的一个工具,用来扫描和处理注解。就是在编译时期,通过注解生成.java文件。针对运行时,采用反射机制。针对编译时,注解会采用AbstractProcessor处理

1647e53e3d5d3365.jpg

Step 1 新增注解类

新建Module来存放注解,取名为annotations

1647def00161e26d.jpg

同时新增一个注解类

@Retention(RetentionPolicy.CLASS)
@Target(ElementType.FIELD)
public @interface BindView {
    int value();
}

Step 2 编写注解处理器

新建一个java library,命名为apt-processor

1647df7689b1ffaf.jpg

里面的build.gradle跟android library的内容有些不一样,同时添加依赖apt-annotations

apply plugin: 'java-library'

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation project(':apt-annotations')   //implementation替代了之前的compile
}

sourceCompatibility = "1.7"
targetCompatibility = "1.7"

接着编写注解处理器ClassProcessor,继承自AbstractProcessor

public class ClassProcessor extends AbstractProcessor{

    @Override
    public synchronized void init(ProcessingEnvironment processingEnvironment) {
        super.init(processingEnvironment);
    }

    @Override
    public Set getSupportedAnnotationTypes() {
        return super.getSupportedAnnotationTypes();
    }

    @Override
    public SourceVersion getSupportedSourceVersion() {
        return super.getSupportedSourceVersion();
    }

    @Override
    public boolean process(Set set, RoundEnvironment roundEnvironment) {
        return false;
    }
}
  • init
    初始化。可以得到ProcessingEnviroment,ProcessingEnviroment提供很多有用的工具类Elements, Types 和 Filer
  • process
    可以在这里写扫描、评估和处理注解的代码,生成Java文件
  • getSupportedAnnotationTypes
    指定这个注解处理器是注册给哪个注解的,这里说明是注解BindView
  • getSupportedSourceVersion
    返回java版本。通常返回SourceVersion.latestSupported

Step 3 注册注解处理器

在processor中添加依赖

implementation 'com.google.auto.service:auto-service:1.0-rc4'

在注解处理器ClassProcessor中添加@AutoService(Processor.class)

Step 4 app依赖

dependencies {
    implementation project(':apt-annotation')
    annotationProcessor project(':apt-processor')
}

注解处理器只在编译期间用到,处理完后没有作用,
使用apt插件可以减少引入不必要的文件。官方(Android)提供了annotationProcessor来代替android-apt

参考APT,里面写了如何去生成一个java文件,可以通过javapoet工具

反射

Java反射机制是指在运行状态中
对于任意一个类,都能知道这个类的所有属性和方法;
对于任何一个对象,都能够调用它的任何一个方法和属性;
这样动态获取新的以及动态调用对象方法的功能就叫做反射。

1.获取Clas的三种方法

Class c = Class.forName("java.lang.String");

Class c1 = String.Class;

String str = new String();
Class c2 = str.getClass();

2.获取成员变量

Field[] fields = c.getDeclaredFields();

获取字段的修饰符
int fieldValue = field.getModifiers();//如:private、static、final等

与某个具体的修饰符进行比较
Modifier.isStatic(fieldValue)//看此修饰符是否为静态(static)

获取字段的声明类型
field.getType();//返回的是一个class

3.获取类的方法

Method[] methods = c.getDeclaredMethods();

                方法                              含义        
      m.getParameterTypes()             获取传入参数类型Class[]
        m.getReturnType()                获取方法返回类型Class 

c.getDeclaredMethod("方法名",类型.class...) 获取特定的方法
c.getDeclaredConstructors() 获取所有的构造方法
c.getDeclaredConstructor(类型.class...) 获取指定的构造方法
c.getSuperclass() 获取父类Class
c.getInterfaces() 获取实现的接口Class[]

运行时注解,是通过反射获取

public T getAnnotation(Class annotationClass)

如果存在于此元素,则返回该元素注释指定的注释类型,否则返回为null

@Retention(RetentionPolicy.RUNTIME)
//Retention注解决定MyAnnotation注解的生命周期
@Target( { ElementType.METHOD, ElementType.TYPE })
public @interface MyAnnotation {
    String color() default "blue";//为属性指定缺省值
}

private void ResolveClass(String className) {
        try {
            Class clazz = classLoader.loadClass(className);
            Class aClass = classLoader.loadClass(MyAnnotation .class.getName());
            System.out.println(clazz.getName());
            MyAnnotation annotation = clazz.getAnnotation(MyAnnotation .class);
            if(annotation != null) {
                System.out.println(annotation.color());
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }

你可能感兴趣的:(注解 反射)