注解概述
注解即Annotation是JDK5.0开始引入的新技术。
作用:
- 注解不是程序本身,但是可以对程序作出解释。这一点的功能类似于注释(comment)。
- 注解可以被其他程序读取,如编译器。
格式: 注解 是以 “@注释名” 的形式在程序中存在的,还可以添加一些参数。例如:@SuppressWarnings(value=“unchecked”)。
使用范围:
注解可以附加在package、class、method、field等上面,这相当于给他们添加了额外的辅助信息。我们可以通过反射机制编程实现对这些元数据的访问。
分类:
- 内置注解
- 元注解
- 自定义注解
内置注解
内置注解是注解的一种。我们遇到的 @Override、@Deprecated、@SuppressWarnings 都是内置注解。
当我们在进行方法的重写的时候,会遇到方法的上一行是 “@Override”,@Override 就是一个内置注解,它是定义在java.lang.Override中的,该注解只适用于修饰方法,表明一个方法声明打算重写超类(父类)的另一个方法声明。
在调用一个类的方法时,有时会遇到"@Deprecated",@Deprecated是定义java.lang.Deprecated 中的,该注解可以用于修饰方法、属性、类,表示不鼓励程序员使用这样的元素,通常是因为它很危险或者存在更好的选择。对于由"@Deprecated"修饰的元素,java中是不建议使用的,但是是可以使用的。
@SuppressWarnings,定义在java.lang.SuppressWarnings中,用于一直编译时的警告信息。但与上面的注解不同的是,需要添加一个参数才可以正确使用该注解,这些参数是java定义好的,我们只要选择性地去使用就行。如下:
@SuppressWarnings("all")
@SuppressWarnings("unchecked")
@SuppressWarnings(value={"unchecked","deprecation"})
元注解
元注解是注解的一个分类,它的作用是负责注解其他注解,java中定义了四个标准的meta-annotation类型,它们被用来提供对其他annotation类型作说明。
这些类型和它们所支持的类在java.lang.annotation包中可以找到。
分类:
- @Target:用于描述注解的使用范围即被描述的注解可以用在什么地方。
- @Retention:表示需要在什么级别保存该注解信息,用于描述注解的生命周期。
- @Documented:说明该注解将被包含在javadoc中。
- @Inherited:说明子类可以继承父类中的该注解。
@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();
}
ElementType源码:
public enum ElementType {
/** Class, interface (including annotation type), or enum declaration */
TYPE,
/** Field declaration (includes enum constants) */
FIELD,
/** Method declaration */
METHOD,
/** Formal parameter declaration */
PARAMETER,
/** Constructor declaration */
CONSTRUCTOR,
/** Local variable declaration */
LOCAL_VARIABLE,
/** Annotation type declaration */
ANNOTATION_TYPE,
/** Package declaration */
PACKAGE,
/**
* Type parameter declaration
*
* @since 1.8
*/
TYPE_PARAMETER,
/**
* Use of a type
*
* @since 1.8
*/
TYPE_USE
}
根据源码可以知道,@Target注解的使用范围:
名称 | 使用范围 |
---|---|
TYPE | 类,接口(包括注解类型)以及枚举 |
FIELD | 字段(包括枚举常量) |
METHOD | 方法 |
PARAMETER | 参数 |
CONSTRUCTOR | 构造方法 |
LOCAL_VARIABLE | 局部变量 |
ANNOTATION_TYPE | 注解类型 |
PACKAGE | 包 |
TYPE_PARAMETER(JDK1.8开始) | 类型参数 |
TYPE_USE(JDK1.8开始) | 类型的使用 |
@Retention
@Retention:表示需要在什么级别保存该注解信息,用于描述注解的生命周期。
@Retention源码:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
/**
* Returns the retention policy.
* @return the retention policy
*/
RetentionPolicy value();
}
RetentionPolicy源码:
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.
*
* @see java.lang.reflect.AnnotatedElement
*/
RUNTIME
}
根据源码可以知道 @Retention使用的生命周期有三个:
- SOURCE:注解将被编译器丢弃
- CLASS:注解由编译器记录在类文件中,但虚拟机在运行时无需保留。 这是默认行为。
- RUNTIME:注解由编译器记录在类文件中,并在运行时由VM保留,因此可以通过反射方式读取它们。
上面的三个生命周期是 SOURCE < CLASS < RUNTIME.
@Documented
@Documented:说明该注解将被包含在javadoc中。
@Documented 源码:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Documented {
}
@Inherited
@Inherited:说明子类可以继承父类中的该注解。
@Inherited源码:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Inherited {
}
自定义注解
除了java给我们提供的内置注解之外,我们还可以自己定义注解,即自定义注解。
格式:
public @interface 注解名 {
定义内容
}
在使用 @interface 自定义注解时,会自动继承java.lang.annotation.Annotation接口。
分析:
- @interface 用来声明一个注解
- 定义的注解中的每一个方法实际上是声明了一个配置参数
- 方法的名称就是参数的名称
- 返回值类型就是参数的类型,返回值类型只能是基本类型、Class、String、enum
- 可以通过default来声明参数的默认值
- 如果只有一个参数成员,一般参数名为value
- 注解元素必须要有值,在定义注解元素时,经常食用空字符串、0作为默认值。
自定义注解举例:
public class Test01 {
public static void main(String[] args) {
test();
}
@MyAnnotation("ll")
public static void test(){
System.out.println("This is my annotation");
}
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation{
String value(); // 只有一个参数成员时,一般参数名为value
}
上述例子中,自定义注解的参数只有一个,所以将参数名命名为value,且在写 @MyAnnotation(“ll”) 注解的时候,可以将参数名省去即将"value="省略不写,但是当注解中的参数大于等于两个时,就必须加上参数名。如下:
public class Test01 {
public static void main(String[] args) {
test();
}
@MyAnnotation(value = "ll",num = 1)
public static void test(){
System.out.println("This is my annotation");
}
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation{
String value();
int num();
}
自定义注解中,默认值的使用:
public class Test01 {
public static void main(String[] args) {
test();
}
@MyAnnotation(value = "ll")
public static void test(){
System.out.println("This is my annotation");
}
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation{
String value();
int num() default 0;
}
当参数有默认值的时候,在写注解时该参数可以传递参数也可以不传递参数。