您的位置 首页 java

Java 17 的注解 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 注解
 */@Documented
public @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 17 的注解 Annotation 基础使用篇

文章地址:https://www.zhihuclub.com/193655.shtml

关于作者: 智云科技

热门文章

网站地图