Java 注解(Annotation)

Java 注解(Annotation)又称 Java 标注,是 JDK5.0 引入的一种注释机制。

Java 语言中的类、方法、变量、参数和包等都可以被标注。和 Javadoc 不同,Java 标注可以通过反射获取标注内容。在编译器生成类文件时,标注可以被嵌入到字节码中。Java 虚拟机可以保留标注内容,在运行时可以获取到标注内容 。 当然它也支持自定义 Java 标注。

一、内置注解说明

Java 在 JDK5.0定义了一套注解,共有 7 个,3 个在 java.lang 中,4 个在 java.lang.annotation 中,在 JDK7.0开始,添加了 3 个注解。

1.1 作用在代码的注解

  • @Override - 检查该方法是否是重写方法。如果发现其父类,或者是引用的接口中并没有该方法时,会报编译错误。
  • @Deprecated - 标记过时方法。如果使用该方法,会报编译警告。
  • @SuppressWarnings - 指示编译器去忽略注解中声明的警告。

1.2 作用在其他注解的注解(元注解)

  • @Retention - 标识这个注解怎么保存,是只在代码中,还是编入class文件中,或者是在运行时可以通过反射访问。
  • @Documented - 标记这些注解是否包含在用户文档中。
  • @Target - 标记这个注解应该是哪种 Java 成员。
  • @Inherited - 标记这个注解是继承于哪个注解类(默认 注解并没有继承于任何子类)

1.3 新增注解

从 Java 7 开始,额外添加了 3 个注解:

  • @SafeVarargs - Java 7 开始支持,忽略任何使用参数为泛型变量的方法或构造函数调用产生的警告。
  • @FunctionalInterface - Java 8 开始支持,标识一个匿名函数或函数式接口。
  • @Repeatable - Java 8 开始支持,标识某注解可以在同一个声明上使用多次。

二、Annotation 架构

目录:java\lang\annotation\Annotation.java

 

 

 

 

 

 

其中:

  • 1 个 Annotation 和 1 个 RetentionPolicy 关联。

​ 每1个Annotation对象,都会有唯一的RetentionPolicy属性。

  • 1 个 Annotation 和 1~n 个 ElementType 关联

​ 对于每 1 个 Annotation 对象,可以有若干个 ElementType 属性。

  • Annotation 有许多实现类,包括:Override ,SuppressWarnings,Deprecated, Documented, Inherited等等

​ Annotation 的每一个实现类,都 "和 1 个 RetentionPolicy 关联" 并且 " 和 1~n 个 ElementType 关联"。

例如Deprecated注解

 

 

 

三、Annotation 组成部分

java Annotation 的组成中,有 3 个非常重要的主干类。它们分别是:

3.1 Annotation.java

package java.lang.annotation;
public interface Annotation {

    boolean equals(Object obj);

    int hashCode();

    String toString();

    Class<? extends Annotation> annotationType();
}

3.2 ElementType.java

package java.lang.annotation;
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
}

3.3 RetentionPolicy.java

package java.lang.annotation;

public enum RetentionPolicy {
    /**
     * Annotations are to be discarded by the compiler.Annotation信息仅存在于编译器处理期间,编译器处理完之后就没有该Annotation信息了
     */
    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.编译器将Annotation存储于类对应的.class文件中。默认行为
     */
    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.
     * 编译器将Annotation存储于class文件中,并且可由JVM读入
     * @see java.lang.reflect.AnnotatedElement
     */
    RUNTIME
}

其中

  • Annotation 是个接口

"每1个Annotation" 都与 "1个 RetentionPolicy" 关联,并且与 "1~n 个 ElementType" 关联。可以通俗的 理解为:每1个 Annotation 对象,都会有唯一的 RetentionPolicy 属性; 有 1~n 个ElementType 属性。

  • ElementType 是 Enum 枚举类型,它用来指定 Annotation 的类型

"每1个 Annotation" 都与 "1~n 个 ElementType" 关联。当 Annotation 与某个 ElementType 关联时,就意味着:Annotation有了某种用途。例如,若一个 Annotation 对象是 METHOD 类型,则该 Annotation 只能用来修饰方法。

  • RetentionPolicy 是 Enum 枚举类型,它用来指定 Annotation 的策略。通俗点说,就是不同 RetentionPolicy 类型的 Annotation 的作用域不同

"每1个 Annotation" 与 "1个 RetentionPolicy" 关联。

(1)若 Annotation 的类型为 SOURCE,则意味着:Annotation 仅存在于编译器处理期间,编译器处理完之后,该 Annotation 就没用了。 例如," @Override" 标志就是一个 Annotation。当它修饰一个方法的时候,就意味着该方法覆盖父类的方法;并且在编译期间会进行语法检查!编译器处理完后,"@Override" 就没有任何作用了。
(2)若 Annotation 的类型为 CLASS,则意味着:编译器将 Annotation 存储于类对应的 .class 文件中,它是 Annotation 的默认行为。
(3)若 Annotation 的类型为 RUNTIME,则意味着:编译器将 Annotation 存储于 class 文件中,并且可由JVM读入。

我们只需要记住"每1个Annotation" 都与 "1个RetentionPolicy" 关联,并且与 "1~n 个ElementType" 关联即可。

四、Java自带的 Annotation

理解了上面的 3 个类的作用之后,我们接下来可以讲解 Annotation 实现类的语法定义了。

4.1 Annotation 通用定义

@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation1 {
}

说明:

上面的作用是定义一个 Annotation,它的名字是 MyAnnotation1。定义了 MyAnnotation1 之后,我们可以在代码中通过 "@MyAnnotation1" 来使用它。 其它的,@Documented, @Target, @Retention, @interface 都是来修饰 MyAnnotation1 的。下面分别说说它们的含义:

@interface

使用 @interface 定义注解时,意味着它实现了 java.lang.annotation.Annotation 接口,即该注解就是一个Annotation。

定义 Annotation 时,@interface 是必须的。

注意:它和我们通常的 implemented 实现接口的方法不同。Annotation 接口的实现细节都由编译器完成。通过 @interface 定义注解后,该注解不能继承其他的注解或接口。

@Documented

类和方法的 Annotation 在缺省情况下是不出现在 javadoc 中的。如果使用 @Documented 修饰该 Annotation,则表示它可以出现在 javadoc 中。

定义 Annotation 时,@Documented 可有可无;若没有定义,则 Annotation 不会出现在 javadoc 中。

@Target(ElementType.TYPE)

前面我们说过,ElementType 是 Annotation 的类型属性。而 @Target 的作用,就是来指定 Annotation 的类型属性。

@Target(ElementType.TYPE) 的意思就是指定该 Annotation 的类型是 ElementType.TYPE。这就意味着,MyAnnotation1 是来修饰"类、接口(包括注释类型)或枚举声明"的注解。

定义 Annotation 时,@Target 可有可无。若有 @Target,则该 Annotation 只能用于它所指定的地方;若没有 @Target,则该 Annotation 可以用于任何地方。

@Retention(RetentionPolicy.RUNTIME)

前面我们说过,RetentionPolicy 是 Annotation 的策略属性,而 @Retention 的作用,就是指定 Annotation 的策略属性。

@Retention(RetentionPolicy.RUNTIME) 的意思就是指定该 Annotation 的策略是 RetentionPolicy.RUNTIME。这就意味着,编译器会将该 Annotation 信息保留在 .class 文件中,并且能被虚拟机读取。

定义 Annotation 时,@Retention 可有可无。若没有 @Retention,则默认是 RetentionPolicy.CLASS。

4.2 Java定义的Annotation

通过上面的示例,我们能理解:@interface 用来声明 Annotation,@Documented 用来表示该 Annotation 是否会出现在 javadoc 中, @Target 用来指定 Annotation 的类型,@Retention 用来指定 Annotation 的策略。

理解这一点之后,我们就很容易理解 java 中自带的 Annotation 的实现类,如Deprecated、Override、Documented等等。

Java 常用的 Annotation:

@Deprecated  -- @Deprecated 所标注内容,不再被建议使用。
@Override    -- @Override 只能标注方法,表示该方法覆盖父类中的方法。
@Documented  -- @Documented 所标注内容,可以出现在javadoc中。
@Inherited   -- @Inherited只能被用来标注“Annotation类型”,它所标注的Annotation具有继承性。
@Retention   -- @Retention只能被用来标注“Annotation类型”,而且它被用来指定Annotation的RetentionPolicy属性。
@Target      -- @Target只能被用来标注“Annotation类型”,而且它被用来指定Annotation的ElementType属性。
@SuppressWarnings -- @SuppressWarnings 所标注内容产生的警告,编译器会对这些警告保持静默。

由于 "@Deprecated 和 @Override" 类似,"@Documented, @Inherited, @Retention, @Target" 类似;下面,我们只对 @Deprecated, @Inherited, @SuppressWarnings 这 3 个 Annotation 进行说明。

4.2.1 @Deprecated

@Deprecated 的定义如下:

package java.lang;

import java.lang.annotation.*;
import static java.lang.annotation.ElementType.*;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
public @interface Deprecated {
}

说明:

  • @interface -- 它的用来修饰 Deprecated,意味着 Deprecated 实现了 java.lang.annotation.Annotation 接口;即 Deprecated 就是一个注解。
  • @Documented -- 它的作用是说明该注解能出现在 javadoc 中。
  • @Retention(RetentionPolicy.RUNTIME) -- 它的作用是指定 Deprecated 的策略是 RetentionPolicy.RUNTIME。这就意味着,编译器会将Deprecated 的信息保留在 .class 文件中,并且能被虚拟机读取。
  • @Deprecated 所标注内容,不再被建议使用。

例如,若某个方法被 @Deprecated 标注,则该方法不再被建议使用。如果有开发人员试图使用或重写被 @Deprecated 标示的方法,编译器会给相应的提示信息。示例如下:

package com.joshua317;

public class Main {

    public static void main(String[] args) {
        new DeprecatedTest().fun1();
    }
}

class DeprecatedTest {
    @Deprecated
    public void fun1()
    {
        System.out.println("Deprecated fun1");
    }
    public void fun2()
    {
        System.out.println("Not Deprecated fun2");
    }
}

 

 

 

说明:

fun1() 被 @Deprecated 标注,意味着建议不再使用 fun1(); 所以 fun1() 调用时,都会一横线。这一横线是对 @Deprecated 方法的处理。

fun2() 没有被 @Deprecated 标注,它的显示正常。

4.2.3 @Override

@Override的定义如下:

package java.lang;

import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}

说明:

  • @interface -- 它的用来修饰 Override,意味着 Override实现了 java.lang.annotation.Annotation 接口;即 Override就是一个注解。
  • @Target(ElementType.METHOD) -- 它的作用是指定 Override的类型是 METHOD。这就意味着,@Override 只能被用来标注方法。
  • @Retention(RetentionPolicy.SOURCE) -- 它的作用是指定 Override的策略是 RetentionPolicy.SOURCE。这就意味着,编译器会将Override的信息保留在 .class 文件中,并且能被虚拟机读取。
  • @Override所标注内容,会检查该方法是否是重写方法。如果发现其父类,或者是引用的接口中并没有该方法时,会报编译错误。

例如,若某个方法被 @Override标注,则会检查该方法是否是重写方法。示例如下:

package com.joshua317;

public class Main {

    public static void main(String[] args) {
        new OverrideTest().fun1();
    }
}

class OverrideTest implements OverrideInterface{
    @Override
    public void fun1()
    {
        System.out.println("Override fun1");
    }
    public void fun2()
    {
        System.out.println("Not Override fun2");
    }
}
interface OverrideInterface {
    public void fun1();
}

 

 

 

说明:

如果不加@Override,则会提示MIss'@Override' annotation on 'fun1'

4.2.3 @Inherited

@Inherited 的定义如下:

package java.lang.annotation;

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Inherited {
}

说明:

  • @interface -- 它的用来修饰 Inherited,意味着 Inherited 实现了 java.lang.annotation.Annotation 接口;即 Inherited 就是一个注解。
  • @Documented -- 它的作用是说明该注解能出现在 javadoc 中。
  • @Retention(RetentionPolicy.RUNTIME) -- 它的作用是指定 Inherited 的策略是 RetentionPolicy.RUNTIME。这就意味着,编译器会将 Inherited 的信息保留在 .class 文件中,并且能被虚拟机读取。
  • @Target(ElementType.ANNOTATION_TYPE) -- 它的作用是指定 Inherited 的类型是 ANNOTATION_TYPE。这就意味着,@Inherited 只能被用来标注 "Annotation 类型"。
  • @Inherited 的含义是,它所标注的Annotation将具有继承性。

假设,我们定义了某个 Annotaion,它的名称是 MyAnnotation,并且 MyAnnotation 被标注为 @Inherited。现在,某个类 Base 使用了MyAnnotation,则 MyAnnotationBase 具有了"具有了注解 MyAnnotation";现在,MyAnnotationSub 继承了 MyAnnotationBase,由于 MyAnnotation 是 @Inherited的(具有继承性),所以,MyAnnotationSub 也 "具有了注解 MyAnnotation"。

package com.joshua317;

import java.lang.annotation.*;

public class Main {

    public static void main(String[] args) {
        MyAnnotationSub myAnnotationSub = new MyAnnotationSub();
    }
}

/**
 * 自定义的Annotation。
 * @author joshua317
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@interface MyAnnotation
{
}

@MyAnnotation
class MyAnnotationBase
{
    public MyAnnotationBase() {
        // MyAnnotationBase是否具有 MyAnnotation Annotation
        System.out.println("MyAnnotationBase:"+MyAnnotationBase.class.isAnnotationPresent(MyAnnotation.class));
    }
}
/**
 * MyAnnotationSub 类只是继承于 MyAnnotationBase,
 */
class MyAnnotationSub extends MyAnnotationBase
{
    public MyAnnotationSub() {
        // 调用父类的构造函数
        super();
        // MyAnnotationSub 类是否具有 MyAnnotation Annotation
        System.out.println("MyAnnotationSub:"+MyAnnotationSub.class.isAnnotationPresent(MyAnnotation.class));
    }
}

 

 

 

现在我们注释掉 "MyAnnotation 的 @Inherited 注解"。

package com.joshua317;

import java.lang.annotation.*;

public class Main {

    public static void main(String[] args) {
        MyAnnotationSub myAnnotationSub = new MyAnnotationSub();
    }
}

/**
 * 自定义的Annotation。
 * @author joshua317
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
//@Inherited
@interface MyAnnotation
{
}

@MyAnnotation
class MyAnnotationBase
{
    public MyAnnotationBase() {
        // MyAnnotationBase是否具有 MyAnnotation Annotation
        System.out.println("MyAnnotationBase:"+MyAnnotationBase.class.isAnnotationPresent(MyAnnotation.class));
    }
}
/**
 * MyAnnotationSub 类只是继承于 MyAnnotationBase,
 */
class MyAnnotationSub extends MyAnnotationBase
{
    public MyAnnotationSub() {
        // 调用父类的构造函数
        super();
        // MyAnnotationSub 类是否具有 MyAnnotation Annotation
        System.out.println("MyAnnotationSub:"+MyAnnotationSub.class.isAnnotationPresent(MyAnnotation.class));
    }
}

 

 

 

可以发现,当注解 Inheritable 被 @Inherited 标注时,它具有继承性。否则,没有继承性。

4.2.4 @SuppressWarnings

@SuppressWarnings 的定义如下:

package java.lang;

import java.lang.annotation.*;
import static java.lang.annotation.ElementType.*;

@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
    String[] value();
}

说明:

  • @interface -- 它的用来修饰 SuppressWarnings,意味着 SuppressWarnings 实现了 java.lang.annotation.Annotation 接口;即 SuppressWarnings 就是一个注解。

  • @Retention(RetentionPolicy.SOURCE) -- 它的作用是指定 SuppressWarnings 的策略是 RetentionPolicy.SOURCE。这就意味着,SuppressWarnings 信息仅存在于编译器处理期间,编译器处理完之后 SuppressWarnings 就没有作用了。

  • @Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE}) -- 它的作用是指定 SuppressWarnings 的类型同时包括TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE。

    TYPE 意味着,它能标注"类、接口(包括注释类型)或枚举声明"。
    
    FIELD 意味着,它能标注"字段声明"。
    
    METHOD 意味着,它能标注"方法"。
    
    PARAMETER 意味着,它能标注"参数"。
    
    CONSTRUCTOR 意味着,它能标注"构造方法"。
    
    LOCAL_VARIABLE 意味着,它能标注"局部变量"。
    
  • String[] value(); 意味着,SuppressWarnings 能指定参数

  • SuppressWarnings 的作用是,让编译器对"它所标注的内容"的某些警告保持静默。例如,"@SuppressWarnings(value={"deprecation", "unchecked"})" 表示对"它所标注的内容"中的 "SuppressWarnings 不再建议使用警告"和"未检查的转换时的警告"保持沉默。示例如下:

package com.joshua317;
@SuppressWarnings("all")
public class Main {

    public static void main(String[] args) {
        new SuppressWarningsTest().fun2();
    }
}

class SuppressWarningsTest{
    public void fun1() {
        System.out.println("SuppressWarnings fun1");
    }
    @Deprecated
    public void fun2() {
        System.out.println("SuppressWarnings fun2");
    }

}

 

 

 

说明:

如果不加@SuppressWarnings,则会提示fun2 is Deprecated

@SuppressWarnings 常用的关键字:

参数作用原描述
all 抑制所有警告 to suppress all warnings
boxing 抑制装箱、拆箱操作时候的警告 to suppress warnings relative to boxing/unboxing operations
cast 抑制装箱、拆箱操作时候的警告 to suppress warnings relative to boxing/unboxing operations
cast 抑制映射相关的警告 to suppress warnings relative to cast operations
dep-ann 抑制启用注释的警告 to suppress warnings relative to deprecated annotation
deprecation 抑制过期方法警告 to suppress warnings relative to deprecation
fallthrough 抑制确在switch中缺失breaks的警告 to suppress warnings relative to missing breaks in switch statements
finally 抑制finally模块没有返回的警告 to suppress warnings relative to finally block that don’t return
hiding 抑制与隐藏变数的区域变数相关的警告 to suppress warnings relative to locals that hide variable()
incomplete-switch 忽略没有完整的switch语句 to suppress warnings relative to missing entries in a switch statement (enum case)
nls 忽略非nls格式的字符 to suppress warnings relative to non-nls string literals
null 忽略对null的操作 to suppress warnings relative to null analysis
rawtype 使用generics时忽略没有指定相应的类型 to suppress warnings relative to un-specific types when using generics on class params
restriction 抑制与使用不建议或禁止参照相关的警告 to suppress warnings relative to usage of discouraged or forbidden references
serial 忽略在serializable类中没有声明serialVersionUID变量 to suppress warnings relative to missing serialVersionUID field for a serializable class
static-access 抑制不正确的静态访问方式警告 to suppress warnings relative to incorrect static access
synthetic-access 抑制子类没有按最优方法访问内部类的警告 to suppress warnings relative to unoptimized access from inner classes
unchecked 抑制没有进行类型检查操作的警告 to suppress warnings relative to unchecked operations
unqualified-field-access 抑制没有权限访问的域的警告 to suppress warnings relative to field access unqualified
unused 抑制没被使用过的代码的警告 to suppress warnings relative to unused code

五、Annotation的作用

Annotation 是一个辅助类,它在 Junit、Struts、Spring 等工具框架中被广泛使用。

我们在编程中经常会使用到的 Annotation 作用有:

5.1 编译检查

Annotation 具有"让编译器进行编译检查的作用"。

例如,@SuppressWarnings, @Deprecated 和 @Override 都具有编译检查作用。

5.2 在反射中使用 Annotation

在反射的 Class, Method, Field 等函数中,有许多于 Annotation 相关的接口。

这也意味着,我们可以在反射中解析并使用 Annotation。

package com.joshua317;

import java.lang.annotation.*;
import java.lang.reflect.Method;

public class Main {

    public static void main(String[] args) throws Exception{
        // 新建Animal
        Animal animal = new Animal();
        // 获取Animal的Class实例
        Class<Animal> cAnimal = Animal.class;
        // 获取 getAnimal() 方法的Method实例
        Method mgetAnimal = cAnimal.getMethod("getAnimal", new Class[]{String.class, int.class});
        System.out.println("类的成员方法mgetAnimal:" + mgetAnimal);
        // 执行该方法
        mgetAnimal.invoke(animal, new Object[]{"狗狗", 2});
        iteratorAnnotations(mgetAnimal);

        // 获取 empty() 方法的Method实例
        Method mEmpty = cAnimal.getMethod("empty", new Class[]{});
        // 执行该方法
        mEmpty.invoke(animal, new Object[]{});
        iteratorAnnotations(mEmpty);
    }

    public static void iteratorAnnotations(Method method) {

        // 判断 getAnimal() 方法是否包含MyAnnotation注解
        if(method.isAnnotationPresent(MyAnnotation.class)){
            // 获取该方法的MyAnnotation注解实例
            MyAnnotation myAnnotation = method.getAnnotation(MyAnnotation.class);
            // 获取 myAnnotation的值,并打印出来
            String[] values = myAnnotation.value();
            for (String str:values) {
                System.out.printf(str+", ");
            }
            System.out.println();
        }

        // 获取方法上的所有注解,并打印出来
        Annotation[] annotations = method.getAnnotations();
        for(Annotation annotation : annotations){
            System.out.println(annotation);
        }
    }
}

/**
 *  自定义的Annotation。
 *  @author joshua317
 * Annotation在反射函数中的使用示例
 */
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation {
    String[] value() default "unknown";
}

/**
 * Animal类,它会使用MyAnnotation注解。
 */
class Animal {

    /**
     * empty()方法同时被 "@Deprecated" 和 "@MyAnnotation(value={"a","b"})"所标注
     * @Deprecated,意味着empty()方法,不再被建议使用
     * @MyAnnotation, 意味着empty() 方法对应的MyAnnotation的value值是默认值"unknown"
     */
    @MyAnnotation
    @Deprecated
    public void empty(){
        System.out.println("\nempty");
    }

    /**
     * getAnimal() 被 @MyAnnotation(value={"dog","cat"}) 所标注,
     * @MyAnnotation(value={"dog","cat"}), 意味着MyAnnotation的value值是{"dog","cat"}
     */
    @MyAnnotation(value={"dog","cat"})
    public void getAnimal(String name, int age){
        System.out.println("\ngetAnimal: "+name+", "+age);
    }
}

5.3 根据 Annotation 生成帮助文档

通过给 Annotation 注解加上 @Documented 标签,能使该 Annotation 标签出现在 javadoc 中。

5.4 能够帮忙查看查看代码

通过 @Override, @Deprecated 等,我们能很方便的了解程序的大致结构。

5.5 自定义 Annotation 来实现一些功能

通过自定义Annotation来满足我们的需求,比如springboot里面大量使用了注解。

 

 
posted @ 2021-12-18 00:00  joshua317  阅读(184)  评论(0编辑  收藏  举报