龙空技术网

Java 17 的注解 Annotation 基础使用篇

小沐学学学 242

前言:

如今朋友们对“java的annotation”可能比较讲究,你们都需要剖析一些“java的annotation”的相关知识。那么小编在网上网罗了一些有关“java的annotation””的相关资讯,希望小伙伴们能喜欢,同学们一起来学习一下吧!

Java 17 的注解 Annotation 基础使用篇思维导图Annotation 简短说明

对于注解 Annotation 是从 Java 1.5 开始加入,对于 Java 17 来说,主要是来自模块 java.base 下的包 java.lang.annotation。该包提供了 Java 编程语言注解的类库支持。

在没有注解之前, Java 中大量的使用了 XML 配置文件的方式, 比如 Java 之首的 Spring 框架, 在 3.0 之前,之后也保留了 xml 配置的方式, 来进行框架相关的配置。 这在项目越来越大的情况下配置文件越来越多,越繁杂,无疑对开发和使用都不是友好的,这个时候就引入了注解 Annotation。当然两者各有优点和缺点,具体的不再详述。

对于 Java 中的注解实现方式是基于源码实现, 对于使用注解和非注解的编程方式,编译的字节码都是一样的。

使用注解格式

注解的格式, 通常情况下使用 @ 符号开始, 后面跟上对应的注解名称,以及注解参数和对应的值。

@注解名称([{ 标识符 = 元素的值,           标识符 = {元素的值, 元素的值, 元素的值},          标识符 = Annotation       }])
定义注解格式
修饰符 @interface 注解名称{    [注解的方法参数]}

根据 jls 定义, 以及 API 的描述,对于注解的实现。通常分为三种,第一种是最通用的。其他的都是第一种的简写方式。

标准的注解( NormalAnnotation )举例: @TypeName(value=ElementValue)标记注解( MarkerAnnotation ) 举例:@TypeName单元素注解( SingleElementAnnotation ) 举例:@TypeName(ElementValue)Annotation 接口

在 Java 中,Annotation 接口是所有元注解接口扩展的通用接口。所有的注解都隐式的扩展自该接口。但是需要注意的,继承和实现该接口并不能实现定义注解接口。并且该接口并没有定义成一个注解接口。

public interface Annotation 

对于 java.lang.annotation 包中, 元注解接口有以下类:

这里的元注解就是专门用于定义注解的注解。

让我们查看其接口的实现类。查看 API 以及前面说 Date 时间类来说,有很多此注解接口。

Deprecated

例如:@Deprecated 此类标注类和方法是已经过期了,不推荐使用了。

让我们看一下该注解的定义:

@Documented@Retention(RetentionPolicy.RUNTIME)@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, MODULE, PARAMETER, TYPE})public @interface Deprecated

让我们把这些注解详细的说一下。

Documented

该注解是一个标注注解, 主要是为了进行 javadoc 生成代码的时候, 显示注解内容。

注解的定义:

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

编写个测试类:

import java.lang.annotation.Documented;/** * 测试 @Documented 注解 */@Documentedpublic @interface DocumentedTest {    /**     * 测试方法     */    void test();}

上面是包含注解类的。 一个不带注解类的。

使用 javadoc 编译 java 文档

javadoc -encoding utf-8 -d jc Test.java

查看编译的文档,先看带有 Documented 注解的。

在使用不包含该注解的进行测试。

javadoc -encoding utf-8 -d jc TestNo.java

根据你自己的代码规范和要求, 决定是否要加该注解。

Retention

接着来看 @Retention 注解接口,可以理解该接口的生命周期, 也就是在运行时保留该注解多少时间。

该注解接口定义为:

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

其中只有一个注解方法。

对于枚举类 RetentionPolicy 的定义

也就是说对于 Retention 注解的接口参数就三个,分别是: RetentionPolicy.CLASS,RetentionPolicy.RUNTIME 以及 RetentionPolicy.SOURCE。

如果注解接口不包含该注解,则默认的策略是:RetentionPolicy.CLASS

Target

对于 @Target 注解接口,是注解接口的上下文。

该注解的定义:

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

注解接口方法同样也是一个:

该类中同样有一个枚举类型 ElementType。该枚举类型包含了如下的枚举常量。

对于 ElementType 枚举类型,主要提供了 Java 程序中可能出现的注解的语法位置的简单分类,这些常量主要在 @Target 注解中使用,用来指定在代码的那个位置添加注解。根据 @Target 的定义,可以看到该值是数组,所以可以设置多个值,例如上面代码中的:@Target(ElementType.ANNOTATION_TYPE)

举个 Java 中的例子 @Override 其中他的定义是:

@Target(ElementType.METHOD)@Retention(RetentionPolicy.SOURCE)public @interface Override {}

根据上面的解释, 就很容易理解该注解, 该注解的注解位置是方法, 并且注解的生命周期也就是保留时间是源码,也就是只有在源码中存在。如果该注解注解到类上, 会有如下的错误信息。

Inherited

对于 @Inherited 注解接口,表示带有该注解的带有继承功能,如果在注解接口的声明中存在继承的元注解,并且用户在类声明上查询注解接口,而类声明没有针对该接口的注解,则该类的超类将自动查询该注解接口。此过程将向上重复进行, 知道找到此接口的注解,或者达到了类层次接口的顶部。如果没有超类具有此接口的注释,则查询将指示所讨论的类没有此类注解。

也就是说此类注解主要是为了让子类进行继承。

需要注意此注解只能用于类上, 而不能用于方法和属性上。还需要注意的是,这个元注解只会导致从超类继承注解,已经实现的接口上对于注解是无效的。

对于 @Native 和 @Repeatable 是从 Java 1.8 新增加的元注解。

定义为:

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

该注解接口没有对应的方法,只有一个元注解。是一个标注接口。

Repeatable

注释接口 java.lang.annotation.Repeatable 用于指示它(元)注释其声明的注释接口是可重复的。 @Repeatable 的值表示可重复注解接口的包含注解接口。

定义为:

@Documented@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.ANNOTATION_TYPE)public @interface Repeatable

该注解的参数有:

Native

表示可以从本机代码引用定义常量值的字段。 注解可以用作生成本机头文件的工具的提示,以确定是否需要头文件,如果需要,应包含哪些声明。

该注解的定义为:

@Documented@Target(ElementType.FIELD)@Retention(RetentionPolicy.SOURCE)public @interface Native {}

该注解接口同样是只有一个元注解, 是一个标注类的注解接口。

自定义注解

根据上面的看到的注解定义实例,以及现在项目中使用的方式, 很容易就可以知道如果自定义一个注解接口。接下来让我们自定义注解接口。

实现一个注解接口用来记录日志的内容。 注解代码如下:

import java.lang.annotation.Documented;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;@Documented@Target(value = {ElementType.FIELD, ElementType.METHOD, ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)public @interface LogAnnotation {        String value() default "";}
注解的使用

注解接口定义好了,如何使用呢? 对于注解的使用,现在来说就只有一种方法,就是基于反射机制。如果有其他的方法,可以评论区告诉我。感谢。

直接上代码。 这里用到了反射, 不过这些都是简单的使用, 加载类, 加载类的方法, 加载类的属性。

注解使用测试类:

@LogAnnotation(value="Test 测试类, 测试日志注解的功能")public class Test {    @LogAnnotation("定义变量用于存放对应的招呼的字符串")    private String sayMsg = "hello, Java 学习者!";    @LogAnnotation("打招呼的方法。")    public String sayHello(){        System.out.println(sayMsg);        return sayMsg;    }    public void test(){        System.out.println("不加注解");    }}

先测试类的日志信息:

Class clazz = Class.forName("Test");LogAnnotation logAnnotation = (LogAnnotation)clazz.getAnnotation(LogAnnotation.class);if(logAnnotation == null){    System.out.println("没有注解");    return ;}System.out.println("类上注解内容:" + logAnnotation.value());

在加载方法测试的日志信息:

Method[] methods = clazz.getMethods();for (Method method : methods) {    // 判断是否包含需要用到的 LogAnnotation 注解, 没有直接跳出, 不用在进行 if 嵌套    if(!method.isAnnotationPresent(LogAnnotation.class)){        continue;    }    LogAnnotation logMethod = (LogAnnotation) method.getAnnotation(LogAnnotation.class);    if(logAnnotation == null){        return ;    }    System.out.println("方法上注解:" + logMethod.value());}

属性的方法一样也可以加载测试:

Field[] fields = clazz.getDeclaredFields();for (Field field : fields) {    if(!field.isAnnotationPresent(LogAnnotation.class)){        continue;    }    LogAnnotation logMethod = (LogAnnotation) field.getAnnotation(LogAnnotation.class);    if(logAnnotation == null){         return ;     }    System.out.println("字段上注解:" + logMethod.value());}

完整的代码如下:

运行测试:

反射不需要了解太多, 后续会单独开一章, 进行讲解。 这里只是测试使用注解。有了这章的知识点, 就可以看些 Spring 框架中注解的使用。或者其他的框架中包含的注解信息。

希望本文对您有所帮助。感谢您的阅读。

点赞,关注, 收藏。

对于大脑来说, 大脑不是软件, 软件不会老化,不会退化。但是,大脑必须刷新,必须使用。否则记忆就会丢失。就比方说, 你只学习一门编程语言而不使用, 下次使用,明明知道自己学过这个, 但是就是记不起来对应详细知识点。

标签: #java的annotation