文章目录

  • 注解
  • 1.引言
  • 2.分类
  • 3.标准注解
  • 4.元注解
  • 4.1注解基本格式
  • 4.2Documented
  • 4.3Retention
  • 4.4Target
  • 4.5lnherited
  • 5.自定义注解


注解

1.引言

注解是java在1.5版本后引入的一种概念,是一个非常重要的知识点,相信很多人学到这的时候都是一脸懵逼。别急,听我慢慢分析。

我们可以把注解理解成一种标签,注解能够存在的地方很多,比如在类上面,方法上【Override】,甚至在注解上也可以存在注解。那么注解有什么用呢?

首先,注解可以编译检查代码,比如@FunctionInterface开启函数式接口检查,@Override重写检查,这两个还是比较常见的,然而注解的功能远不这些,接着往下看。

2.分类

java注解可以简单分为三类:

标准注解:
	@Override	@FunctionalInterface	@SuppressWarnings
元注解:
	@Documented
	@Retention
	@Target
	@Inherited
自定义注解

其中标准注解还是很常见的,我们先介绍一下这个。

3.标准注解

此类注解都是java定义好的注解,一般用于开始代码编译检查,例如:

@Override

开启重写检查。如果试图用@Override标记一个没有重写父类方法的方法,编译器会报警。

@FunctionalInterface

这个同理,开启函数式接口严格检查。

4.元注解

4.1注解基本格式

看元注解之前,我们先来看一下,注解的基本格式:

public @Interface AnnotationName{
    //属性
    //建议,属性必须有一个value属性,属性对应的数据类型不限制
}

例如: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();
}

可以看到,注解和接口的声明格式很像,直接使用@Interface修饰,至于为什么建议必须有一个value呢,接下来将自定义注解我会讲到,还有在注解声明上面的注解就是元注解,那么元注解都有什么呢?

元注解是一种基本注解,它可以用到其他注解上,可以这样理解,它是一种特殊的标签,是对其他注解进行解释说明的。那么元注解最常用的有三种,我们分别来看看。

4.2Documented

@Documented

这个注解功能比较简单,就是标记当前注解参与Javadoc操作,可以生成对应的【JavaDoc文档】
4.3Retention

@Retention

该注解标记了当前注解在哪一级别可用。分别有代码编译阶段,生成.class文件阶段,代码运行阶段。这三个阶段对应了Retention的三个属性。

RetentionPolicy.SOURCE
	标记当前注解只存在代码中,编译时被丢弃,不存在类文件中
RetentionPolicy.CLASS
	标记当前注解在类文件中存在,但是不参与代码的运行。
RetentionPolicy.RUNTIME
	标记当前代码不仅在类文件中存在,而且参与代码的运行。我们可以通过反射的方式获取对应的注解信息。
4.4Target

@target

决定当前注解可以作用于java代码中的哪一部分内容,通过枚举ElementedType来决定当期注解可以使用范围。

  • ElementType.TYPE:表示注解可以用于类、接口、枚举
  • ElementType.FIELD:表示注解可以用于成员变量
  • ElementType.METHOD:表示注解可以用于方法
  • ElementType.PARAMTER:表示注解可以用于参数
  • ElementType.CONSTRUCTOR:表示注解可以用于构造器
  • ElementType.ANNOTATION_TYPE:表示注解可以用于注解
  • ElementType.LOCAL_VARIABLE:表示注解可以用于局部变量
  • ElementType.PACKAGE:表示注解可以用于包
例如,上面的@Target注解源码,上面@Target(ElementType.ANNOTATION_TYPE)
就是标记当前注解可以用于注解之上。
4.5lnherited

@lnherited

标记这个注解是继承于哪个注解类(默认 注解并没有继承于任何子类)

这个注解不是很常用,所以在此就不详细介绍了。

5.自定义注解

java的骚操作之一。

//自定义注解的格式
 public @interface 注解名{
     //注解内容,属性
 }

实际代码演示:

//可以生成JavaDOC文档
@Documented	
//参与到程序的运行
@Retention(RetentionPolicy.RUNTIME)	
//当前注解可以用在类、接口、枚举之上
@Target(ElementType.TYPE)
public @interface Annotation {
    //注解中如果用到了属性,属性列表中必须有一个value反馈类型任意
    
    /**
     * 当前注解名为value
     *
     * @return 反馈类型是String
     */
    String value() default "";

    /**
     * 当前注解名为num
     *
     * @return 反馈类型是int
     */
    int num();
}

注解里支持的类型有很多,上面只列举了基本类型和String。它支持所有的基本类型枚举,注解,还有以上所有类型的数组。

注解里使用枚举

先定义一个枚举类型,里面定义周一到周末

//枚举类型,使用关键字enum,定义周一到周末,用逗号隔开
enum Day {
    MONDAY, 
    TUESDAY,
    WEDNESDAY,
    THURSDAY,
    FRIDAY,
    SATURDAY,
    SUNDAY
}

注解里面加入其他注解

再定义一个注解

public @interface MyAnnotation {
    int  value() default 0;
    String name() default "";
}

将枚举类型和自定义注解@MyAnnotation添加进自定义注解@Annotation

public @interface Annotation {
    //注解中如果用到了属性,属性列表中必须有一个value反馈类型任意

    /**
     * 当前注解名为value
     *
     * @return 反馈类型是String
     */
    String value() default "";

    /**
     * 当前注解名为num
     *
     * @return 反馈类型是int
     */
    int num();

    /**
     * 获取日期
     *
     * @return 反馈类型是枚举
     */
    Day getDay();

    /**
     * 获取自定义注解的值
     * 
     * @return  反馈类型是在自定义注解
     */
    MyAnnotation[] ANNOTATIONS();
}

接下来测试,用反射的方法获取注解属性。

@Annotation(value = "注解",
        num = 22,
        getDay = Day.SATURDAY,
        ANNOTATIONS = {
                @MyAnnotation(value = 1, name = "李星云"),
                @MyAnnotation(value = 2, name = "不良帅")
        }
)
public class Demo {
    public static void main(String[] args) {
        //获取类对象
        Class<Demo> cls = Demo.class;

        //获取注解对象
        Annotation annotation = cls.getAnnotation(Annotation.class);
        
        //获取注解中的属性
        System.out.println(annotation.num());

        //获取注解中的注解属性
        System.out.println(annotation.ANNOTATIONS()[0].name());
        System.out.println(annotation.ANNOTATIONS()[1].name());
    }
}

注解的属性赋值就是属性名 = 具体值,注解中的属性有一句话总结它的特性,我觉得很不错,最后分享给各位:

以方法之式,行变量之实,实则为方法。
	怎么理解呢,我们可以看出来属性定义的时候,都带有小括号(),是方法的形式,
	但是在上面赋值的时候,跟变量的赋值是一样的。很有意思,但是实际上还是方法。