千家信息网

怎么使用注解

发表于:2025-01-20 作者:千家信息网编辑
千家信息网最后更新 2025年01月20日,这篇文章主要介绍"怎么使用注解",在日常操作中,相信很多人在怎么使用注解问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答"怎么使用注解"的疑惑有所帮助!接下来,请跟着小编一
千家信息网最后更新 2025年01月20日怎么使用注解

这篇文章主要介绍"怎么使用注解",在日常操作中,相信很多人在怎么使用注解问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答"怎么使用注解"的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

首关之程娲造注

注解一旦构造出来,就享有编译器的类型检查保护。让我们先看下一组代码热热身:

public class TestService {      @MyAnnotation     public void runTset() {         System.out.println("annotation test");     }  }

不要纳闷,Java 中确实没有一个注解名为MyAnnotation,但这个怎么来的呢,就是我们自己造的。

那么关子卖完了,接下来就来揭秘注解的制造:

@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface MyAnnotation { }

这样子,一个简单的注解就新鲜出炉了。需要注意的是这可不是一个接口,需要留言interface前面还有一个@,这个标识要是漏掉了,那可以天差地别。

细心的小伙伴可能注意到了,定义的注解头上怎么还有注解。

这就是接下来要讲到,敲黑板,注意看!

元注解来帮忙

在定义注解时,会需要一些元注解。上面出现了两个,分别是@Target和@Retention.

其中@Target用来定义你的注解将应用于什么地方(例如一个方法或一个域),@Retention用来定义该注解在哪一个级别可用,在源代码中(「SOURCE」),类文件中(「CLASS」)或者运行时(「RUNTIME」)。Java 提供了四种元注解,如下:

名称用处
「@Target」标识该注解可以用于什么地方。其中 ElementType 参数包括:
1. CONSTARUCTOR:构造器的声明
2. FIELD:域声明(包括enum实例)
3. LOCAL_VARIABLE:局部变量声明
4. METHOD:方法声明
5. PACKAGE:包声明
6. TYPE:类、接口(包括注解类型)或enum 声明
「@Retention」表示需要在什么级别保存该注解信息,其中RetentionPolicy参数包括:
1.SOURCE:注解将被编译器丢弃
2.CLASS:注解在 class 文件中可用,但会被 VM 丢弃
3. RUNTIME:VM 将在运行期也保留注解,因此可以通过反射机制读取注解的信息
「@Documented」将此注解包含在 JavaDoc 中
「@Inherited」允许子类继承父类的注解

注解也分类

我们在上面示例中创建了一个 @MyAnnotation 注解。看起来很简单,没什么内容,因此这种注解我们也称为 「标记注解」,注解也分几类:

  • 标记注解:注解内部没有属性。使用方式:「@注解名」

//定义 @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface MyAnnotation { }
  • 单值注解:注解内部只有一个属性。使用方式:「@注解名(key = value)」

//定义 @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface SingleValueAnnotation {     String name(); } //使用 @SingleValueAnnotation(name = "test") public void singleTest() {}
  • 多值注解:注解内部有过个属性。使用方式:「@注解名(key = value, key = value, ...)」

//定义 @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface MultiValueAnnotation {     String name();     int num(); } //使用 @MultiValueAnnotation(name = "test", num = 1) public void multiTest() {}

值也有默认

当我们使用的不是标记注解时,如果在使用注解的时候不给注解中的属性赋上值,那么编译器就会报错,提示我们需要赋值。

这样子是很不方便,有时候我们并没有使用到或值是固定的不想重复写,那么这个时候就需要借助「default」关键字来帮忙我们解决这种问题。

@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface MultiValueAnnotation {          String name();          int num() default 0; }

我们在属性上使用了 default 关键字来声明 num 属性的默认值为 0 ,这样子我们在使用上述那个注解的时候就可以不用手动给num赋值了。

次关之造器解注

注解具有让编译器进行编译检查的作用,但是如果没有用来读取注解的工具,那注解也不会比注释更有用,起码注释可以让开发人员更直观的看到此段代码的用处。

重回反射想要创建与使用 「注解处理器」,我们还需要借助反射机制来构造这类工具。以下是简单的例子:

public class AnnotationHandle {      public static void track(Class c) {         for (Method m : c.getDeclaredMethods()) {             MultiValueAnnotation annotation = m.getAnnotation(MultiValueAnnotation.class);             if (annotation != null) {                 System.out.println("name:" + annotation.name() +                         "\n num:" + annotation.num());             }         }     }      public static void main(String[] args) {         track(TestService.class);     } }  /*  OUTPUT:   name:test    num:0 */

在上述例子中我们用到了两个反射的方法:getDeclaredMethods()和getAnnotation()。

其中getDeclaredMethods() 用来返回该类的所有方法,getAnnotation()用来获取指定类型的注解对象。如果方法上没有该注解则会返回 「null」 值。

注解元素可用类型

上述@MultiValueAnnotation注解中我们定义了 String类型的 「name」 和 int类型的 「num」,除此之外我们还可以使用其他类型如下:

  • 「基本类型」(「int、float、boolean等」)

  • 「String」

  • 「Class」

  • 「enum」

  • 「Annotation」

  • 「以上类型的数组」

如果使用了上面以外的其他类型,那么编译器就会报错。而且要注意的是,「也不能使用基本类型的包装类型」

默认值的限制

上述例子中我们也看到了,我们可以在使用注解的时候给注解属性赋值,也可以在定义注解的时候给注解一个默认值,但是这两者都说明了一件事:「那就是,注解元素不能有不确定的值,要么具有默认值,要么在使用注解时提供元素的值」

基本元素不存在null值,因此对于非基本类型的元素,无论是在使用中声明,还是在定义时声明, 「都不能将 null 值作为其值」。因此在实际开发中,我们往往会定义一些特殊值作为不存在的标识,例如 「负数」 或 「空字符串」

三关之运注帷幄

在前面两关中,我们学会了定义注解和创建注解处理器。接下来我们就要来更加深入掌握注解!

注解也能嵌套

在修饰注解元素的时候我们看到可以使用Annotation来修饰,估计看到那的时候会觉得有点奇怪。在这里就来为你来揭秘。

先来看一组注解:

@Constraints

@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface Constraints {     boolean primaryKey() default false;     boolean unique() default false; }

@SQLString

@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface SQLString {     String name() default "";     Constraints constraints() default @Constraints; }

我们在@SQLString注解中使用Constraints注解元素,并将默认值设为@Constraints。这个时候Constraints中的值都是@Constraints注解中定义的默认值,如果我们要使用自定义的话,做法如下:

@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface SQLString {     String name() default "";     Constraints constraints() default @Constraints(primaryKey = true); }

这样子我们就可以使用自己定义的「value」

注解不支持继承

我们不能使用extends来继承某个@interface,但是可以通过嵌套的方式来解决这一烦恼。

AOP与注解的搭配

「AOP」 在当今开发中我们并不陌生,那么 「AOP」 和 「注解」 能产生什么化学反应呢,请看以下代码:

@ApiLog:

@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD, ElementType.TYPE}) public @interface ApiLog {     /**      * 接口名称      */     String name(); }

使用:

@GetMapping(value = "/getConfig") @ApiLog(name = "获取系统相关配置") public Result getConfig() throws Exception {     return sendOK(SystemService.getConfig(type)); }

Aop使用:

@Aspect @Component public class SysLogAspect {     @Autowired     private LogService logService;          @Pointcut("@annotation(cbuc.life.annotation.ApiLog)")     public void logPointCut() {             }      @Around("logPointCut()")     public Object around(ProceedingJoinPoint point) throws Throwable {         long beginTime = System.currentTimeMillis();         //执行方法         Object result = point.proceed();         //执行时长(毫秒)         long time = System.currentTimeMillis() - beginTime;         //保存日志         saveSysLog(point, time);         return result;     }      private void saveSysLog(ProceedingJoinPoint joinPoint, long time) {         MethodSignature signature = (MethodSignature) joinPoint.getSignature();         Method method = signature.getMethod();          LogEntity log = new LogEntity();         ApiLog apiLog = method.getAnnotation(ApiLog.class);         if(apiLog != null){             //注解上的描述             log.setMethodDescribe(syslog.value());         }          //请求的方法名         String className = joinPoint.getTarget().getClass().getName();         String methodName = signature.getName();         log.setMethod(className + "." + methodName + "()");          //请求的参数         Object[] args = joinPoint.getArgs();         String params = JSON.toJSONString(args[0]);         log.setParams(params);          //获取request         HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();          //设置IP地址         log.setIp(ServletUtil.getIpAddress(request));          //用户名         String username = LoginInfo.getUsername();         log.setUsername(username);          //保存系统日志         logService.save(log);     } }

到此,关于"怎么使用注解"的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注网站,小编会继续努力为大家带来更多实用的文章!

注解 类型 方法 时候 元素 属性 编译 编译器 接下来 方式 样子 反射 学习 代码 例子 参数 就是 接口 标记 标识 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 无锡构建智慧园区软件开发 公安机关能否侵入服务器 使命召唤18服务器快照 软件开发厂商电话多少 软件开发时期阶段 幻塔切换服务器开服礼包还有吗 沈阳软件开发驻场 网络短信软件开发 如何登录宽带服务器 魔兽世界玩哪个服务器 青浦区参考网络技术创新服务 我的世界服务器账号被封了 天津常规软件开发设计 服务器管理系统 开源 服务器扩容硬盘不显示 反欺诈数据库命中该客户怎么消除 网络优化网络安全宣传周 绿园区网络技术咨询经验丰富 考研考网络安全怎么样 三级网络技术报名要求 企业号服务器配置 win2003打印服务器 软件开发小组成员岗位职责 周村企业管理erp软件开发 影响计算机网络安全的因素 阳江无限软件开发价格走势 始终提高警惕筑牢网络安全 创建数据库表达正确的语句是 湖南专科学校软件开发 tp路由器dns服务器异常
0