注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。
它作用于程序元素(类、字段、方法、局部变量、方法参数等)的上面,用于一些工具在编译、运行时进行解析和使用,起到说明、配置的功能。
注释:用来解释说明,是给程序员看的
注解:用来解释说明,是给程序看的
生成文档这是最常见的,也是java最早提供的注解,常用的有@param
,@return
等
在编译时进行格式检查,如@Override
放在方法上,如果这个方法并不是覆盖了超类方法,则编译时就能检查出
跟踪代码依赖性,实现替代配置文件功能,比较常见的是spring2.5
开始的基于注解配置,作用就是减少配置
在反射的Class,Method,Field等类的实例函数中,有许多于 Annotation 相关的接口,可以在反射中解析并使用 Annotation。
将注解写在类,方法,成员变量的上面即可
如果注解有成员(无默认值),那么在使用的时候必须在注解名后指明成员的值
如果一个注解中有多个属性的时候,我们在使用注解的时候,要给所有的属性附上值,之间用逗号分隔。
@MyAnnotation(name="lucy",age=12)
在注解中,有一个非常特别的属性名,叫做value
,如果一个注解中,只有一个属性,而且这个属性的名字叫做value
的话,那我们在使用注解的时候,就可以不写该属性的名字,例如@Annotation("val")
@AnnotationName
public void show() {}
@AnnotationName
int i;
@AnnotationName
class user {
public void show() {}
}
JDK定义好的注解,常用的有:
@Override
:检测该方法是否是重写的方法,如果发现父类、实现的接口中未定义该方法,会在编译器报错@Deprecated
:标记过期的方法和类,如果调用了此方法和类,会有编译警告@SuppressWarnings
:指示编译器在编译时忽略声明的警告,以下为value常用可选值
deprecation
:使用过期方法、类警告unchecked
:执行了未进行检查的转换时的警告,如集合未使用泛型fallthrough
:Swith代码块未使用break的警告path
:类路径、源文件路径不存在的警告serial
:在可序列化类上缺少serialVersionUID
定义的警告finally
:任何finally子句不能正常完成时的警告all
:所有警告@FunctionalInterface
:Java8支持,检测接口是否是一个函数式接口,如果不是(接口中没有抽象方法,抽象方法的个数多于一个)则编译失败注解只有属性(抽象方法),没有方法体
public @interface 注解名{
public String 属性名();
public String 属性名() default 默认值;
//由于注解的本质是接口,所以权限修饰符可以省略,默认是public
String 属性名() default 默认值;
}
public interface MyAnnotation1 extends java.lang.annotation.Annotation {}
通过反编译可以了解到,注解的本质是默认继承java.lang.annotation.Annotation
接口的接口
由于注解本质就是接口,所以在接口可以定义抽象方法,在接口中叫抽象方法,在注解中就叫做属性
在注解中,属性类型(抽象方法的返回值类型)可以写以下几种数据类型:
用来标记注解的注解
标识这个注解怎么保存,是只在代码中,还是编入.class
文件中,或者是在运行时可以通过反射访问。
value枚举如下
package java.lang.annotation;
public enum RetentionPolicy {
//Annotation信息仅存在于编译器处理期间,编译器处理完之后就没有该Annotation信息了
SOURCE,
//编译器将Annotation存储于类对应的.class文件中。默认行为
CLASS,
//编译器将Annotation存储于class文件中,在执行的时也加载到Java的JVM中,因此可以反射性的读取
RUNTIME
}
指定注解用于修饰哪些程序元素
value枚举如下
package java.lang.annotation;
public enum ElementType {
TYPE, //类、接口(包括注释类型)或枚举声明
FIELD, //字段声明(包括枚举常量)
METHOD, //方法声明
PARAMETER, //参数声明
CONSTRUCTOR, //构造方法声明
LOCAL_VARIABLE, //局部变量声明
ANNOTATION_TYPE, //注释类型声明
PACKAGE //包声明
}
pacakge-info.java
是一个 Java 文件,目标是提供一个包级的文档说明及包级的注释。在 Java 5 之前,包级的文档是package.html
,是通过 JavaDoc 生成的。而在 Java 5 之后版本,包的描述以及相关的文档都可以写入pacakge-info.java
文件。
/**
* 包级别注释测试
*
* @author ygang
* @since 1.0.0-RELEASE
* @version 2.0.0-RELEASE
*/
package top.ygang;
使用javadoc
命令生成文档
javadoc -encoding UTF-8 -charset UTF-8 top.ygang
@Target(ElementType.PACKAGE)
public @interface MyAnnotation{}
// 在package-info.java中使用
@MyAnnotation
package top.ygang;
package-info.java
中只能声明 default
默认访问权限的类,只能包内访问,其它包、子包都不可访问。
package top.ygang;
class Constant {
static final String VALUE = "Test";
}
生成文档信息的时候保留注解,对类作辅助说明
如果注解类型声明中存在@Inherited
元注解,则注解所修饰类的所有子类都将会继承此注解。
用来标注一个注解在同一个地方可重复使用的一个注解
就是指使用反射技术,获取注解的属性值。
注意:如果想要使用反射来解析注解,前提条件,该注解一定要有元注解@Retention
,而且其值一定要为RetentionPolicy.RUNTIME
,否则属性不进JVM内存,会有空指针异常
getAnnotation(Class<A> annatationClass)
:取得该元素指定类型的注解Annotation[] getAnnotations()
:返回此元素上存在的所有注解的数组,包括从父类继承的Annotation[] getDeclaredAnnotations()
:返回直接存在于此元素上的所有注解的数组,不包括父类的注解boolean isAnnotation()
:判断元素是否是一个注解boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)
:判断元素是否存在指定类型的注解//获取运行时类的Class对象
Class cls = 带有注解的类的类名.getClass();
//判断是否有注解
if(cls.isAnnotationPresent(注解.class)){
//获取注解对象
注解 a = (注解)cls.getAnnotation(注解.class);
//获取属性值
a.属性名();
}
//获取运行时类的Class对象
Class cls = 带有注解的类的类名.getClass();
Method m = cls.getMethod("方法名");
//判断是否有注解
if(m.isAnnotationPresent(注解.class)){
//获取注解对象
注解 a = (注解)m.getAnnotation(注解.class);
//获取属性值
a.属性名();
}