首页 > 编程语言 >Java自定义注解(Annontation)

Java自定义注解(Annontation)

时间:2023-05-25 21:11:53浏览次数:50  
标签:Java 自定义 User user Annontation 注解 ElementType class 属性

(一)注解简介

注解(Annontation),Java5引入的新特性,位于java.lang.annotation包中。提供了一种安全的类似注释的机制,用来将任何的信息或元数据(metadata)与程序元素(类、方法、成员变量等)进行关联。是一种说明、配置、描述性的信息,与具体业务无关,也不会影响正常的业务逻辑。但我们可以用反射机制来进行校验、赋值等操作。

1.注解的常见用途:

  1. 生成文档的注解,如@author,@param。
  2. 跟踪代码依赖性,实现替代配置文件功能,如spring mvc的注解。
  3. 编译时进行格式检查,如@override。
  4. 编译时进行代码生成补全,如lombok插件的@Data。

(二)注解基础知识

1.注解的定义

  1. 注解的定义通过@interface表示,所有的注解会自动继承java.lang.Annotation接口,且不能再继承别的类或是接口。
  2. 注解的成员参数只能用public或默认(default) 访问权修饰来进行修饰。
  3. 成员参数只能使用八种基本类型(byte、short、char、int、long、float、double、boolean)和String、Enum、Class、annotations等数据类型,及其数组。
  4. 获取类方法和字段的注解信息,只能通过Java的反射技术来获取 Annotation 对象。
  5. 注解可以没有定义成员,只做标识。

2.元注解

元注解是专门用来注解其他注解的注解,听起来有些绕口,实际上就是专门为自定义注解提供的注解。java.lang.annotation提供了四种元注解:

  1. @Documented – 注解是否将包含在JavaDoc中
  2. @Retention – 什么时候使用该注解
  3. @Target – 注解用于什么地方
  4. @Inherited – 是否允许子类继承该注解
  5. @Repeatable - 是否可重复注解,jdk1.8引入

3.注解的生命周期

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

@Retention(RetentionPolicy.SOURCE)

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

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

4.注解的作用目标

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

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

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

5.Documented

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

6.Inherited

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

(三)实例

自定义注解

这里定义两个注解,一个用来赋值,一个用来校验。
/**
 * 性别赋值
 * @author zzs
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD,ElementType.METHOD})
@Inherited
public @interface InitSex {
    /**
     * sex enum
     * @author zzs
     */
    enum SEX_TYPE {MAN, WOMAN}
    SEX_TYPE sex() default SEX_TYPE.MAN;
}
/**
 * 年龄校验
 * @author zzs
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD,ElementType.METHOD})
@Inherited
public @interface ValidateAge {
    /**
     * 最小值
     */
    int min() default 18;
    /**
     * 最大值
     */
    int max() default 99;
    /**
     * 默认值
     */
    int value() default 20;
}

定义数据模型

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

/**
 * user
 *
 * @author zzs
 */
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;
/**
 * @author zzs
 */
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
年龄值不符合条件
校验未通过
校验通过

 

标签:Java,自定义,User,user,Annontation,注解,ElementType,class,属性
From: https://www.cnblogs.com/imreW/p/17432942.html

相关文章

  • mongodb(5)--使用Java操作MongoDB
    一、环境的准备1、MongoDB已经安装完成2、java环境准备(1)jdk:oracle官网:https://www.oracle.com/java/technologies/downloads/(2)开发工具:  eclipse官网:https://www.eclipse.org/  idea官网:https://www.jetbrains.com.cn/idea/3、选择MongoDBJDBC驱动https://mongodb.gi......
  • JavaScript中的生成器函数(Generator Functions)
    简介:生成器函数(GeneratorFunctions)是JavaScript中的一种特殊类型函数,它允许开发者在函数内部产生多个值并逐步返回,与传统函数一次返回单个值的方式不同。本文将介绍生成器函数的特性、优缺点以及如何使用它们,并提供一些代码案例来说明其用法。特性:使用function\*关键字声明:生成......
  • Java面向对象(高级)
    1、类变量类变量是被类的所有实例共享的。类变量具体放的位置在哪?在内存中的那个区域,这和jdk的版本是有关的静态变量在类加载的时候就生成了,即使没有创建类实例也能访问,当然通过实例来实现类变量定义访问修饰符static类型变量名2、类方法1、只需要在普通方法前面加上......
  • java反射代码案例
    反射案例代码点击查看代码packagecom.bh.zoo;publicclassWolfextendsAnimal{publicStringname;publicStringcolor;protectedStringblood;privateintage;publicvoideat(){System.out.println("狼吃肉");}public......
  • 自定义频率类
    自定义频率类classSuperThrottle(BaseThrottle):VISIT_RECORD={}def__init__(self):self.history=Nonedefallow_request(self,request,view):#自己写逻辑,判断是否超频#(1)取出访问者ip#(2)判断当前ip不在访问字典......
  • Java比较两个实体属性值是否相同,将不同的属性输出
    /** *比较两个实体属性值,返回一个map以有差异的属性名为key,value为一个Map分别存oldObject,newObject此属性名的值 *@paramoldObject进行属性比较的对象1 *@paramnewObject进行属性比较的对象2 *@return属性差异比较结果map */ @SuppressWarnings("rawtypes")......
  • JAVA List和Map切割方法
    importorg.springframework.util.CollectionUtils;importjava.util.ArrayList;importjava.util.HashMap;importjava.util.Iterator;importjava.util.List;importjava.util.Map;importjava.util.Set;publicclassCollectionUtil{/***将map切成段,作......
  • java两个对象属性比较
    两个对象进行比较相等,有两种做法:1,情况一:当仅仅只是判断两个对象是否相等时,只需重写equals()方法即可。这里就不用说明2.情况二:当除了情况一之外,还需知道是那个属性不同,那么就需要采用类反射,具体代码如下:publicstaticvoidmain(String[]args){Aa=newA();a.setUserName(......
  • IDEA下查看Java字节码(插件ByteCode Viewer)
    安装jclasslibbytecodeviewer插件 使用结果......
  • jenkins--构建传输jar包后启动java服务
    jenkins--构建传输jar包后启动java服务目标:针对单体java服务前置条件:jdk1.8日志切割cronologjdk1.8安装cronolog安装创建server.sh脚本文件#!/bin/bashJAR_PATH="/data/forwarder"#文件目录JAR_FILE="ruoyi-admin.jar"#文件名LOG_PATH="/data/forwarder/logs"#cro......