Java注解相关完全解析

概述

Java中的注解常用语描述或者标记的作用,通俗的讲,就是一组语法元数据,可以用于从java代码中抽取文档、跟踪代码中的依赖性或者在编译时做检查.
可以添加到Java源代码.类、方法、变量、参数、包都可以被注解.
java8后新增了一种类型注解,可以用在代码的任何位置.可用来将信息元数据与程序元素进行关联,参考阅读Java 8新特性探究(四)类型注解 复杂还是便捷

注解作用

注解大体有如下三类作用:

  1. 标记(如@Override,@Deprecated),java标准注解就是这个作用
  2. 编译时动态处理,动态生成代码,如butterknife,Dagger2
  3. 运行时动态处理,得到注解信息,如Retrofit

注解分类

标准 Annotation

Java 语法本身自带提供了三个 Annotation,主要起到提示作用,分别是:

  1. Override(重写函数), 被@Override标注的方法如果没有覆盖父类的方法,编译时报错。
  2. Deprecated(不鼓励使用), 无论是继承、覆盖或直接使用此方法,编译器都会给出警告。
  3. SuppressWarnings(忽略某项 Warning),告诉编译器,对被标注的这句代码不要给出特定的警告.
    常见的压制警告参数有:deprecation,unchecked,fallthrough,path,serial,serialVersionUID,finally,all.

元 Annotation

元注解通常被称为注解的注解,因为定义注解的时候需要用到元注解.java提供了四类元注解,分别是:

@Retention(保留时间):
  1. SOURCE(源码时),在源文件中有效,SOURCE 大都为标记注解,如Java标准2. Annotation
  2. CLASS(编译时),在class文件中有效
  3. RUNTIME(运行时),在运行时有效
@Target(可修饰的程序元素):
  1. TYPE(描述类、接口(包括注解类型) 或enum声明),
  2. METHOD(描述方法),
  3. CONSTRUCTOR(描述构造器),
  4. FIELD(描述域),
  5. PARAMETER(描述参数),
  6. LOCAL_VARIABLE(描述局部变量),
  7. PACKAGE(描述包)
  8. 未标注则表示可修饰所有的类型
@Inherited(是否可以被继承):

默认为false
此注解说明它注解的类将自动地把这个注解传递到所有子类中而不用在子类中声明。

@Documented(会保存到 Javadoc 文档中):

默认为false

自定义Annotation

自定义注解可以使用上面的元 Annotation,根据作用域分为源码时、编译时、运行时 Annotation.

Annotation自定义

定义注意事项

一. 通过 @interface 定义,如

 public @interface 注解名 {定义体}

二. 注解方法没有方法体,没有参数没有修饰符(允许 public & abstract,默认为public),不允许抛异常

三. 返回值只能是基本类型,String, Class, annotation, enumeration 或者是他们的一维数组

四. 只有一个默认属性,可直接用 value() 函数

五. 可以加 default 表示默认值.

六. 注解参数的支持类型有

  1. 所有基本数据类型(int,float,boolean,byte,double,char,long,short)
  2. String类型
  3. Class类型
  4. enum类型
  5. Annotation类型
  6. 以上所有类型的数组

Annotation 解析

运行时注解

运行时注解即@RetentionRUNTIMEAnnotation,一般需要用到反射
如,其 @TargetMETHOD 的运行时注解的解析

method.getAnnotation(AnnotationName.class);//得到某个 Annotation 的信息
method.getAnnotations();//得到该 Target 所有 Annotation
method.isAnnotationPresent(AnnotationName.class);//该 Target 是否被某个 Annotation 修饰
编译时注解

而编译时注解即@RetentionCLASSAnnotation,有编译器在编译时自动完成,编译时注解需要用到apt技术,定义一个编译时注解的过程如下

  1. 自定义类继承AbstractProcessor,并重写其中的process函数
  2. process函数中收集注解信息,并生成相关类
  3. process 函数返回值表示这组 annotations 是否被这个 Processor 接受,如果接受后续的 processor 不会再对这个 Annotations 进行处理
@AutoService(Processor.class)//需要添加compile 'com.google.auto.service:auto-service:1.0-rc2'依赖
@SupportedSourceVersion(SourceVersion.latestSupported())
@SupportedAnnotationTypes({
   // 合法注解全名的集合
 })
public class MyProcessor extends AbstractProcessor {

    @Override
    public synchronized void init(ProcessingEnvironment env){ }

    @Override
    public boolean process(Set<? extends TypeElement> annoations, RoundEnvironment env) { }
}

java8 中的类型注解

在Java8中的Annotations是可重复的。

@interface Hints {
    Hint[] value();
}

@Repeatable(Hints.class)
@interface Hint {
    String value();
}

@Hints({@Hint("hint1"), @Hint("hint2")})
class Person {}
Hints hints1 = Person.class.getAnnotation(Hints.class);
System.out.println(hints1.value().length);  // 2

Hint[] hints2 = Person.class.getAnnotationsByType(Hint.class);
System.out.println(hints2.length);          // 2

相关概念

  1. 注解处理器(Annotation Processor)是javac的一个工具
  2. 虚处理器写好后需要注册到JVM,编译器才能在编译时自动查找所有继承自 AbstractProcessor 的类,然后调用他们的 process 方法去处理
  3. 处理器上添加@AutoService(Processor.class)即可自动注册到JVM中.AutoService注解处理器是Google开发的,会自动生成META-INF/services/javax.annotation.processing.Processor文件
  4. 注解处理器中提供了一些好用的工具包括,如Elements,Types,Filer,Messager,他们都可以通过init方法中的参数获得
  5. Elements分类包括如下
package com.example;    // PackageElement

public class Foo {        // TypeElement

    private int a;      // VariableElement
    private Foo other;  // VariableElement

    public Foo () {}    // ExecuteableElement

    public void setA (  // ExecuteableElement
                     int newA   // TypeElement
                     ) {}
}

我们可以使用EmentKind或者TypeKind来判断Element的类型,如

// 检查被注解为@Factory的元素是否是一个类
if (annotatedElement.getKind() != ElementKind.CLASS) {
     //...
}

最佳实践

基于编译时注解项目,比较著名的有想 ButterKnife,EventBus3,而运行时项目 有 Retrofit等,相关阅读:Android 打造编译时注解解析框架 这只是一个开始

实践Demo:
AnnotationDemo

参考与扩展阅读:

公共技术点之 Java 注解 Annotation

Android 打造编译时注解解析框架 这只是一个开始

Java注解处理器:讲解非常详细

Java 8 Tutorial

扩展阅读:Java 8 Annotation 新特性在软件质量和开发效率方面的提升

Android APT(编译时代码生成)最佳实践

Java 8新特性探究(四)类型注解 复杂还是便捷

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值