绑定完请刷新页面
取消
刷新

分享好友

×
取消 复制
Java自定义注解Annotation的使用
2019-10-10 11:36:16

从 jdk5 开始, Java 增加了对元数据的支持,也就是 Annotation , Annotation 其实就是对代码的一种特殊标记,这些标记可以在编译,类加载和运行时被读取,并执行相应的处理。当然刚刚说了, Annotation 只是一种标记,所以要是在代码里面不用这些标记也是能完成相应的工作的,只是有时候用注解能简化很多代码,看起来非常的简洁。

常见的注解(Annotation )

@Override ——限定重写父类方法

@Deprecated ——标示已过时

@SuppressWarning ——抑制编译器警告

JAVA 的元注解

除了上面的注解,还有元注解。元注解是指注解的注解,包括@Retention @Target @Document @Inherited 四种。

1.@Retention 这个是决定你 Annotation 存活的时间的,它包含一个 RetationPolicy 的 value 成员变量,用于指定它所修饰的 Annotation 保留时间,一般有 :

1. Retationpolicy.CLASS :编译器将把注解记录在 Class 文件中,

不过当java 程序执行的时候, JVM 将抛弃它。不过当 java 程序执行的时候, JVM 将抛弃它。

2. Retationpolicy.SOURCE : 默认的保留策略,注解会在 class 字节码文件中存在,但运行时无法获得。

4. Retationpolicy.RUNTIME : 在 Retationpolicy.CLASS 的基础上, JVM 执行的时候也不会抛弃它,所以我们一般在程序中可以通过反射来获得这个注解,然后进行处理。

首先要明确生命周期长度 SOURCE < CLASS < RUNTIME ,所以前者能作用的地方后者一定也能作用。一般如果需要在运行时去动态获取注解信息,那只能用 RUNTIME 注解;如果要在外汇返佣http://www.kaifx.cn/编译时进行一些预处理操作,比如生成一些辅助代码(如 ButterKnife ),就用 CLASS 注解;如果只是做一些检查性的操作,比如 @Override 和 @SuppressWarnings ,则可选用 SOURCE 注解。

2.@Target 这个注解一般用来指定被修饰的注解修饰哪些元素,如下:

ElementType.ANNOTATION_TYPE : // 注解

ElementType.CONSTRUCTOR: // 构造函数

ElementType.FIELD: // 字段、枚举的常量

ElementType.LOCAL_VARIABLE: // 局部变量

ElementType.METHOD: // 方法

ElementType.PACKAGE: // 包   

ElementType.PARAMETER:// 方法参数

ElementType.TYPE: // 接口、类、枚举、注解

@Document 这个注解修饰的 Annotation 类可以被 javadoc 工具提取成文档

@Inherited 被他修饰的注解具有继承性,说明子类可以继承父类中的该注解

例子

自定义注解MyClassAnnotation

@Retention(RetentionPolicy.RUNTIME)  

@Target(ElementType.TYPE)  

public @interface MyClassAnnotation {

String value();

}

自定义注解MyFieldAnnotation

@Retention(RetentionPolicy.RUNTIME)  

@Target(ElementType.FIELD)  

public @interface MyFieldAnnotation {

public String name() default "fieldName";

}

自定义注解MyMethodAnnotation

@Retention(RetentionPolicy.RUNTIME)  

@Target(ElementType.METHOD)  

public @interface MyMethodAnnotation {

      String name();

      int age();

}

在实例中使用TestRuntimeAnnotation 来测试注解情况:

@MyClassAnnotation(value = "test Class")

public class TestRuntimeAnnotation {

    @MyFieldAnnotation

    public String fieldInfo = "FiledInfo";  

@MyMethodAnnotation(age = 0, name = "zhangsan")

    public static String getMethodInfo() {  

        return TestRuntimeAnnotation.class.getSimpleName();  

    }   

    public static void main(String[]args) {

        StringBuffer sb = new StringBuffer();  

        Class<?> cls = TestRuntimeAnnotation.class;  

sb.append("Class 注解: ").append("\n");  

        MyClassAnnotation myClassAnnotation = cls.getAnnotation(MyClassAnnotation.class);  

        if (myClassAnnotation != null) {  

            sb.append(Modifier.toString(cls.getModifiers())).append(" ")  

                    .append(cls.getSimpleName()).append("\n");  

sb.append(" 注解值 : ").append(myClassAnnotation.value()).append("\n\n");  

        }

sb.append("Field 注解: ").append("\n");  

        Field[] fields = cls.getDeclaredFields();  

        for (Field field : fields) {  

         MyFieldAnnotation fieldInfo = field.getAnnotation(MyFieldAnnotation.class);  

            if (fieldInfo != null) {  

                sb.append(Modifier.toString(field.getModifiers())).append(" ")  

                        .append(field.getType().getSimpleName()).append(" ")  

                        .append(field.getName()).append("\n");  

sb.append(" 注解值 : ").append(fieldInfo.name()).append("\n\n");  

            }  

        }  

      sb.append("Method 注解: ").append("\n");  

        Method[] methods = cls.getDeclaredMethods();  

        for (Method method : methods) {  

         MyMethodAnnotation methodInfo = method.getAnnotation(MyMethodAnnotation.class);  

            if (methodInfo != null) {  

                sb.append(Modifier.toString(method.getModifiers())).append(" ")  

                        .append(method.getReturnType().getSimpleName()).append(" ")  

                        .append(method.getName()).append("\n");  

sb.append(" 注解值 : ").append("\n");  

                sb.append("name: ").append(methodInfo.name()).append("\n");  

                sb.append("age: ").append(methodInfo.age()).append("\n");  

            }  

        }  

        System.out.print(sb.toString());  

    }

}

测试结果如下:

Class 注解:

public TestRuntimeAnnotation

注解值: test Class

Field 注解:

public String fieldInfo

注解值: fieldName

Method 注解:

public static String getMethodInfo

注解值:

name: zhangsan

age: 0

定义注解

该注解可以验证成员属性是否为空,长度,提供了几种常见的正则匹配,也可以使用自定义的正则去判断属性是否合法,同时可以为该成员提供描述信息。

定义注解

该注解可以验证成员属性是否为空,长度,提供了几种常见的正则匹配,也可以使用自定义的正则去判断属性是否合法,同时可以为该成员提供描述信息。

package org.xdemo.validation.annotation;

import java.lang.annotation.ElementType;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;

import org.xdemo.validation.RegexType;

/**

* 数据验证

 * @author Goofy

 */

@Retention(RetentionPolicy.RUNTIME)

@Target({ElementType.FIELD,ElementType.PARAMETER})

public @interface DV {  

// 是否可以为空

    boolean nullable() default false;

// 大长度

    int maxLength() default 0;

// 小长度

    int minLength() default 0;

// 提供几种常用的正则验证

    RegexType regexType() default RegexType.NONE;

// 自定义正则验证

    String regexExpression() default "";

// 参数或者字段描述 , 这样能够显示友好的异常信息

    String description() default "";

}

注解的解析

package org.xdemo.validation.annotation.support;

import java.lang.reflect.Field;

import org.xdemo.validation.RegexType;

import org.xdemo.validation.annotation.DV;

import org.xdemo.validation.utils.RegexUtils;

import org.xdemo.validation.utils.StringUtils;

/**

* 注解解析

 * @author Goofy

 */

public class ValidateService {

     

    private static DV dv;

     

    public ValidateService() {

        super();

    }

// 解析的入口

    public static void valid(Object object) throws Exception{

// 获取 object 的类型

        Class<? extends Object> clazz=object.getClass();

// 获取该类型声明的成员

        Field[] fields=clazz.getDeclaredFields();

// 遍历属性

        for(Field field:fields){

// 对于 private 私有化的成员变量,通过 setAccessible 来修改器访问权限

            field.setAccessible(true);

            validate(field,object);

// 重新设置会私有权限

            field.setAccessible(false);

        }

    }  

    public static void validate(Field field,Object object) throws Exception{

        String description;

        Object value;

// 获取对象的成员的注解信息

        dv=field.getAnnotation(DV.class);

        value=field.get(object);

        if(dv==null)return;

        description=dv.description().equals("")?field.getName():dv.description();

/************* 注解解析工作开始 ******************/

        if(!dv.nullable()){

            if(value==null||StringUtils.isBlank(value.toString())){

throw new Exception(description+" 不能为空 ");

            }

        }

        if(value.toString().length()>dv.maxLength()&&dv.maxLength()!=0){

throw new Exception(description+" 长度不能超过 "+dv.maxLength());

        }

         

        if(value.toString().length()<dv.minLength()&&dv.minLength()!=0){

throw new Exception(description+" 长度不能小于 "+dv.minLength());

        }

        if(dv.regexType()!=RegexType.NONE){

            switch (dv.regexType()) {

                case NONE:

                    break;

                case SPECIALCHAR:

                    if(RegexUtils.hasSpecialChar(value.toString())){

throw new Exception(description+" 不能含有特殊字符 ");

                    }

                    break;

                case CHINESE:

                    if(RegexUtils.isChinese2(value.toString())){

throw new Exception(description+" 不能含有中文字符 ");

                    }

                    break;

                case EMAIL:

                    if(!RegexUtils.isEmail(value.toString())){

throw new Exception(description+" 地址格式不正确 ");

                    }

                    break;

                case IP:

                    if(!RegexUtils.isIp(value.toString())){

throw new Exception(description+" 地址格式不正确 ");

                    }

                    break;

                case NUMBER:

                    if(!RegexUtils.isNumber(value.toString())){

throw new Exception(description+" 不是数字 ");

                    }

                    break;

                case PHONENUMBER:

                    if(!RegexUtils.isPhoneNumber(value.toString())){

throw new Exception(description+" 不是数字 ");

                    }

                    break;

                default:

                    break;

            }

        }

        if(!dv.regexExpression().equals("")){

            if(value.toString().matches(dv.regexExpression())){

throw new Exception(description+" 格式不正确 ");

            }

        }

/************* 注解解析工作结束 ******************/

    }

}

用到的几个类

package org.xdemo.validation;

/**

* 常用的数据类型枚举

 * @author Goofy

 *

 */

public enum RegexType {

     

    NONE,

    SPECIALCHAR,

    CHINESE,

    EMAIL,

    IP,

    NUMBER,

    PHONENUMBER;   

}

其中正则验证类和字符串工具类请参考以下链接:

SuperUtil 之 RegexUtils

SuperUtil 之 StringUtils

使用方法

package org.xdemo.validation.test;

import org.xdemo.validation.RegexType;

import org.xdemo.validation.annotation.DV;

public class User {

@DV(description=" 用户名 ",minLength=6,maxLength=32,nullable=false)

    private String userName;

     

    private String password;

@DV(description=" 邮件地址 ",nullable=false,regexType=RegexType.EMAIL)

    private String email;

public User(){}

    public User(String userName, String password, String email) {

        super();

        this.userName = userName;

        this.password = password;

        this.email = email;

    }

    public String getUserName() {

        return userName;

    }

    public void setUserName(String userName) {

        this.userName = userName;

    }

    public String getPassword() {

        return password;

    }

    public void setPassword(String password) {

        this.password = password;

    }

    public String getEmail() {

        return email;

    }

    public void setEmail(String email) {

        this.email = email;

    }

}

测试代码

import org.xdemo.validation.annotation.support.ValidateService;

/**

 * @author Goofy

 */

public class Test {

    public static void main(String[] args){

User user=new User(" 张三 ", "xdemo.org", "252878950@qq.com");

        try {

            ValidateService.valid(user);

        } catch (Exception e) {

            e.printStackTrace();

        }

        user=new User("zhangsan","xdemo.org","xxx@");

        try {

            ValidateService.valid(user);

        } catch (Exception e) {

            e.printStackTrace();

        }

        user=new User("zhangsan","xdemo.org","");

        try {

            ValidateService.valid(user);

        } catch (Exception e) {

            e.printStackTrace();

        }

    }

}

 

分享好友

分享这个小栈给你的朋友们,一起进步吧。

Java小专栏
创建时间:2019-08-08 21:32:06
Java专栏专注技术分享
展开
订阅须知

• 所有用户可根据关注领域订阅专区或所有专区

• 付费订阅:虚拟交易,一经交易不退款;若特殊情况,可3日内客服咨询

• 专区发布评论属默认订阅所评论专区(除付费小栈外)

栈主、嘉宾

查看更多
  • lihong
    栈主

小栈成员

查看更多
  • 栈栈
  • 杨三百
  • at_1
  • gaokeke123
戳我,来吐槽~