注解的介绍

目录

1、注解

2、注解的重要性

3、注解的作用分类

4、注解分类

5、JDK内置注解

 6、元注解

7、自定义注解

8、注解应用场景

         9、注解的提取



1、注解

JDK5.0新增 --- 注解(Annotation),也叫元数据。与类、接口、枚举是在同一个层次,它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。

2、注解的重要性

Annotation 可以像修饰符一样被使用,可用于修饰包,类,构造器,方法,成员变量,参数,局部变量的声明,这些信息被保存在Annotation的"name=value"对中。在JavaSE中,注解的使用目的比较简单,例如标记过时的功能,忽略警告等。在JavaEE/ArIdroid中注解占据了更重要的角色,例如用来配置应用程序的任何切面,代替JavaEE旧版中所遗留的繁冗代码和XML配置等。未来的开发模式都是基于注解的,JPA(java的持久化API)是基于注解的,Spring2.5以后都是基于注解的,Hibernate3.x以后也是基于注解的,注解是一种趋势,一定程度上可以说 :框架=注解+反射+设计模式。

3、注解的作用分类

  • 编写文档: 通过代码里标识的元数据生成文档【生成文档doc文档】

  • 代码分析: 通过代码里标识的元数据对代码进行分析【使用反射】

  • 编译检查: 通过代码里标识的元数据让编译器能够实现基本的编译检查【Override等】

4、注解分类

注解可以根据注解参数分为三大类:

标记注解: 没有参数的注解,仅用自身的存在与否为程序提供信息,如@Override注解,该注解没有参数,用于表示当前方法为重写方法。
单值注解: 只有一个参数的注解,如果该参数的名字为value,那么可以省略参数名,如 @SuppressWarnings(value = “all”),可以简写为@SuppressWarnings(“all”)。
完整注解: 有多个参数的注解。

1、标记注解
 

该注解中方法体并没有任何参数,也就是只起到标记作用

@Override注解是一个标记注解

@Target({TYPE,CONSTRUCTOR,METHOD})
public @interface MyAnnotation4 {
}

2、单值注解

在上面我们用到的@SuppressWarnings注解就是一个单值注解。那我们进入到它的源码看一下是怎么个情况。其实,和标记注解比较,它就多一个value参数而已,而这就是单值注解的必要条件,即只有一个参数。并且这一个参数为value时,我们可以省略value。

3、完整注解

上述两个类型注解讲解完,至于完整注解嘛,这下就能更明白了。其中的方法体就是有多个参数而已。

5、JDK内置注解

@Override: 标记在成员方法上,用于标识当前方法是重写父类(父接口)方法,编译器在对该方法进行编译时会检查是否符合重写规则,如果不符合,编译报错。

@Deprecated: 用于标记当前类、成员变量、成员方法或者构造方法过时如果开发者调用了被标记为过时的方法,编译器在编译期进行警告。

@SuppressWarnings: 压制警告注解,可放置在类和方法上,该注解的作用是阻止编译器发出某些警告信息。

@Repeatable:用于注解上,标记该注解可以在同一类中重复使用

1、@Override注解

@Override:限定重写父类方法,该注解只能用于方法

public class Person {
    public void eat(){
        System.out.println("父类eat..");
    }
}
public class Student extends Person {
    /*
    @Override的作用:限定重写的方法,只要重写方法有问题,就有错误提示。
     */
    @Override
    public void eat(){
        System.out.println("子类eat..");
    }
}

在子类中去实现父类的方法,就会在方法上有@Override注解,假如我们试图去重写eat方法名称,会发现在编译期就报错了,就说明该方法不是我们重写其父类(eat)的方法

2、@Deprecated

 用于表示所修饰的元素(类,方法,构造器,属性等)已过时。通常是因为所修饰的结构危险或存在更好的选择

 我们解释@Deprecated注解就需要模拟一种场景了。假设我们公司的产品,目前是1.0版本。这时候我们为产品的功能又进行了扩展,打算发布V2.0版本。但是,我们V1.0版本的产品需要抛弃吗?也就是说我们V1.0的产品功能还继续让用户使用吗?答案肯定是不能抛弃的,因为有一部分用户是一直用V1.0版本的。如果抛弃了该版本会损失很多的用户量,所以我们不能抛弃该版本。这时候,我们对功能进行了扩展后,发布了V2.0版本,我们给予用户的通知就可以了,也就是告知用户我们在V2.0版本中为功能进行了扩展。可以让用户自行选择版本。
 

在方法前加入@Deprecated,这个方法就会变成一个废弃方法/过期方法/过时方法
     */
    @Deprecated
    public void study(){
        System.out.println("学习。。");
    }

还有例如我们知道Date类中的这些方法已经是过时的了,如果我们使用该方法并执行该程序的话。执行的过程中就会提示该方法已过时的内容,但是只是提示,并不影响你使用该方法。 

 

 而这些过时的方法都有@Deprecated注解

3、@SuppressWarnings:

抑制编译器警告  这个抑制警告在idea中不明显,在eclipse才明显

unchecked:未检查的转化,如集合没有指定类型还添加元素
unused:未使用的变量
resource:有泛型未指定类型
path:在类路径,原文件路径中有不存在的路径
deprecation:使用了某些不赞成使用的类和方法
fallthrough:switch语句执行到底没有break关键字
rawtypes:没有写泛型,比如: List list = new ArrayList();
all:全部类型的警告

在这里插入图片描述

 在这里插入图片描述

@SuppressWarnings在IDEA中不明显,在eclipse中有显示黄色警告。

 6、元注解

元注解是用于修饰其它注解的注解。 

@Target:指定被修饰的注解的作用范围

@Retention:指定了被修饰的注解的生命周期

@Documented:指定了被修饰的注解是可以Javadoc等工具文档化

@Inherited:指定了被修饰的注解修饰程序元素的时候是可以被子类继承的

1、@Target

用于修饰注解的注解,用于指定被修饰的注解能用于修饰哪些程序元素。@Target也包含一个名为value的成员变量。
 

  • ANNOTATION_TYPE 用于描述注解
  • CONSTRUCTOR 用于描述构造方法
  • FIELD 用于描述属性
  • LOCAL_VARIABLE 用于描述局部变量
  • METHOD 用于描述方法
  • PACKAGE 用于描述包
  • PARAMETER 用于描述方法内的参数
  • TYPE  用于描述类型进行注解,比如类、接口、枚举

@Target({TYPE,CONSTRUCTOR,METHOD})
public @interface MyAnnotation4 {
}

2、@Retention

@Retention 用于修饰注解,用于指定修饰的那个注解的生命周期,@Rentention包含一个RetentionPolicy枚举类型的成员变量,使用@Rentention时必须为该value成员变量指定值

        属性    

                描述

RetentionPolicy.SOURCE

注解只保留在源文件,当Java文件编译成class文件的时候,注解被遗弃;
RetentionPolicy.CLASS注解只被保留到编译进行时的class文件,但 JVM 加载class文件时候被遗弃,也就是在这个阶段不会读取到该class文件。
RetentionPolicy.RUNTIME注解可以保留到程序运行的时候,它会被加载进入到 JVM 中,所以在程序运行时可以获取到它们。

注意: 我们常用的定义即是RetentionPolicy.RUNTIME,因为我们使用反射来实现的时候是需要从JVM中获取class类对象并操作类对象的。

三个生命周期是源码阶段 - > class类对象阶段 - > Runtime运行时阶段

3、@Documented

用于指定被该元注解修饰的注解类将被javadoc工具提取成文档。默认情况下,javadoc是 不包括注解的,但是加上了这个注解生成的文档中就会带着注解了

如果:Documented注解修饰了Deprecated注解, 

 那么Deprecated注解就会在javadoc提取的时候,提取到API中:

4、@Inherited

被它修饰的Annotation将具有继承性。如果某个类使用了被@Inherited修饰的Annotation,则其子类将自动具有该注解。

7、自定义注解

格式: public @Interface 注解名 {属性列表/无属性}

而注解体中的属性也是有要求的。其属性要求如下:

注解的属性也叫做成员变量。注解只有成员变量,没有方法。

属性的返回值类型必须是以下几种:
1、基本数据类型
2、String类型
3、枚举类型
4、注解
5、以上类型的数组

​​​​​​
注意:

1、在这里不能有void的无返回值类型和以上类型以外的类型
2、定义的属性,在使用时需要给注解中的属性赋值
3、如果定义属性时,使用default关键字给属性默认初始化值,则使用注解时可以不为属性赋值,它取的是默认值。如果为它再次传入值,那么就发生了对原值的覆盖。
4、如果只有一个属性需要赋值,并且属性的名称为value,则赋值时value可以省略,可以直接定义值
5、数组赋值时,值使用{}存储值。如果数组中只有一个值,则可以省略{} 

package com.mylifes1110.anno;

import com.mylifes1110.enums.Lamp;

public @interface MyAnno {
    //基本数据类型
    int num();

    //String类型
    String value();

    //枚举类型
    Lamp lamp();

    //注解类型
    MyAnno2 myAnno2();
    
    //以上类型的数组
    String[] values();
    Lamp[] lamps();
    MyAnno2[] myAnno2s();
    int[] nums();
}

8、注解应用场景

在javaWeb中,Selvert开发有两种方式,一种是web配置,另一种是注解式开发

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <!--配置Servlet-->
    <!--配置Servlet的信息-->
    <servlet>
        <servlet-name>HelloServlet</servlet-name>
        <servlet-class>com.annotation.servlet.HelloServlet</servlet-class>
    </servlet>
    <!--配置Servlet的映射路径-->
    <servlet-mapping>
        <servlet-name>HelloServlet</servlet-name>
        <!--http://localhost:8080/01-hello-servlet/hello-->
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>
</web-app>

注解替代配置文件

package com.bjsxt.servlet;

import javax.servlet.*;
import java.io.IOException;

@WebServlet("/hello")
public class HelloServlet implements Servlet {
    @Override
    public void init(ServletConfig servletConfig) throws ServletException {

    }

    @Override
    public ServletConfig getServletConfig() {
        return null;
    }

    /**
    * 用于提供服务, 接收请求, 处理响应
    *
    * @param servletRequest
    * @param servletResponse
    * @throws ServletException
    * @throws IOException
    */
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {

    }

    @Override
    public String getServletInfo() {
        return null;
    }

    @Override
    public void destroy() {

    }
}

在spring框架就是一个典型的注解式开发

spring注解:

@Param 将参数封装为Map集合

@ResponseBody 将返回的数据转化为JSON串, 如果是字符串本身 原数据返回
@RequestMapping("/hello") 实现浏览器的请求路径与方法的映射
@ComponentScan 包扫描注解 扫描注解
@Bean 标识该方法的返回值交给Spring容器管理
@Scope 控制单例和多例
@Lazy 懒加载
@PostConstruct 初始化方法
@PreDestroy 销毁方法
@Component 将当前类未来的对象交给容器管理
@Autowired 按照类型进行注入
@Qualifier 按照名称进行注入
@Repository 标识持久层注解
@Service 标识Service层
@Controller 标识Controller层
@Value 为属性赋值
@PropertySource 加载指定路径下的配置文件
@Aspect 标识当前类是一个切面类
@Pointcut 用于定义切入点表达式 表达式写法4种
@EnableAspectJAutoProxy 让AOP的注解有效果
@Before AOP-前置通知
@AfterReturning AOP-后置通知
@AfterThrowing AOP-异常通知
@After AOP-最终通知
@Around AOP-环绕通知
@Order(1) //可以利用order关键字 实现AOP的排序 数字越小越先执行
@PathVariable restFul结构,接收参数的注解
@GetMapping("") 只能接收GET请求类型
@DeleteMapping("") 只能接收DELETE请求类型
@PostMapping("") 只能接收POST请求类型
@PutMapping("") 只能接收PUT请求类型
@RestController 表示Controller类,同时要求返回值为JSON
@CrossOrigin 允许跨域访问
@RequestMapping 将公共的部分抽取
@Data lombok动态生成get/set/toString/equals/hashcode等方法
@Accessors(chain = true) 开启链式加载
@NoArgsConstructor 生成无参构造方法
@AllArgsConstructor 生成全参构造方法
@Mapper mybatis将当前的接口交给Spring容器管理. Map<类名小写,JDK动态代理对象>
@SpringBootTest 该注解的作用在进行代码测试时启动spring容器,之后动态的获取对象 注意包路径 主启动类的同包及子包中
@Alisa 设置别名
@MapperScan Mybatis中扫描指定包路径的接口 为其创建代理对象.
@Insert Mybatis 新增操作注解
@Update Mybatis 修改操作注解
@Delete Mybatis 删除操作注解
@Select Mybatis 查询操作注解
@Transactional Spring中用来控制事务
@RestControllerAdvice Controller层的全局异常处理
@ExceptionHandler 按照某种异常类型进行拦

@Configuration 标识当前类是配置类

9、注解的提取

注解通过反射获取。首先可以通过 Class 对象的 isAnnotationPresent() 方法判断它是否应用了某个注解

public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {}

然后通过 getAnnotation() 方法来获取 Annotation 对象。

public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {}

或者是 getAnnotations() 方法。

public Annotation[] getAnnotations() {}

前一种方法返回指定类型的注解,后一种方法返回注解到这个元素上的所有注解。

如果获取到的 Annotation 如果不为 null,则就可以调用它们的属性方法了。比如

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation {

    public int id() default -1;

    public String msg() default "Hi";

}

TestAnnotation 中 id 属性默认值为 -1,msg 属性默认值为 Hi 

因为有默认值,所以无需要再在 @TestAnnotation 后面的括号里面进行赋值了,这一步可以省略

@TestAnnotation()
public class Test {}

@TestAnnotation()
public class Test {

    public static void main(String[] args) {

        boolean hasAnnotation = Test.class.isAnnotationPresent(TestAnnotation.class);

        if ( hasAnnotation ) {
            TestAnnotation testAnnotation = Test.class.getAnnotation(TestAnnotation.class);

            System.out.println("id:"+testAnnotation.id());
            System.out.println("msg:"+testAnnotation.msg());
        }

    }

}

 至此,注解介绍完毕,由于作者水平有限难免有疏漏,欢迎留言纠错。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值