注解入门
注解和注释
注释是给人看的,注解是给机器(编译器,虚拟机)看的。
注解的概念
注解是一个标识,或者说是标签。
注解是一系列元数据,它提供数据用来解释程序代码,但是注解并非是所解释的代码本身的一部分。注解对于代码的运行效果没有直接影响。
注解有许多用处,主要如下:
- 提供信息给编译器: 编译器可以利用注解来探测错误和警告信息
- 编译阶段时的处理: 软件工具可以用来利用注解信息来生成代码、Html文档或者做其它相应处理。
- 运行时的处理: 某些注解可以在程序运行的时候接受代码的提取
注解长什么样,怎么用,如何生效,效果是什么
需要提前说的是,单单为一个类/一个方法/一个变量/等添加注解,完全不会影响代码地运行。重要的是程序对注解进行提取,根据提到的注解做一定的事情才会起作用(提取以及响应可以由编译器、框架代码或者开发者自己处理,一般框架只会处理框架定义的注解,开发人员也只会处理自己定义的注解)。
先来一个系统定义的 : Override
//注解的定义是这样的
@Target(ElementType.METHOD)//标明该注解的使用对象是方法
@Retention(RetentionPolicy.SOURCE)//标明该注解的生效场景是在源码中
public @interface Override {
}
//注解的使用是这样的
@Override
public void methodDefineInParentType(){
// your code...
}
// 如何生效
// 前面注释说到了该注解仅在源码中生效,由编译器识别注解,并且给予开发者提示
// 效果是什么
// 如果父类定义了该方法,则没有什么效果,仅用于提示。如果父类没有该方法,则编译器给出提示,并且编译器不允许编译通过(其实编译器也可以允许编译通过,即使通过,也不影响代码的运行效果)
再来一个自定义的:
/**
* 自定义注解跟系统定义的注解都一样,可以使用元注解对注解进行说明
* Target = Element.TYPE 说明了该注解可以作用在类和接口上
**/
@Target(ElementType.TYPE)//可以用在类、接口、枚举类上
@Retention(RetentionPolicy.RUNTIME)//保留到运行时
public @interface UselessAnnotation{
String stringValue() default "test";//添加了一个成员变量,变量的默认值是test
}
//使用
@UselessAnnotation(stringValue = "helloWorld")
public class MainActivity extends AppCompatActivity {
...
//1. 判断MainActivity.class上是否存在特定类型的注解
//2. 获取MainActivity.class上是特定类型的注解
//3. 获取注解的变量值并且赋值给一个textView
if (MainActivity.class.isAnnotationPresent(UselessAnnotation.class)) {
UselessAnnotation annotation = MainActivity.class.getAnnotation(UselessAnnotation.class);
String string = annotation.stringValue();
textView.setText(string);
}
...
}
元注解
作用在注解上的注解叫做元注解。
Java提供的元注解有五种:
- @Retention : 设置保留期
- @Documented :设置是否在javaDoc中呈现
- @Target :设置注解的作用对象
- @Inherited ://设置注解可被继承
- @Repeatable ://设置注解可重复
@Retention
retention用于说明注解保留的时间
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
/**
* Returns the retention policy.
* @return the retention policy
*/
RetentionPolicy value();
}
public enum RetentionPolicy {
/**
* Annotations are to be discarded by the compiler.
* 注解只在源码中存在,保留到编译之前,在编译时就扔掉了
*/
SOURCE,
/**
* Annotations are to be recorded in the class file by the compiler
* but need not be retained by the VM at run time. This is the default
* behavior.
* 保留到编译器进行编译时,编译时注解可以在编译时被注解处理器进行处理,然后插入生成代码之类的(这也是很多编译时注解框架使用的方法)。
* 但是不会保留到运行时
*/
CLASS,
/**
* Annotations are to be recorded in the class file by the compiler and
* retained by the VM at run time, so they may be read reflectively.
* 保留到Java字节码文件中,并且被加载到虚拟机中,故而可以在运行时通过反射获取
*
* @see java.lang.reflect.AnnotatedElement
*/
RUNTIME
}
@Documented
顾名思义,这个元注解肯定是和文档有关。它的作用是能够将注解中的元素包含到 Javadoc 中去
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Documented {
}
@Target
Target 是目标的意思,@Target 指定了注解运用的地方。
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
/**
* Returns an array of the kinds of elements an annotation type
* can be applied to.
* @return an array of the kinds of elements an annotation type
* can be applied to
*/
ElementType[] value();
}
@Target 有下面的取值
- ElementType.ANNOTATION_TYPE 可以作用于注解
- ElementType.CONSTRUCTOR 可以作用于构造方法
- ElementType.FIELD 可以作用于属性
- ElementType.LOCAL_VARIABLE 可以作用于局部变量
- ElementType.METHOD 可以作用于方法
- ElementType.PACKAGE 可以作用于包
- ElementType.PARAMETER 可以作用于参数
- ElementType.TYPE 可以作用于一个类型,比如类、接口、枚举
@Inherited
如果一个超类被 @Inherited 注解过的注解进行注解的话,那么如果它的子类没有被任何注解应用的话,那么这个子类就继承了超类的注解。
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Inherited {
}
@Repeatable
@Repeatable 是 Java 1.8 才加进来的,所以算是一个新的特性。
什么样的注解会多次应用呢?通常是注解的值可以同时取多个(这似乎可以被数组取代)。暂时不明白它的独特点。
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Repeatable {
/**
* Indicates the <em>containing annotation type</em> for the
* repeatable annotation type.
* @return the containing annotation type
*/
Class<? extends Annotation> value();
}