Java 注解详解:从基础到自定义及解析

news2024/11/16 15:42:00

注解:概述

目标

  • 能够理解注解在程序中的作用

路径

  1. 什么是注解
  2. 注解的作用

注解

什么是注解?

  • 注解(Annotation)也称为元数据,是一种代码级别的说明
  • 注解是JDK1.5版本引入的一个特性,和类、接口是在同一个层次
  • 注解可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明

注解:就是具有特殊含义的标记(注解是给机器阅读的)

注解的作用

注解就是在代码里添加一些特殊标志,这些标志可以在编译,类加载,运行时被读取,并执行相应的处理,以便于其他工具补充信息或者进行操作

注解的作用:

  1. 编译检查
  • @Override:用来修饰方法声明。
  • 用来告诉编译器该方法是重写父类中的方法,如果父类不存在该方法,则编译失败

代码分析:

  • 通过代码里标识的注解对代码进行分析
  • 框架的配置( 框架 = 代码 + 配置 )
    • 具体使用请关注框架课程的内容的学习(注解去配置数据)

生成帮助文档:

  • @author:用来标识作者姓名
  • @version:用于标识对象的版本号,适用范围:文件、类、方法
    • 使用@author和@version注解就是告诉Javadoc工具在生成帮助文档时把作者姓名和版本号也标记在文档中

使用过的注解:

  • @Override
    • 用来修饰方法声明,告诉编译器该方法是重写父类中的方法,如果父类不存在该方法,则编译失败
  • @Test
    • Junit测试注解
  • @FunctionalInterface //函数式接口

注解:自定义注解

目标

  • 能够熟悉自定义注解的格式

路径

  1. 注解的定义格式
  2. 定义带有属性的注解

注解的定义格式

定义注解使用关键字:@interface

public @interface 注解名{
   //内容
}

注解本质上就是一个接口。所有注解都会继承一个接口:Annotation

    public interface 自定义注解名 extends java.lang.annotation.Annotation {}

带有属性的注解

属性的格式

  • 格式1:数据类型 属性名(); //无默认值的属性
  • 格式2:数据类型 属性名() default 默认值; //有默认值的属性
public @interface Student {
  String name();                // 姓名
  int age() default 18;         // 年龄
  String gender() default "男"; // 性别
} 
// 该注解就有了三个属性:name,age,gender

属性适用的数据类型【记住】

1. 八种数据数据类型(int,short,long,double,byte,char,boolean,float)
2. String,Class,注解类型,枚举类
3. 以上类型的一维数组形式

注解的定义格式:

public @interface 注解名
{
    //属性格式 :  数据类型 属性名()
    String 属性名();
    int 属性名() default 默认值;
}
//注意:属性的类型只能是8种基本数据类型、String、Class、枚举、注解、(以及一维数组形式)

注解:注解的使用

路径

  1. 注解的使用格式
  2. 案例代码
  3. 特殊属性value

注解的使用格式

//无属性注解
@注解名                      例:@Test

//有属性注解
@注解名(属性=值,属性=值)

解可以在类上,成员变量上,构造方法上,方法上,参数上....

有默认值的属性,可以不用进行赋值。

案例代码

将Book注解使用起来

public @interface Book {
    String name();

    double price() default 100.0;

    String[] author();
}

建立一个BookStore的类,在类中定义成员变量,构造方法,成员方法

@Book(name = "西游记", author = {"吴承恩", "张三"})
public class BookStore {
    @Book(name = "三国", price = 10, author = {"罗贯中"})
    private String book;

    @Book(name = "三国", price = 10, author = {"罗贯中"})
    public BookStore() {
    }


    @Book(name = "三国", price = 10, author = {"罗贯中"})
    public void test() {

    }
}

特殊属性value

如果注解中只有一个属性要赋值,而且名字是value,可以将value给省略,可以直接给值

@interface A{
    String value();
}

@interface B{
    String value();
    String name();
}

@interface C{
    String value();
    int price() default 100; //有默认值
}
//测试类
public class Demo {
    @A("值")  //当自定义注解中仅有一个value属性时,可以省略value属性名
    public void test1() {
    }

    @B(value = "值",name="aa") //当自定义注解中除了value属性外,还有其它属性,value不能省略
    public void test2() {

    }

    @C("值")//自定义注解中除了value属性外,还有其它带有默认值的属性,value可以省略
    public void test3() {

    }
}
1.如果自定义注解中的属性不给默认值,那么使用的时候必须赋值,如果有默认值,使用的时候可以不给值
2.使用注解:@注解名(属性名=属性值,属性名=属性值,....)
3.如果注解中没有属性,使用的时候@注解名
4.如果属性是数组,那么赋值方式:
    @注解名(属性名=属性值,属性名=属性值,属性名={属性值,属性值,..}....)
5.如果属性是数组类型,并且使用的时候只给一个值,那么可以省略大括号
6.如果属性只有一个并且属性名是value,那么给value赋值的时候可以不写value
7.如果含有多个属性,并且没有默认值,那么给value赋值的时候必须书写value
8.如果含有多个属性,并且具有默认值,那么给value赋值的时候可以不写value
9.同一个注解不能同时修饰同一个方法或者同一个类
10.不同注解可以同时修饰同一个方法或者同一个类

注解:元注解

路径

  1. 元注解的作用
  2. 常用的元注解
  3. 元注解的使用

元注解的作用

默认情况下,注解可以用在任何地方,比如类,成员方法,构造方法,成员变量等地方

如果要限制自定义注解的使用位置怎么办?那就要学习一个新的知识点:元注解

结论:元注解是用来约束自定义注解的使用范围、生命周期

常用的元注解

常用元注解:@Target、@Retention

@Target

  • 作用:指明此注解用在哪个位置,如果不写默认是任何地方都可以使用
  • @Target可选的参数值在枚举类ElemenetType中包括:
    • TYPE: 用在类,接口上
    • FIELD:用在成员变量上
    • METHOD: 用在方法上
    • PARAMETER:用在参数上
    • CONSTRUCTOR:用在构造方法上
    • LOCAL_VARIABLE:用在局部变量上

@Retention

  • 作用:定义该注解的生命周期(有效范围)。
  • @Retention可选的参数值在枚举类型RetentionPolicy中包括:
    • SOURCE:注解只存在于Java源代码中,编译生成的字节码文件中就不存在了
      • 使用场景:针对一些检查性的操作,比如:@Override ,就使用SOURCE注解
    • CLASS:注解存在于Java源代码、编译以后的字节码文件中,运行的时候内存中没有,默认值
      • 使用场景:在编译时进行一些预处理操作,比如:生成一些辅助代码,就用CLASS注解
    • RUNTIME:注解存在于Java源代码中、编译以后的字节码文件中、运行时内存中,程序可以通过反射获取该注解
      • 使用场景:要在运行时去动态获取注解信息,那只能用 RUNTIME 注解

使用

@Target({ElementType.METHOD,ElementType.TYPE}) //元注解
@interface Stu{
    String name();
}

//类
@Stu(name="jack")  //成功
public class AnnotationDemo02 {
    // 成员变量
    @Stu(name = "lily")  // 编译失败
    private String gender;

    // 成员方法
    @Stu(name="rose")  //成功
    public void  test(){
    }

    // 构造方法
    @Stu(name="lucy") // 编译失败
    public AnnotationDemo02(){}
}

注解:注解解析

路径

  1. 获取注解数据的原理
  2. 案例代码

获取注解数据的原理

想要对注解中的数据进行解析,需要借助:AnnotatedElement接口

  • Field,Method,Constructor,Class等类都是实现了AnnotatedElement接口

AnnotatedElement 是一个接口,定义了解析注解的方法:

1. boolean isAnnotationPresent(Class<Annotation> annotationClass)   
   判断当前对象是否使用了指定的注解,如果使用了则返回true,否则false

   public class BookStore{

       @Book(name="书名")
       public void buy() // Method对象 判断该对象上是否使用了@Book注解
       {                 // boolean flag = Method对象.isAnnotationPresent(Book.class)
       }
   } 


2. T getAnnotation(Class<T> annotationClass) 
   根据注解类型获得对应注解对象
   // 获取对象上的自定义注解
   // Book bookAnno = Method对象.getAnnotation(Book.class); 
   //      bookAnno.属性   //获取注解中属性的值

Class,Constructor,Method,Field都会实现AnnotatedElement 接口

  • 解析类型上的注解:借助字节码对象(Class对象)
  • 解析构造方法上的注解:借助构造器对象(Constructor对象)
  • 解析方法上的注解:借助方法对象(Method对象)
  • 解析字段上的注解:借助字段对象(Field对象)

注解解析的步骤:(注解是书写在:类、方法、变量上)

1、利用反射技术获取注解作用的对象:类、方法、变量、构造方法

2、判断对象上是否有自定义注解存在

3、有:获取对象上的自定义注解

4、使用获取到的自定义注解对象,拿到注解中的属性值

注意:注解解析必须保证自定义注解生命周期在RUNTIME(程序运行中)

案例代码

需求如下:

  1. 定义注解Book,要求如下:
  • 包含属性:String value() 书名
  • 包含属性:double price() 价格,默认值为 100
  • 包含属性:String[] authors() 多位作者
  • 限制注解使用的位置:类和成员方法上 【Target】
  • 指定注解的有效范围:RUNTIME 【Retention】
  1. 定义BookStore类,在类和成员方法上使用Book注解
  2. 定义TestAnnotation测试类获取Book注解上的数据
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.METHOD,ElementType.TYPE}) //使用范围:方法、类
@Retention(RetentionPolicy.RUNTIME) //保证注解在程序执行时有效(适用于注解解析)
public @interface Book {
    String value();
    double price() default 100;
    String[] authors();
}


//类
public class BookStore {
    @Book(value = "Java入门", authors = {"张老师", "毕老师"})
    public void buy() {
        System.out.println("购书.....");
    }
}

//对注解中的数据进行解析
public class TestBookStore {
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //反射套路:1、Class  2、构造器   3、Method
        Class<BookStore> bookStoreClass = BookStore.class;

        //获取构造器
        Constructor<BookStore> con = bookStoreClass.getConstructor();
        BookStore bookStore = con.newInstance();//实例化对象

        //获取Method
        Method method = bookStoreClass.getMethod("buy");

        //解析注解的步骤
        if(method.isAnnotationPresent(Book.class)){
            //获取Method对象上的Book注解
            Book bookAnno = method.getAnnotation(Book.class);

            //获取注解上的数据
            String bookName = bookAnno.value();
            double bookPrice = bookAnno.price();
            String[] bookAuthors = bookAnno.authors();

            System.out.println("书名:"+bookName);
            System.out.println("价格:"+bookPrice);
            System.out.println("作者:"+ Arrays.toString(bookAuthors));
        }
    }
}

小结

注解解析的步骤:

  1. 利用反射技术获取相关的对象:类、构造器、方法、变量
  2. 使用方法getAnnotation,获取自定义注解对象
  3. 使用注解对象,分别获取注解中的属性值

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2165287.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux系统--五种IO模型

1、简介 Linux IO 模型根据实现的功能可以划分为为阻塞 IO、 非阻塞 IO、 信号驱动 IO&#xff0c; IO 多路复用和异 步 IO。 根据等待 IO 的执行结果进行划分&#xff0c; 前四个 IO 模型又被称为同步 IO&#xff0c;如下图&#xff1a; 2、详细介绍 2.1 阻塞IO 在阻塞IO模…

Docker容器常用命令详解

Docker容器常用命令&#xff0c;我们经常使用&#xff0c;又经常忘记&#xff0c;今天我们系统分析一下&#xff1a; 1、查看运行的进程 #列出所有运行的容器 sudo docker ps#列出所有容器&#xff0c;包括运行和停止的 docker ps -a #列出所有容器&#xff0c;并过滤 docker…

大数据Hologres(一):Hologres 简单介绍

文章目录 Hologres 简单介绍 一、什么是实时数仓 Hologres 二、产品优势 1、专注实时场景 2、亚秒级交互式分析 3、统一数据服务出口 4、开放生态 5、MaxCompute查询加速 6、计算存储分离架构 三、应用场景 搭建实时数仓 四、产品架构 1、Shared Disk/Storage &am…

深入探索linux的零拷贝(zero-copy):底层技术原理与代码实现

前言 I/O 或输入/输出通常意味着中央处理器(CPU) 与外部设备&#xff08;如磁盘、鼠标、键盘等&#xff09;之间的读写。在深入研究零拷贝之前&#xff0c;有必要指出磁盘 I/O&#xff08;包括磁盘设备和其他块导向设备&#xff09;和网络 I/O之间的区别。 磁盘 I/O 的常用接…

mysql安装教程(新手版)

本教程不需要手动设置配置文件&#xff0c;比较简单&#xff0c;适合新手&#xff0c;过程需联网。 1.找到mysql官网 mysql官网 一.mysql的安装 1.界面如下图&#xff0c;点击箭头所指。 2.选择mysql版本&#xff0c;系统&#xff0c;安装。 3.下载完成后双击打开&#xff0…

JavaWeb--纯小白笔记03:servlet入门---动态网页的创建

笔记&#xff1a;index.html在tomcat中为默认的名字&#xff0c;html里面的语法不严谨。改配置文件要小心&#xff0c;不然容易删掉其他 Servlet&#xff1a;服务器端小程序&#xff0c;写动态网页需要用Servlet&#xff0c;普通的java类通过继承HttpServlet&#xff0c;可以响…

c++9月25日

1.栈的实现 头文件 #ifndef STACKHEAD_H #define STACKHEAD_H #include <iostream> #define MAX 30 using namespace std;class Stack { private:int *ptr;int top; public:Stack();Stack(int *,int);~Stack();bool full();bool empty();int push(int);void show();Sta…

一个超强的Python库!HTTP请求性能分析工具推荐:httpstat!

什么是Python httpstat&#xff1f; httpstat是一个基于命令行的工具&#xff0c;用于在终端中展示HTTP请求的详细统计信息。它以可视化和易读的方式显示了HTTP请求的各个阶段的性能数据&#xff0c;如DNS解析、TCP连接、TLS握手、发送请求、服务器处理、接收响应等。 使用ht…

2024.9.26 Spark学习

资料&#xff1a; Spark基础入门-第一章-1.1-Spark简单介绍_哔哩哔哩_bilibili &#xff08;1&#xff09;基础知识 Apache Spark 是用于大规模数据&#xff08;large-scale data&#xff09;处理的统一分析引擎。 分布式处理数据 PySpark模块 Spark 和 Hadoop 有区别&…

QT编译之后的debug包下运行程序双击运行出现无法定位程序输入点__gxx_personlity_seh0于动态链接库

1.出现这个错误的原因是&#xff1a; 缺少如下文件&#xff1a; 2.解决方法&#xff1a; 在运行程序.exe所在的目录执行&#xff1a;windeployqt untitled.exe&#xff08;指打包的运行程序&#xff09; 3.如果执行提示由于找不到qt5core.dll,无法继续执行代码和无法识别win…

c++进阶学习-----继承

1.继承的概念及定义 1.1继承的概念 继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段&#xff0c;它允许程序员在保持原有类特性的基础上进行扩展&#xff0c;增加功能&#xff0c;这样产生新的类&#xff0c;称派生类。 继承呈现了面向对象 程序设计的…

聚合函数count 和 group by

count函数&#xff1a; count&#xff08;列名&#xff09; SELECT COUNT(sid) FROM grade 统计列中所有的数值个数&#xff0c;会忽略null值。 count&#xff08;*&#xff09;和count&#xff08;1&#xff09; SELECT COUNT(*) FROM grade SELECT COUNT(1) FROM grade 统…

前端接口报错302 [已解决]

前端接口报错302 [已解决] 在前端开发中&#xff0c;与后端接口的交互是项目成功的关键。然而&#xff0c;遇到如302这样的状态码报错时&#xff0c;可能会让开发者感到困惑。本文将通过详细解析和多个代码案例&#xff0c;帮助你深入理解前端接口报错302&#xff0c;并提供有效…

Redis入门介绍

1.初识Redis 计算机领域的任何问题都可以通过增加一个间接的中间层来解决 1.Redis介绍 Redis&#xff08;Remote Dictionary Server )&#xff0c;即远程字典服务&#xff0c;是一个开源的&#xff0c;使用C语言编写、支持网络调用、基于内存亦可持久化的Key-Value数据库&…

静电势能(electrostatic potential energy)和电势(electric potential)

静电势能(electrostatic potential energy) 静电势能是把一个电荷从无穷远处移动到这个位置需要做的功。 静电势能的符号&#xff1a; U 图示&#xff1a; 计算公式&#xff1a; U q 1 q 2 4 π ϵ 0 R U \frac{q_1q_2}{4\pi\epsilon_0R} U4πϵ0​Rq1​q2​​ 其中 U …

【JavaEE】——阻塞队列,生产消费者模型(较难)

阿华代码&#xff0c;不是逆风&#xff0c;就是我疯&#xff0c;你们的点赞收藏是我前进最大的动力&#xff01;&#xff01;希望本文内容能够帮助到你&#xff01; 目录 一&#xff1a;阻塞队列 1&#xff1a;概念 2&#xff1a;阻塞队列与普通队列比较 二&#xff1a;“生…

简单好用的PDF编辑器有哪些?这4款千万不要错过。

PDF文件在生活中被我们大量使用&#xff0c;所以编辑PDF文件也是常有的事。平时我们用的文档编辑器不一定能够编辑PDF。这个时候就需要使用专业的PDF 编辑器&#xff0c;下面这几款工具就可以帮助我们直接对 PDF 文件中的内容进行编辑&#xff0c;可以有效的提高工作效率。 1、…

测序技术--组蛋白甲基化修饰、DNA亲和纯化测序,教授(优青)团队指导:从实验设计、结果分析到SCI论文辅助

组蛋白甲基化修饰工具(H3K4me3 ChIP-seq)组蛋白甲基化类型也有很多种&#xff0c;包括赖氨酸甲基化位点H3K4、H3K9、H3K27、H3K36、H3K79和H4K20等。组蛋白H3第4位赖氨酸的甲基化修饰(H3K4)在进化上高度保守&#xff0c;是被研究最多的组蛋白修饰之一。 DNA亲和纯化测序 DNA亲…

JPA+Thymeleaf

创建项目:创建一个crm项目 添加依赖: <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http:/…

C++ | Leetcode C++题解之第420题强密码检验器

题目&#xff1a; 题解&#xff1a; class Solution { public:int strongPasswordChecker(string password) {int n password.size();bool has_lower false, has_upper false, has_digit false;for (char ch: password) {if (islower(ch)) {has_lower true;}else if (isu…