前言:
如今朋友们对“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