Java自定义注解Annotation的使用
从 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 ,所以MT4下载教程前者能作用的地方后者一定也能作用。一般如果需要在运行时去动态获取注解信息,那只能用 RUNTIME 注解;如果要在编译时进行一些预处理操作,比如生成一些辅助代码(如 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自定义注解Annotation的使用的更多相关文章
- JAVA自定义注解 ------ Annotation
日常开发工作中,合理的使用注解,可以简化代码编写以及使代码结构更加简单,下面记录下,JAVA自定义注解的开发过程. 定义注解声明类. 编写注解处理器(主要起作用部分). 使用注解. 相关知识点介绍, ...
- Java自定义注解Annotation详解
注解相当于一种标记,在程序中加了注解就等于为程序打上了某种标记,没加,则等于没有某种标记,以后,javac编译器,开发工具和其他程序可以用反射来了解你的类及各种元素上有无何种标记,看你有什么标记,就去 ...
- java自定义注解类
一.前言 今天阅读帆哥代码的时候,看到了之前没有见过的新东西, 比如java自定义注解类,如何获取注解,如何反射内部类,this$0是什么意思? 于是乎,学习并整理了一下. 二.代码示例 import ...
- java自定义注解实现前后台参数校验
2016.07.26 qq:992591601,欢迎交流 首先介绍些基本概念: Annotations(also known as metadata)provide a formalized way ...
- Java Android 注解(Annotation) 及几个常用开源项目注解原理简析
不少开源库(ButterKnife.Retrofit.ActiveAndroid等等)都用到了注解的方式来简化代码提高开发效率. 本文简单介绍下 Annotation 示例.概念及作用.分类.自定义. ...
- java自定义注解知识实例及SSH框架下,拦截器中无法获得java注解属性值的问题
一.java自定义注解相关知识 注解这东西是java语言本身就带有的功能特点,于struts,hibernate,spring这三个框架无关.使用得当特别方便.基于注解的xml文件配置方式也受到人们的 ...
- Java自定义注解的实现
Java自定义注解的实现,总共三步(eg.@RandomlyThrowsException): 1.首先编写一个自定义注解@RandomlyThrowsException package com.gi ...
- Java自定义注解源码+原理解释(使用Java自定义注解校验bean传入参数合法性)
Java自定义注解源码+原理解释(使用Java自定义注解校验bean传入参数合法性) 前言:由于前段时间忙于写接口,在接口中需要做很多的参数校验,本着简洁.高效的原则,便写了这个小工具供自己使用(内容 ...
- Java自定义注解和运行时靠反射获取注解
转载:http://blog.csdn.net/bao19901210/article/details/17201173/ java自定义注解 Java注解是附加在代码中的一些元信息,用于一些工具在编 ...
随机推荐
- ORACLE 11G新特性之一(增加带default的字段)
在11g之前,增加带default值的字段,实现原理如下: alter table t1 add c1 varchar2(20) default 'XX' not null; 假设t1表有4千万行数据 ...
- OpenCV常用基本处理函数(3)颜色空间
颜色空间转换 对图像进行颜色空间转换,比如从 BGR 到灰度图,或者从BGR 到 HSV 等 我们要用到的函数是:cv2.cvtColor(input_image ,flag),其中 flag就是转换 ...
- Anaconda基本命令
创建环境 conda create --name bunnies python=3 astroid babel 列出所有环境 conda info --envs 或 conda env list 克隆 ...
- Mac上使用频率最高的七组快捷键
不管Mac还是Windows,会使用快捷键都能让你的工作效果提升不少,但是快捷键那么多一下子全部记下来也不太实际,这里小编就整理了七组使用频率最高的快捷键,希望可以帮到大家. https://www. ...
- docker 运行springboot jar包
1.将jar包移至自定义的/usr/jar目录下; 2.在/usr/jar目录下创建Dockerfile文件 文件如下: #FROM命令定义构建镜像的基础镜像,该条必须是dockerfile的首个命令 ...
- bootsrap 按钮样式
<!-- Standard button --> <button type="button" class="btn btn-default"& ...
- C# GDI+简单绘图
一.使用Pen画笔 Pen的主要属性有: Color(颜色),DashCap(短划线终点形状),DashStyle(虚线样式),EndCap(线尾形状), StartCap(线头形状),Width(粗 ...
- 洛谷P1122 最大子树和 (树状dp)
题目描述 小明对数学饱有兴趣,并且是个勤奋好学的学生,总是在课后留在教室向老师请教一些问题.一天他早晨骑车去上课,路上见到一个老伯正在修剪花花草草,顿时想到了一个有关修剪花卉的问题.于是当日课后,小明 ...
- 外部表及oracle数据库内存
create table alert1 (log varchar2(1000))2 organization external3 (type oracle_loader4 default direct ...
- 51nod1340地铁环线
经典题. 经典差分约束模型. 但是 显然这个总长是有上下界的. 直接二分总长,判断有没有负环 如果没有负环好办,有负环就不知道怎么偏了. 因为没有单调性! (如果所有没有单调性的函数图像,都知道往哪里 ...