【Java】注解Annotation

来源:互联网 发布:win10怎么激活windows 编辑:程序博客网 时间:2024/06/07 21:46

之前一直对注解一知半解的,然后花费了点时间来学习这块内容,整理如下。

一、Annotation的概念

An annotation is a form of metadata, that can be added to Java source code. Classes, methods, variables, parameters and packages may be annotated. Annotations have no direct effect on the operation of the code they annotate.

能够添加到Java源代码中的语法元数据,可以用来将信息元数据与程序元素进行关联。类,方法,变量,包都可以被注解。Annotation是被动的元数据,永远不会有主动行为
什么是元数据:描述数据的数据。

二、Annotation的作用

  1. 标记信息,用于编译的时候告诉编辑器这些标记的信息(SOURCE 源码时)
  2. 编译时动态处理,例如:编译的时候,动态生成代码(CLASS 编译时)
  3. 运行时动态处理,例如:运行的时候,动态生成代码(RUNTIME 运行时)

三、Annotation的分类

标准Annotation

标准Annotation,也是指Java中自带的三个注解 java.lang包中定义的Override(重写函数), Deprecated(函数已经过期), SuppressWarnings(忽略警告)。

元Annotation

元Annotation是指用来定义Annotation的Annotation,也就是说,是用来为注解定义注解的。

  • @Retention 什么时候使用该注解,使用Retention必须要提供一个为java.lang.annotation.RetentionPolicy类型的的枚举RetentionPolicy

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

  • @Target 注解用于什么地方,在使用时要指定一个java.lang.annotation.ElementType的枚举值类型为他的“属性”, ElementType枚举的类型如下:

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

  • @Inherited 是否允许子类继承该注解,默认false

  • @Documented 注解是否将包含在JavaDoc中。

自定义Annotation

自定义 Annotation 表示自己根据需要定义的 Annotation,定义时需要用到元 Annotation

四、自定义Annotation

使用@interface来定义一个注解,Annotation只有成员变量,没有方法。Annotation的成员变量是以 “无形参的方法”来声明,其方法名定义了该成员变量的名字,其返回值定义了该成员变量的类型。比如:

@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.FIELD})@Documented@Inheritedpublic @interface Doudou{    int value() default 1;    boolean isDa() defalut false;}

自定义一个只能在方法上使用的注解

/** * 自定义一个只能在方法上适用的注解 */@Target(ElementType.METHOD)public @interface method{    int a(); //为注解设置int类型的value}

五、Android Annotation

Android Annotation是以Support Library的形式提供给我们。

安卓注解有8种类型,分别是Nullness注解、资源类型注解、线程注解、变量限制注解、权限注解、结果检查注解、CallSuper注解、枚举注解(IntDef和StringDef)。

Nullness

包括@NoNull和@Nullable,这里以@NoNull为例说明,源码如下:

@Retention(CLASS)@Target({METHOD, PARAMETER, FIELD})public @interface NonNull {}

@NoNull编译到类文件中,应用于方法,参数,成员变量,下面来个小细腿妹的例子说明下:

public class MainActivity extends Activity {    @NonNull private String str;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        str = null;    }}

我们给成员变量str加上了@NoNull注解,也就是str不能为null,而后面我们把str初始化为null,此时as编译器这样提示我们不能为空。

资源类型Annotation

此类注解以Res结尾,比如@BoolRes, @IdRes, @IntegerRes, @StringRes, @ColorRes等,这里以@ColorRes为例说明
来个大波妹@ColorRes的源码:

@Documented@Retention(CLASS)@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE})public @interface ColorRes {}

从大波妹中可以看出@ColorRes在编译时生效,适用于方法,参数和成员变量和局部变量,下面我们再来一个脱了衣服的细腿妹的例子:

public class MainActivity extends Activity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        getCurColor(R.id.ic_launcher);    }    void getCurColor(@ColorRes int color) {        Toast.makeText(this, "Color: " + getString(color), Toast.LENGTH_LONG).show();    }}

我们给getColor函数的参数color加上了@ColorRes注解,即该参数是一个颜色资源。

权限注解

直接上三角的代码了,客官请看

 @RequiresPermission(Manifest.permission.SET_WALLPAPER) public abstract void setWallpaper(Bitmap bitmap) throws IOException;

此例说明setWallpaper方法有设置壁纸的权限。

CallSuper Annotations

继续脱,客官不要:

@CallSuperprotected void onCreate(Bundle savedInstanceState) {}

@CallSuper说明所有重写onCreate()方法的方法都要有super.onCreate();

枚举注解

很多时候,我们使用整型常量代替枚举类型(性能考虑),例如我们有一个IceCreamFlavourManager类,它具有三种模式的操作:VANILLA,CHOCOLATE和STRAWBERRY。我们可以定义一个名为@Flavour的新注解,并使用@IntDef指定它可以接受的值类型。

public class IceCreamFlavourManager {    private int flavour;    public static final int VANILLA = 0;    public static final int CHOCOLATE = 1;    public static final int STRAWBERRY = 2;    @IntDef({VANILLA, CHOCOLATE, STRAWBERRY})    public @interface Flavour {    }    @Flavour    public int getFlavour() {        return flavour;    }    public void setFlavour(@Flavour int flavour) {        this.flavour = flavour;    }}

这时如果我们使用错误的整型值调用IceCreamFlavourManager.setFlavour时,IDE将报错如下:

IDE甚至会提示我们可以使用的有效的取值:

我们也可以指定整型值作为标志位,也就是说这些整型值可以使用’|’或者’&’进行与或等操作。如果我们把@Flavour定义为如下标志位:

@IntDef(flag = true, value = {VANILLA, CHOCOLATE, STRAWBERRY})    public @interface Flavour {    }

那么可以如下调用:

iceCreamFlavourManager.setFlavour(IceCreamFlavourManager.VANILLA & IceCreamFlavourManager                .CHOCOLATE);

@StringDef用法和@IntDef基本差不多,只不过是针对String类型而已。

参考如下:
http://www.trinea.cn/android/java-annotation-android-open-source-analysis/
http://www.jianshu.com/p/1942ad208927
https://asce1885.gitbooks.io/android-rd-senior-advanced/content/shen_ru_qian_chu_android_support_annotations.html
http://blog.qiji.tech/archives/3184

0 0