浅谈Java中的注解

注解概述

注解即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;
}

当参数有默认值的时候,在写注解时该参数可以传递参数也可以不传递参数。

发布了44 篇原创文章 · 获赞 7 · 访问量 2443

猜你喜欢

转载自blog.csdn.net/Adelagirl/article/details/103490443