两种注解的基本使用

来源:互联网 发布:杭州网络推广营销 编辑:程序博客网 时间:2024/06/04 19:07

首先介绍下注解的基本知识,详细使用方法请自行百度
首先注解分为三类:
标准 Annotation,元 Annotation,自定义 Annotation
(1).标准 Annotation
包括 Override, Deprecated, SuppressWarnings,是java自带的几个注解,他们由编译器来识别,不会进行编译,
不影响代码运行,至于他们的含义不是这篇博客的重点,这里不再讲述。
(2).元 Annotation
@Retention, @Target, @Inherited, @Documented,它们是用来定义 Annotation 的 Annotation。也就是当我们要自定义注解时,需要使用它们。
(3).自定义 Annotation
根据需要,自定义的Annotation。而自定义的方式,下面我们会讲到。
同样,自定义的注解也分为三类,通过元Annotation - @Retention 定义:
@Retention(RetentionPolicy.SOURCE)
源码时注解,一般用来作为编译器标记。如Override, Deprecated, SuppressWarnings。
@Retention(RetentionPolicy.RUNTIME)
运行时注解,在运行时通过反射去识别的注解。
@Retention(RetentionPolicy.CLASS)
编译时注解,在编译时被识别并处理的注解

这里主要介绍下运行时注解,和编译时注解。

所谓运行时注解是指,注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在;所以注解信息会加入到class文件中,在使用的时候通过反射方法拿到注解的传递数值.这就是为什么说,使用注解会影响性能,就是因为使用了反射。下面通过一个简单例子进行解释说明。
编写注解,含有名字name,年龄age ,年龄设置有默认值10

 @Target({ElementType.TYPE,ElementType.FIELD, ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)@Inherited@Documentedpublic @interface Deanitation {    String name();    int age() default 10;}

@Retention(RetentionPolicy.RUNTIME)表示该注解是运行时注解,@Target({ElementType.TYPE,ElementType.FIELD, ElementType.METHOD})表示该注解能作用的范围,

在类中使用方法如下:

 @Deanitation(name ="test")public class Test {    @Deanitation(name = "run",age = 17)    public void run(){        System.out.print("run");    }}

然后在Main方法执行过程中通过反射获取注解标注的信息:

public static void main(String[] args) {        try {            Class c=Class.forName("com.zhujie.Test");            //2.判断类上是否存在注解,并获取类上面注解的实例            if(c.isAnnotationPresent(Deanitation.class)){                Deanitation Description = (Deanitation) c.getAnnotation(Deanitation.class);                System.out.println(Description.name());                System.out.println(Description.age());            }            //3.判断方法上是否存在注解,并获取方法上面注解的实例            Method[] ms = c.getMethods();            for (Method method : ms) {                if(method.isAnnotationPresent(Deanitation.class)){                    Deanitation Description = (Deanitation)method.getAnnotation(Deanitation.class);                    System.out.println(Description.name());                    System.out.println(Description.age());                }            }            //另一种获取方法上的注解的解析方法            for (Method method : ms) {                Annotation[] as = method.getAnnotations();                for (Annotation annotation : as) {                    if(annotation instanceof Deanitation){                        System.out.println(((Deanitation) annotation).name());                        System.out.println(((Deanitation) annotation).age());                    }                }            }        } catch (ClassNotFoundException e) {            e.printStackTrace();        }    }

以上就是运行时注解使用的基本方法,应为在使用过程中使用反射,所以对性能有影响,使用范围也有限制。下面模拟ButterKnife的使用过程,说明下编译时注解的使用。
建立项目后,因为要继承AbstractProcessor编写自定义注解解释器,所以要建立一个javalib的module,在改module下编写注解类DebindVeiw

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

下面编写自定义注解解释器,主要是继承AbstractProcessor重写process方法,其中核心步骤是获取注解集合,然后生成所需要的java文件

 @Override    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {        messager.printMessage(Diagnostic.Kind.NOTE, "process...");        mProxyMap.clear();        Set<? extends Element> elesWithBind = roundEnv.getElementsAnnotatedWith(DeBindView.class);        for (Element element : elesWithBind) {            checkAnnotationValid(element, DeBindView.class);            VariableElement variableElement = (VariableElement) element;            //class type            TypeElement classElement = (TypeElement) variableElement.getEnclosingElement();            //full class name            String fqClassName = classElement.getQualifiedName().toString();            messager.printMessage(Diagnostic.Kind.NOTE, fqClassName);            ProxyInfo proxyInfo = mProxyMap.get(fqClassName);            if (proxyInfo == null) {                proxyInfo = new ProxyInfo(elementUtils, classElement);                mProxyMap.put(fqClassName, proxyInfo);            }            DeBindView bindAnnotation = variableElement.getAnnotation(DeBindView.class);            int id = bindAnnotation.value(); /**获取View iD**/            proxyInfo.injectVariables.put(id, variableElement);        }        /**         * 生成所需要的java类         */        for (String key : mProxyMap.keySet()) {            ProxyInfo proxyInfo = mProxyMap.get(key);            try {                JavaFileObject jfo = processingEnv.getFiler().createSourceFile(                        proxyInfo.getProxyClassFullName(),                        proxyInfo.getTypeElement());                Writer writer = jfo.openWriter();                writer.write(proxyInfo.generateJavaCode());                writer.flush();                writer.close();            } catch (IOException e) {                error(proxyInfo.getTypeElement(),                        "Unable to write injector for type %s: %s",                        proxyInfo.getTypeElement(), e.getMessage());            }        }        return true;    }

下面生成的java文件
根据注解生成的类
当然还要编写使用的API,我们要新建一个android lib module 在里面编写一个注册类,通过反射初始化 生成的类。达到初始化view findviewById()作用。

public class ViewInjector {    private static final String SUFFIX = "$$ViewInject";    public static void injectView(Activity activity) {        ViewInject proxyActivity = findProxyActivity(activity);        proxyActivity.inject(activity, activity);    }    public static void injectView(Object object, View view) {        ViewInject proxyActivity = findProxyActivity(object);        proxyActivity.inject(object, view);    }    private static ViewInject findProxyActivity(Object activity) {        try {            Class clazz = activity.getClass();            Class injectorClazz = Class.forName(clazz.getName() + SUFFIX);            return (ViewInject) injectorClazz.newInstance();        } catch (ClassNotFoundException e) {            e.printStackTrace();        } catch (InstantiationException e) {            e.printStackTrace();        } catch (IllegalAccessException e) {            e.printStackTrace();        }        throw new RuntimeException(String.format("can not find %s , something when compiler.", activity.getClass().getSimpleName() + SUFFIX));    }}

使用方法如下:

  @DeBindView(R.id.tv_text)    TextView textView;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_annotation);        ViewInjector.injectView(this);    }

以上就是简单的使用编译时注解,完成时间绑定,详细代码请下载查看,包含annotationapi ,javalib 两个module,其中annotationapi 依赖javalib 。使用的时候导入module 主module app只需要依赖annotationapi就可以了
下载地址:点击