Java注解浅谈
来源:互联网 发布:电脑怎么连网络机顶盒 编辑:程序博客网 时间:2024/06/06 04:26
Java SE5内置了三种标准注解:
@Override,表示当前的方法定义将覆盖超类中的方法。 @Deprecated,使用了注解为它的元素编译器将发出警告,因为注解@Deprecated是不赞成使用的代码,被弃用的代码。 @SuppressWarnings,关闭不当编译器警告信息。
上面这三个注解多少我们都会在写代码的时候遇到。Java还提供了4中注解,专门负责新注解的创建。即元注解。
一.元注解。Java5.0定义的4种元注解:
1.@Target, 2.@Retention, 3.@Documented, 4.@Inherited下面,分别看看这4种注解的详细说明。
1.1 @Target。(注解用于什么地方)
@Target说明了Annotation所修饰的对象范围,注解用于什么地方。如果不明确指出,该注解可以放在任何地方。
作用:用于描述注解的使用范围(即:被描述的注解可以用在什么地方)
取值(ElementType)有:
CONSTRUCTOR:构造器的声明 FIELD:域声明(包括enum实例) LOCAL_VARIABLE:局部变量声明 METHOD:方法声明 PACKAGE:包声明 PARAMETER:参数声明 TYPE:类、接口(包括注解类型)或enum声明1.2 @Retention。(什么时候使用该注解。定义该注解的生命周期)
@Retention定义了该Annotation被保留的时间长短。表示需要在什么级别保存该注解信息。
作用:表示需要在什么级别保存该注释信息,用于描述注解的生命周期(即:被描述的注解在什么范围内有效)
取值(RetentionPoicy)有:
SOURCE: 注解将被编译器丢弃(在源文件中有效,即源文件保留)CLASS: 注解在class文件中可用,但会被VM丢弃(在class文件中有效,即class保留)RUNTIME:VM将在运行期间保留注解,因此可以通过反射机制读取注解的信息(在运行时有效,即运行时保留)1.3 @Documented。(将注解包含在Javadoc中)
@Documented一个简单的Annotations标记注解,表示是否将注解信息添加在java文档中。因此可以被javadoc此类的工具文档化。@Documented是一个标记注解,没有成员。有关标记注解,下文有说明。
1.4 @Inherited。(是否允许子类继承该注解)
@Inherited阐述了某个被标注的类型是被继承的。@Inherited是一个标记注解,没有成员。有关标记注解,下文有说明。
注意:@Inherited annotation类型是被标注过的class的子类所继承。类并不从它所实现的接口继承annotation,方法并不从它所重载的方法继承annotation。
二. 自定义注解。
使用@interface自定义注解。在定义注解时,不能继承其他的注解或接口。@interface用来声明一个注解,其中的每一个方法实际上是声明了一个配置参数。方法的名称就是参数的名称,返回值类型就是参数的类型(返回值类型只能是基本类型、Class、String、enum)。可以通过default来声明参数的默认值。
定义注解格式:
public @interface 注解名 {定义体}
注解参数的可支持数据类型:
1.所有基本数据类型(int,float,boolean,byte,double,char,long,short) 2.String类型 3.Class类型 4.enum类型 5.Annotation类型 6.以上所有类型的数组Annotation类型里面的参数该怎么设定:
第一,只能用public或默认(default)这两个访问权修饰.例如,String value();这里把方法设为defaul默认类型;
第二,参数成员数据类型如上所述;
第三,如果只有一个参数成员,最好把参数名称设为"value"。
实例代码:
@Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)public @interface Table {}
ps: 1. 没有元素的注解称为标记注解,上面的@Table就是一个标记注解。
2. 如果只有一个参数成员,最好把参数名称设为"value",例如,
@Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)public @interface Table {String value();}在使用注解时,可以不写属性名和等于号,直接写值即可,例如可以这么写@Table("user")。
自定义完注解后,最核心的东西便是要实现注解解析!注解解析主要是通过反射机制实现的。有关反射机制,可以看这篇文章,Java反射浅谈。此处不再详说。
三. 注解解析。
首先,看看JDK提供的有关注解相关的API方法,
3.1 isAnnotationPresent(Class<? extends Annotation> annotationClass),
如果指定的注解位于此元素上,则返回‘true’,否则返回‘false’。
3.2 <T extends Annotation> T getAnnotation(Class<T> annotationClass),
如果存在此注释,则返回此元素的指定类型的注释,否则为空。
3.3 Annotation[] getAnnotations(),
返回此元素上的所有注释。如果这个元素上没有注释,则返回值是一个长度为0的数组。此方法的调用方可以自由修改返回的数组;它将对返回给其他调用方的数组没有影响。
3.4 Annotation[] getDeclaredAnnotations(),
返回直接在该元素上的注释。此方法忽略了继承的注释。如果在这个元素上没有直接存在的注释,返回值是一个长度为0的数组。此方法的调用方可以自由修改返回的数组;它将对返回给其他调用方的数组没有影响。
下文,结合具体的场景,来实现注解以及注解解析。
从原理上讲,注解解析器就是通过反射机制获取被检查方法上的注解信息,然后根据注解元素的值进行特定的处理。
四. 注解实战。
打算使用注解生成SQL语句。
4.1 自定义注解。
(1) 自定义一个Table(表)注解,作用域是类,在运行时有效,只有一个属性,所有命名为‘value’,
@Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)public @interface Table {String value();}(2) 自定义一个Column(列)注解,作用域是类,在运行时有效,只有一个属性,所有命名为‘value’,
@Target({ElementType.FIELD})@Retention(RetentionPolicy.RUNTIME)public @interface Column {String value();}4.2 定义一个实体类,使用注解,具体代码如下,
@Table("user")public class User {@Column("id")private int id;@Column("user_name")private String userName;@Column("nick_name")private String nickName;@Column("age")private int age;@Column("city")private String city;@Column("email")private String email;@Column("mobile")private String mobile;public int getId() {return id;}public void setId(int id) {this.id = id;}public String getUserName() {return userName;}public void setUserName(String userName) {this.userName = userName;}public String getNickName() {return nickName;}public void setNickName(String nickName) {this.nickName = nickName;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getCity() {return city;}public void setCity(String city) {this.city = city;}public String getEmail() {return email;}public void setEmail(String email) {this.email = email;}public String getMobile() {return mobile;}public void setMobile(String mobile) {this.mobile = mobile;}}其中‘@Table("user")’表示数据库中表名,而类似‘@Column("id") private int id;’表示 该字段(属性)在表中对应的列名。
注解部分已经实现了,接下来就需要实现注解解析,具体代码如下,
4.3 注解解析,具体代码如下,
/** * 生成sql * @param f * @return */private static String query(Object f) {StringBuilder builder=new StringBuilder();//1 获取classClass c=f.getClass();//是否有Table注解boolean exists=c.isAnnotationPresent(Table.class);if(!exists){return null;}//2 获取table的名字Table t=(Table)c.getAnnotation(Table.class);String tableName=t.value();builder.append("select * from ").append(tableName).append(" where 1=1");//3 遍历所有字段Field[] fArray=c.getDeclaredFields();for(Field field:fArray){//4 处理每个字段对应的sql// //是否有Column注解boolean fExists=field.isAnnotationPresent(Column.class);if(!fExists){continue;}// 4.1 拿到字段名Column column=field.getAnnotation(Column.class);String columnName=column.value();//4.2 拿到字段值String fieldName=field.getName();String getMethodName="get"+fieldName.substring(0, 1).toUpperCase()+fieldName.substring(1); Method getMethod;Object fieldValue = null;try {getMethod = c.getMethod(getMethodName); fieldValue=(Object) getMethod.invoke(f);} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}//如果值为null或者值为Integer类型并且等于0,则不生成sqlif(fieldValue==null||(fieldValue instanceof Integer && (Integer)fieldValue==0)){continue;}// 4.3 组装sqlbuilder.append(" and ").append(fieldName);//if(fieldValue instanceof String){//生成模糊查询的sqlif(((String) fieldValue).contains(",")){String[] values=((String) fieldValue).split(",");builder.append(" in(");for (String v:values) {builder.append("'").append(v).append("'").append(",");}builder.deleteCharAt(builder.length()-1);builder.append(")");}else{builder.append("=").append("'").append(fieldValue).append("'");}}else if(fieldValue instanceof Integer){builder.append("=").append(fieldValue);}}return builder.toString();}代码都有注释,不多说了。下面,我们测试一下这个注解解析器生成的sql,
(1) 测试代码1,
public static void main(String[] args) {User f1=new User();f1.setId(10);User f2=new User();f2.setUserName("xingxing");User f3=new User();f3.setEmail("123456789@163.com");String sql1=query(f1);String sql2=query(f2);String sql3=query(f3);System.out.println(sql1);System.out.println(sql2);System.out.println(sql3);}运行结果截图如下,
(2) 测试代码2
public static void main(String[] args) {User f1=new User();f1.setEmail("123456789@163.com,wangwei@sina.com,zhuhe@qq.com");String sql1=query(f1);System.out.println(sql1);}运行结果截图如下,
通过注解生成的sql与我们想要的sql基本一致。
五、总结。
通过本篇文章,我们对注解有一个新的认识!如果你觉得很炫,那么赶紧动手吧!
- Java注解浅谈
- 浅谈java的注解
- Java注解浅谈
- 浅谈JAVA注解
- 浅谈java注解
- 浅谈关于Java的注解使用
- Spring @Resource注解浅谈
- 注解框架AndroidAnnotations浅谈
- 浅谈hibernate注解
- 浅谈Spring注解
- 注解(浅谈Dagger,ButterKnife,Roboguide)
- Java注解-自定义注解
- Java注解----自定义注解
- Java注解自定义注解
- Java注解--四种元注解
- Java注解-三种內建注解
- 【Java】【注解】自定义注解
- java注解
- 轻量级模式(Flyweight Pattern)
- JMeter Badboy 脚本录制
- Android home/up 按钮
- Redis ZADD命令
- Java NIO与阻塞IO的研究
- Java注解浅谈
- 使用MAT分析内存泄漏(一)
- va_start和va_end的使用
- concurrent - ReentrantReadWriteLock - learning
- VS2015,error:C2664
- iOS左侧滑动返回
- 自己写的RxBus,写的不是很好勿喷
- Spring整合activeMq(二):发布订阅模式
- QQZiFramework笔记:entityTable与erp.public.js使用方法之常归篇