一、前言
本文分析注解体系的主要目的有如下三点:
- 个人的知识体系的梳理,希望能把书由薄读厚,再由厚读薄;
- 为后续博文,仿ButterKnife框架的内容铺垫;
- ORM类型框架中大量使用到了注解的内容,明确注解意义及使用方法,能够打通学习ORM类型框架的任督二脉。
进入正题:
- 用专业名词解释专业名词的注解说明版本如下:
- 个人认为这样去理解适合于有经验的开发同学。
从JDK5开始,Java增加了对元数据(MetaData)的支持,也就是Annotation(即注解),这里介绍的注解,其实是代码里的特殊标记,这些标记可以在编译、类加载。运行时被读取,并执行相应的处理。通过使用注解,程序开发人员可以在不改变原有逻辑的情况下,在源文件中嵌入一些补充的信息。代码分析工具、开发工具和部署工具可以通过改变这些补充信息进行验证或者进行部署。 ———《疯狂Java讲义》
二、注解体系
1、注解概述
注解提供了一种为程序元素设置元数据的方法,从某些方面来看,注解就像修饰符一样,可以用于修饰包、类、构造器、方法、成员变量、参数、局部变量的声明,这些信息被储存在注解的“name=value”对中。
注解能被用来为程序元素(类、方法、成员变量)设置元数据。值得指出的是,注解不影响程序代码的执行,无论添加、删除注解,代码都始终如一的执行。如果希望让程序中的注解在运行时起一定的作用,只有通过某种配套的工具对注解中的信息进行访问和处理,访问和处理注解的工具统称为APT(Annotation Processing Tool)。
1.1 元数据(metadata)
元数据(metadata):就是关于数据的数据。
- 示例:
①表格中呈现的是数据,而表格还会有额外的数据来说明表格的作用,这个就是表格的元数据。
②数据库中的表存放了数据,但表还需要有表的定义、字段的定义等,这个就是数据库表的元数据。
③XML文件可以存放数据。但xml文件的每个标签还需要有相应的描述,这些描述就是XML标签的元数据。 - 元数据可以用于创建文档,跟踪代码中的依赖性,甚至执行基本编译时检查。
1.2 什么是Annotation
- JDK5.0通过名为Annotation(注解)的新功能将一个更通用的元数据工具合并到核心 Java 语言中。
- 注解是可以添加到代码中的修饰符,对程序代码做出一些说明和解释。可以用于包声明、类声明、构造方法、方法、字段、参数和变量。
这样就将程序的元素和元数据联系起来。编译器就可以将元数据存储在Class文件中。之后虚拟机和其它对象可以根据这些元数据来决定如何使用这些程序元素或改变它们的行为。 - JDK5.0包含了内置注解,还支持编写定制注解。
1.3 注解基本知识
- 注解采用“@”标记形式 ,后面跟注解类型名称。通过(name=value)向注解提供参数数据。每次使用这类表示法时,就是在生成注解。
注解类型和注解的区别:注解类型类似于类,注解类似于该类的实例
2、内置注解类型
2.1 内置注解类型—Override
- Override 指明被注解的方法必须是重写超类中的方法。仅能用于方法之上。
编译器在编译源代码时会检查用@Override标注的方法是否有重写父类的方法。
举例如下:
public class InternalAnnotationTest {
@Override
public String toString() {
return super.toString() + " [Override toString]";
}
public static void main(String[] args) {
TestAnnotation test = new TestAnnotation();
System.out.println(test);
}
}
2.2 内置注解类型—Deprecated
- Deprecated 指明被注解的方法为过时的方法,不建议使用了。能用于方法之上。
当编译调用到被标注为Deprecated的方法的类时,编译器会产生警告。
举例如下:
public class InternalAnnotationTest {
…
@Deprecated
public void test(){
System.out.println("[Deprecated Annotation]");
}
}
2.3 内置注解类型—SuppressWarnings
- SuppressWarnings 指明被注解的方法在编译时如果有警告信息,就阻止警告。可放置任何位置。
- 它有一个必需属性:value,是String[]类型的,指定取消显示的警告集。警告类型如下:
类型 | 作用 |
---|---|
unused | 未被使用的警告 |
deprecation | 使用了不赞成使用的类或方法时的警告 |
unchecked | 执行了未检查的转换时的警告 |
rawtypes | 没有用泛型 (Generics) 的警告 |
fallthrough | 当 Switch 程序块直接通往下一种情况而没有 Break 时的警告。 |
path | 在类路径、源文件路径等中有不存在的路径时的警告。 |
serial | 当在可序列化的类上缺少 serialVersionUID 定义时的警告。 |
finally | 任何 finally 子句不能正常完成时的警告。 |
all | 关于以上所有情况的警告。 |
举例如下:
public class InternalAnnotationTest {
@SuppressWarnings(value={"unchecked", "deprecation"})
public void test() {
Map map = new HashMap();
map.put("name", "Alex");
System.out.println(map);
}
}
3、自定义注解类型
格式如下:
[访问修饰符] @interface 注解类型名 {
数据类型 属性名() [default 默认值];//定义属性
}
举例如下:
public @interface AlexDebug{
}
public @interface AlexAnnotation{
String value();
}
public @interfacle AlexType{
int age() default 18;
}
4、元注解
元注解:对注解的注解
- 为注解类型提供某种元数据,使用系统预定义的元注解可以对我们的注解进行注解。
结合元注解,我们可以对自定义注解类型进行相当大程度的内容补充说明。
Java的API为我们提供的元注解如下:
4.1 @Target
指定此注解的适用时机
- 在定义注解类型时,使用java.lang.annotation.Target可以定义其适用的时机。
在定义时要指定为java.lang.annation.ElementType的枚举值之一:
package java.lang.annotation;
public enum ElementType{
TYPE, //适用于 类,接口,枚举
FIELD, //适用于 成员字段
METHOD, //适用于 方法
PARAMETER, //适用于 方法的参数
CONSTRUCTOR, //适用于 构造方法
LOCAL_VARIABLE, //适用于 局部变量
ANNOTATION_TYPE, //适用于 注解类型
PACKAGE //适用于 包
}
举例如下:
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
//声明注解适用于方法
@Target({ElementType.METHOD})
public @interface AlexAnnotation {
}
4.2 @Retention
- 使用java.lang.annotation.Retention用来告诉编译器如何处理当前注解。
在使用Retention类型时,需要提供java.lang.annotation.RetentionPolicy的枚举类型,它的定义如下:
package java.lang.annotation;
public enum RetentionPolicy {
SOURCE, //编译器处理完后,并不将它保留到编译后的类文件中
CLASS, //编译器将注解保留在编译后的类文件中,但是在运行时忽略它
RUNTIME //编译器将注解保留在编译后的类文件中,并在第一次加载类时读取它
}
内置注解中的Override、SuppressWarnings的RetentionPolicy为SOURCE,而Deprecated为RUNTIME
4.3 @Documented
- 在默认情况下,注解不包括在Javadoc 中,用java.lang.annatation.Documented可以使此注解加入到Javadoc中。
- 定义为Documented的注解必须要设置Retention的值为RetentionPolicy.RUNTIME。
举例如下:
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface DocAnnotation {
}
4.5 @Inherited
- 定义的注解类型使用于程序代码上后,默认父类中的注解并不会继承至子类中。
如果想让父类中的注解被继承到子类中,可以在定义注解类型时加上java.lang.annotation.Inherited类型的注解。
举例如下:
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface Alex{
String name();
int value();
}
@Alex(name="John Snow",age=32)
public class Parent{}
class SubClass extends Parent{}
4.6 @Repeatable
- 意味着注解的值可以同时取多个
@Repeatable是Java1.8加进来的新注解,同样这里我们举个例子:
@interface Persons {
Person[] value();
}
@Repeatable(Persons.class)
@interface HumanBeing{
String role default "coder";
}
@Person(role="PM")
@Person(role="Teacher")
@Person(role="Reader")
public class Alex{
}
三、结语
1、一个技术开发人员老去的标志,绝不是老成稳重、沉默寡言,而是不肯再尝试,不肯再容许自己置身不熟悉的境地。
2、一个技术开发人员开始废掉的迹象之二,便是沉溺于短期快感之中,不再做长期投入。不再深入研究底层内容。在这里,我对注解相关的知识体系进行梳理,后续会推出更多的内容和大家分享。
3、一个技术开发人员开始废掉的迹象之三,是沦为抵触的情绪的奴隶。遇到新技术畏手畏脚,遇困难而退缩。
希望我们一起努力,加油!