我的编程空间,编程开发者的网络收藏夹
学习永远不晚

【Java 注解】自定义注解(注解属性与使用)

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

【Java 注解】自定义注解(注解属性与使用)

文章目录


前言

Java注解是一种元数据(metadata)机制,它提供了在Java代码中添加附加信息的方式。注解可以应用于类、方法、字段和其他程序元素,以提供关于这些元素的额外信息。
注解以 @ 符号开头,后面跟着注解的名称。注解可以包含属性,属性可以带有默认值。使用注解时,可以为属性提供值,也可以使用默认值。
注解可以用于各种目的,例如:

  • 提供编译时的静态检查和验证。
  • 在运行时通过反射获取元数据信息。
  • 自动生成代码或配置文件。
  • 在框架和库中进行配置和扩展。
    Java提供了一些内置的注解,如 @Override@Deprecated@SuppressWarnings 。此外,开发人员还可以自定义注解,以满足特定的需求。
    通过使用注解,可以在代码中添加额外的信息,从而提供更多的灵活性和可读性,同时也可以为工具和框架提供更多的上下文信息。

一、自定义注解与元注解

分析 Java 中自带的 @Override 注解 , 源码如下 :

@Target(ElementType.METHOD)@Retention(RetentionPolicy.SOURCE)public @interface Override {}

注解分为两部分 :

  1. 元注解:
    元注解是专门用来注解其他注解的注解,听起来有些绕口,实际上就是专门为自定义注解提供的注解。java.lang.annotation提供了五种元注解:
    @Documented – 注解是否将包含在JavaDoc中
    @Retention – 什么时候使用该注解
    @Target – 注解用于什么地方
    @Inherited – 是否允许子类继承该注解
    @Repeatable - 是否可重复注解,jdk1.8引入
  2. 自定义注解:public @interface 注解名称 ;
    除了上面的元注解其他的注解其实都是自定义注解。
    这里不准备深入介绍以上四个元注解的作用,大家可以自行学习。

本文即将提到的几个例子,都是在日常工作中真实使用到的场景,这例子有一个共同点,那就是都用到了Spring的AOP技术。

什么是AOP以及他的用法相信很多人都知道,这里也就不展开介绍了。

1.注解属性类型

注解属性 ( 接口方法 ) 返回值类型要求 :

① 基本数据类型 : byte , short , int , long , float , double , char , boolean ;

② 字符串类型 : String ;

③ 枚举类型 : enum ;

④ 注解类型 ;

⑤ 以上类型的数组形式 ;

注解属性返回值必须是以上的类型 , 不能设置其它类型返回值 , 否则会报错 ;

注解中定义了属性 , 在使用注解时 , 需要 给 注解属性 赋值;

定义 注解属性 时 , 可以 使用 default 关键字 指定属性默认值 , 下面代码中 , 制定 注解属性 intValue 值类型为 int 整型 , 默认值 88;

int intValue() default 88

如果 注解属性 指定了默认值 , 在使用注解时 , 可以选择 不为该属性赋值 ( 此时使用默认属性值 ) , 也可以进行赋值 ( 指定一个新的属性值 ) ;

如果 注解属性 没有指定默认值 , 则使用 注解 时 , 必须为其指定一个默认值 , 否则编译时报错 ;

数组类型 的 注解属性 赋值 时 , 使用大括号进行赋值 , 大括号内是数组元素 , 如果只有一个属性 , 可以省略大括号 ,

注解声明示例 :

public @interface Annotation {        String stringValue();        int intValue() default 88;        Number enumValue();        Annotation2 annotationValue();        String[] stringArrayValue();}

枚举类:

public enum Number {    ONE, TWO, THREE}

Annotation2 注解类 :

public @interface Annotation2 {// 自定义属性可以为空,只声明一个自定义注解}

自定义注解使用:

public class Example{         // 如果你的注解定义了属性,在引用时这些属性都是不可缺少的    @Annotation(            stringValue = "tom",            enumValue = Number.ONE,            annotationValue = @Annotation2,            stringArrayValue = {"tom", "jerry"})    Student(String name, int age){    }    @SuppressWarnings("all")    @Override    public String toString() {        return super.toString();    }}

代码分析 : 重点关注注解的使用 , 使用注解时 , 需要给 没有默认值 的 注解属性 赋值 , 格式为 注解属性名称 = 对应类型属性值 , 如果 注解属性 有默认值 , 则

@Annotation(stringValue = "tom", enumValue = Number.ONE, stringArrayValue = {"tom", "jerry"})

二、注解的生命周期以及作用目标

1.生命周期

通过@Retention定义注解的生命周期,格式如下:

@Retention(RetentionPolicy.SOURCE)

其中RetentionPolicy的不同策略对应的生命周期如下:

RetentionPolicy.SOURCE : 仅存在于源代码中,编译阶段会被丢弃,不会包含于class字节码文件中。@Override, @SuppressWarnings都属于这类注解。
RetentionPolicy.CLASS : 默认策略,在class字节码文件中存在,在类加载的时被丢弃,运行时无法获取到。
RetentionPolicy.RUNTIME : 始终不会丢弃,可以使用反射获得该注解的信息。自定义的注解最常用的使用方式。

2.作用目标

通过@Target定义注解作用的目标,比如作用于类、属性、或方法等,默认可用于任何地方。格式如下:

@Target(ElementType.TYPE)

对应ElementType参数值适用范围如下:

  • ElementType.TYPE: 类、接口、注解、enum
  • ElementType.CONSTRUCTOR: 构造函数
  • ElementType.FIELD: 成员变量、对象、属性、枚举的常量
  • ElementType.LOCAL_VARIABLE: 局部变量
  • ElementType.METHOD: 方法
  • ElementType.PACKAGE: 包
  • ElementType.PARAMETER: 参数
  • ElementType.ANNOTATION_TYPE): 注解
  • ElementType.TYPE_PARAMETER:类型参数,表示这个注解可以用在 Type的声明式前,jdk1.8引入。
  • ElementType.TYPE_USE:类型的注解,表示这个注解可以用在所有使用Type的地方(如:泛型,类型转换等),jdk1.8引入。

Documented
@Documented,表示是否将此注解的相关信息添加到javadoc文档中。

Inherited
@Inherited,定义该注解和子类的关系,使用此注解声明出来的自定义注解,在使用在类上面时,子类会自动继承此注解,否则,子类不会继承此注解。注意,使用Inherited声明出来的注解,只有在类上使用时才会有效,对方法,属性等其他无效。


三,简单使用

结合aop使用,完成一个当方法抛出异常时发送通知:

package com.kimo.shop.admin.aop;import org.aspectj.lang.JoinPoint;import org.aspectj.lang.annotation.AfterThrowing;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Pointcut;import org.springframework.stereotype.Component;@Aspect@Componentpublic class AbnormalAspect {    @AfterThrowing(value = "@annotation(com.kimo.shop.admin.aop.AbnormalAnnotations)",throwing = "exception")    public void afterThrowing(JoinPoint joinPoint,Exception exception){        // get joinPoint methodName        String methodName = joinPoint.getSignature().getName();        // get joinPoint className        String className = joinPoint.getTarget().getClass().getName();        // Get the exception information        String exceptionMessage = exception.getMessage();        // // Perform other operations, such as querying switch status and sending notifications        System.out.println("方法 " + methodName + " 在类 " + className + " 中抛出了异常");        System.out.println("异常信息:" + exceptionMessage);// 当你需要从自定义注解里面取出属性,可以看下面的方法//        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();//        Method method = methodSignature.getMethod();//        AbnormalAnnotations annotation = method.getAnnotation(AbnormalAnnotations.class);//        System.out.println("发生异常时间:" + annotation.date());    }}

第二个示例:通过注解进行赋值和通过注解进行校验。
两个注解:一个用来赋值,一个用来校验。

@Documented@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.FIELD,ElementType.METHOD})@Inheritedpublic @interface InitSex {    enum SEX_TYPE {MAN, WOMAN}    SEX_TYPE sex() default SEX_TYPE.MAN;}
@Documented@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.FIELD,ElementType.METHOD})@Inheritedpublic @interface ValidateAge {        int min() default 18;        int max() default 99;        int value() default 20;}

定义数据模型
这里用User类来表示具体待处理的数据对象。

public class User {    private String username;    @ValidateAge(min = 20, max = 35, value = 22)    private int age;    @InitSex(sex = InitSex.SEX_TYPE.MAN)    private String sex;    // 省略getter/setter方法}

测试调用
具体测试调用的过程,参考代码中的注解,其中initUser方法来演示通过反射给属性赋值,checkUser方法通过反射拿到当前属性的值进行对比校验。

import java.lang.reflect.Field;public class TestInitParam {    public static void main(String[] args) throws IllegalAccessException {        User user = new User();        initUser(user);        // 年龄为0,校验为通过情况        boolean checkResult = checkUser(user);        printResult(checkResult);        // 重新设置年龄,校验通过情况        user.setAge(22);        checkResult = checkUser(user);        printResult(checkResult);    }    static void initUser(User user) throws IllegalAccessException {        // 获取User类中所有的属性(getFields无法获得private属性)        Field[] fields = User.class.getDeclaredFields();        // 遍历所有属性        for (Field field : fields) {            // 如果属性上有此注解,则进行赋值操作            if (field.isAnnotationPresent(InitSex.class)) {                InitSex init = field.getAnnotation(InitSex.class);                field.setAccessible(true);                // 设置属性的性别值                field.set(user, init.sex().toString());                System.out.println("完成属性值的修改,修改值为:" + init.sex().toString());            }        }    }    static boolean checkUser(User user) throws IllegalAccessException {        // 获取User类中所有的属性(getFields无法获得private属性)        Field[] fields = User.class.getDeclaredFields();        boolean result = true;        // 遍历所有属性        for (Field field : fields) {            // 如果属性上有此注解,则进行赋值操作            if (field.isAnnotationPresent(ValidateAge.class)) {                ValidateAge validateAge = field.getAnnotation(ValidateAge.class);                field.setAccessible(true);                int age = (int) field.get(user);                if (age < validateAge.min() || age > validateAge.max()) {                    result = false;                    System.out.println("年龄值不符合条件");                }            }        }        return result;    }    static void printResult(boolean checkResult) {        if (checkResult) {            System.out.println("校验通过···");        } else {            System.out.println("校验未通过···");        }    }}

打印日志

完成属性值的修改,修改值为:MAN
年龄值不符合条件
校验未通过···
校验通过···

四,注解属性赋值简化

如果注解属性名称是 value , 并且注解中只有1个属性 , 那么在使用注解为注解属性赋值时 , 可以省略注解名称 , 直接传入注解属性值;

示例 : JDK 自带的 SuppressWarnings 注解:

@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})@Retention(RetentionPolicy.SOURCE)public @interface SuppressWarnings {    String[] value();}

注解使用 : 使用 SuppressWarnings 注解时 , 直接传入 “all” 参数 , 省略了注解属性名称:

    @SuppressWarnings("all")    @Override    public String toString() {        return super.toString();    }

满足两个条件 , 才能使用上述简化方式 ;

来源地址:https://blog.csdn.net/m0_71621983/article/details/131816443

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

【Java 注解】自定义注解(注解属性与使用)

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Java注解怎么自定义使用

这篇文章主要介绍了Java注解怎么自定义使用的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Java注解怎么自定义使用文章都会有所收获,下面我们一起来看看吧。注解注解基本介绍注解概述:Java 注解(Annota
2023-07-05

详解Java中自定义注解的使用

Annontation是Java5开始引入的新特征,中文名称叫注解,它提供了一种安全的类似注释的机制,用来将任何的信息或元数据(metadata)与程序元素(类、方法、成员变量等)进行关联。本文主要介绍了自定义注解的使用,希望对大家有所帮助
2023-03-20

Java自定义注解的详解

Java自定义注解Java注解提供了关于代码的一些信息,但并不直接作用于它所注解的代码内容。在这个教程当中,我们将学习Java的注解,如何定制注解,注解的使用以及如何通过反射解析注解。Java1.5引入了注解,当前许多java框架中大量使用
2023-05-31

Java中自定义注解如何使用

本文小编为大家详细介绍“Java中自定义注解如何使用”,内容详细,步骤清晰,细节处理妥当,希望这篇“Java中自定义注解如何使用”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。什么是注解在早期的工作的时候 ,自定义
2023-07-05

Java怎么自定义注解

这篇文章主要介绍“Java怎么自定义注解”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Java怎么自定义注解”文章能帮助大家解决问题。注解注解为我们在代码中添加信息提供一种形式化的方法,使我们可以在
2023-07-05

Java教程:JAVA自定义注解

注解概念注解是Java SE 5.0版本开始引入的概念,它是对java源代码的说明,是一种元数据(描述数据的数据)。注解和注释的不同注释注释是对代码的说明,给代码的读者看,便于帮读者梳理业务逻辑;在程序代码中经常看到的以@ 开头的大部分是注
2023-06-02

Java中的注解(Annotation)有什么作用?如何自定义注解?(Java注解的功能是什么?如何定义自己的注解?)

Java注解用于提供附加信息,不会影响代码行为。它们用于:文档化代码代码分析代码生成运行时行为修改自定义注解通过@Retention和@Target指定范围和应用元素,并使用@Documented和@Inherited控制文档和继承行为。在使用时,通过@AnnotationName(value)语法应用注解。通过反射可以在运行时访问自定义注解。最佳实践包括保持简洁、使用标准化命名、避免过度使用和详细文档化。
Java中的注解(Annotation)有什么作用?如何自定义注解?(Java注解的功能是什么?如何定义自己的注解?)
2024-04-02

java中怎么自定义注解详解

在Java中,可以使用`@interface`关键字来定义注解。自定义注解的语法如下:public @interface CustomAnnotation {String value() default "";int number() d
java中怎么自定义注解详解
2023-10-28

怎么用自定义注解

本篇内容介绍了“怎么用自定义注解”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!基本知识在Java中,注解分为两种,元注解和自定义注解。很多人
2023-06-16

浅析Java自定义注解的用法

注解为我们在代码中添加信息提供一种形式化的方法,使我们可以在源码、编译时、运行时非常方便的使用这些数据。本文主要为大家介绍了Java自定义注解的用法,希望对大家有所帮助
2023-03-21

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录