JAVA系列教程:注解

什么是注解

我们知道类是对于某一特征的事物进行定义,这些事物具有相同的属性,相同的行为。那注解可以理解为对于类的一个横向扩展,然后在类进行编译时对注解信息进行解析或丢弃,运行时可以根据注解信息进行横向操控.

如下图所示,假设我有这样一个需求,A,B,C是三个不同的类,我需要在应用程序启动时分别调用类A method1(), 类B method2(),类C的method3()方法。如果不使用注解的话我们可以考虑定义一个接口StartUpService,同时会有initWhenStart()方法,而method1(), method2()和method3()就都变成了initWhenStart()方法,同时定义StartupService类,将所有实现了StartService接口的所有实现类通过反射机制查找出来,然后逐个调用initWhenStart()方法.
在这里插入图片描述
那如果使用注解之后我们可以怎么实现呢?我们可以通过在类A method1(),类B method2(), 类C method3()方法上都加入注解A, 然后当我们程序启动时,获取所有实现注解A的方法,然后分别对这些方法进行调用。
在这里插入图片描述

从上面的例子来看,好像可以通过接口的形式来解决方法注解的问题,那是不是所有问题都能解决呢?

我们通过Spring中一个常用的注解@RequestMapping来再深入的研究一下(如果对这个注解不了解的可以先去百度或google了解一下,这里就不深入研究了)。

这个注解主要用来将请求与处理函数关联起来,如下图所示当请求为/hello的时候,我们就会调用home()函数,当请求为/test的时候,就调用test()函数。看到这里,是不是发现用前面的接口实现起来就比较麻烦了呢,那就让我们来好好来认识认识注解吧~

package com.mary.demo.controller;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloWorldController {

    @RequestMapping("/hello")
    String home() {
        return "Hello World!";
    }

    @RequestMapping("/test")
    String test(){
        return "test";
    }
}

JDK的元Annotation

通过元Annotation,我们可以规范定义的注解具体能用在什么地方(比如方法上面,类上面还是属性上面),保存时间有多久(如只是存在于编译之前,或者存在到编译过程还是说可以一直到jvm运行),或者这个注解能不能被继承等等

  1. @Retention : 用来描述定义的注解能保存多长时间,具体见下表
类型描述
RetenionPolicy.CLASS编译器把该注解记录在class文件中。当运行java程序时,JVM不可获取注解信息。这是默认值!
RetenionPolicy.RUNTIME编译器把该注解记录在class文件中。当运行java程序时,JVM可获取注解信息,程序可以通过反射获取该注解信息
RetenionPolicy.SOURCE该注解只保存在源代码中,编译器直接丢弃该注解
  1. @Target: 用来描述定义的注解具体能用在哪个地方
类型描述
METHOD用于方法上
TYPE用于类或接口(同时也包括了ANNOTATION_TYPE即注解)上
ANNOTATION_TYPE可用于注解类型上(被@interface修饰的类型)
CONSTRUCTOR用于构造函数上
FIELD用于属性上
LOCAL_VARIABLE用于局部变量上
PACKAGE用于记录java文件的package信息
PARAMETER用于参数上
  1. @Documented: 指定了是否对使用了该注解的API添加到document中
  2. @Inherited:主要用于表明该注解是否可继承,即如果注解可继承,则当我们去查找某个类是否有该注解时,会自动去其父类进行查找,一直查找到Object类。如果没设置可继承,则我们对某个类中是否定义了某个注解的查找只会在当前类中查找。另外,该注解指针对@Target为Element.Type和Element.ANNOTATION_TYPE有效,对于其他类型就没啥意义了。

JDK自带注解

对于JDK自带的注解,我们是可以直接使用的,同时对于注解的处理JDK也已经做好了。

注解名称描述
@Override当子类重写父类方法时,子类可以加上这个注解,那这有什么什么用?这可以确保子类确实重写了父类的方法,避免出现低级错误
@Deprecated这个注解用于表示某个程序元素类,方法等已过时,当其他程序使用已过时的类,方法时编译器会给出警告
@SuppressWarnings被该注解修饰的元素以及该元素的所有子元素取消显示编译器警告,例如修饰一个类,那他的字段,方法都是显示警告
@SafeVarargs“堆污染”警告
@Functionallnterface.函数式接口

如何自定义注解

定义注解跟定义类一样,只是定义类我们使用class关键字,而定义注解我们使用@interface,同时我们可以添加元注解对注解进行修饰。
以Spring框架中的Indexed注解为例,看一下如何自定义注解。

  1. 首先我们使用@interface关键字定义注解
  2. 指定@Target元注解 --此例中这个注解定义在类或接口(同时包括了Annotation)上面
  3. 指定@Retention–此例中设置RetentionPolicy.RUNTIME, 即该注解能够一直存活到JVM运行,可以通过反射机制去查找出所有实现了该注解的接口跟类
  4. 可指定注解@Documented: 表明对于定义了该注解的接口跟类,所有的API都将被document.
  5. 可指定注解@Inherited

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

看一个复杂一点的注解
在注解Controller定义时,同时了声明了注解Component,此时我们猜到注解Component在定义的时候@Target应该是ElementType .ANNOTATION_TYPE或者ElementType.TYPE,直接上Component注解定义代码如下,由图可知,确实跟我们想的是一样的。

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Controller {
    @AliasFor(
        annotation = Component.class
    )
    String value() default "";
}

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Indexed
public @interface Component {
    String value() default "";
}

特别说明

  1. 注解上面除了使用元注解之外,也是可以使用自定义注解(如上图的@Controller注解)
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值