在现实生活中,贴标签这种现象比比皆是。去超市,去商场,每个或者每类物品都会有它的标签,甚至在我们自己身上也会有标签,比如,程序猿、逗逼、单身狗、80/90后、屌丝……呵呵,太多了。有时候,我们也会戏谑朋友同事,给他们贴个标签逗逗乐。但是这篇的正题是注解,下面我会说说为什么我理解的注解就是贴标签,虽然有时候也会称它为“扣帽子”。
元注解
在java提供了四个元注解,元注解就是注解的注解。它们是:
1[email protected], 2[email protected], 3[email protected], [email protected]
在我们刚出生的时候,就已经被贴上标签了,我们的户籍按照地域划分,会被贴上河南河北、山东山西、湖南湖北等等23个省和四个直辖市中的其中一个。另外在我们的生命过程中也会经历标签的变换,小孩、未成年人、成年人、丈夫、妻子、父亲、母亲、爷爷奶奶等等。国家还会给我们贴上一个最普通的标签“公民”以及我们的继承的身份,农民或者城里人。为什么要说这些呢,因为JAVA中提供的四个元注解要表达的东西和提到的有共通之处。
@Target
@Target说明了注解修饰的范围,就好像我们有地域划分,而Java中也会有包、接口、类、枚举、属性、方法、构造函数等。那么为了表示不同的区别,注解是这么写的:
1、包 @Target(ElementType.PACKAGE) 2、接口、类、枚举、注解 @Target(ElementType.TYPE) 3、注解 @Target(ElementType.ANNOTATION_TYPE) 4、构造函数 @Target(ElementType.CONSTRUCTOR) 5、局部变量 @Target(ElementType.LOCAL_VARIABLE) 6、方法 @Target(ElementType.METHOD) 7、方法的参数 @Target(ElementType.PARAMETER)
@Retention
@Retention表示了注解的生命周期。我们在生命过程中会随着时间的变化而引起标签的变化,那么我们的标签本身也就说明了它有一定的生命周期,当我们未满18周岁的时候叫未成年人,在我们满18周岁的时候叫做成年人,等头发白了,走不动就被叫做老年人,而有的标签会伴随一生,例如男人或者女人。在JAVA中,注解也有它的生命周期,从源代码到编译后的Class文件,再到被JDK加载后的运行时就是整个周期。@Retention指定了它所要注解的注解的生命周期是什么,它会存在多长时间。JAVA中我们最常见的两个注解@SuppressWarnings和@Override,他们就只会存在于源代码中。下面是@Retention的取值:
1、在源代码中保留 @Retention( RetentionPolicy.SOURCE) 2、在Class文件中保留 @Retention( RetentionPolicy.CLASS) 3、在运行时保留 @Retention( RetentionPolicy.RUNTIME)
@SuppressWarnings注解的源代码如下:
package java.lang; import java.lang.annotation.*; import java.lang.annotation.ElementType; import static java.lang.annotation.ElementType.*; @Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE}) @Retention(RetentionPolicy.SOURCE) public @interface SuppressWarnings { String[] value(); }
@Documented
默认情况下javadoc是不包括注解信息的,但是当某一个注解被贴上@Documented标签的时候,那么当某个类或者方法的使用了被贴上@Documented这个标签的注解的时候,javadoc就会把注解信息也包含在生成的文档中。这个注解就不过度解读了,如果有兴趣的可以从网上自行查找相关资料。
@Inherited
@Inherited注解主要说明了一种继承性,意思是子类可以继承父类中的该注解(注意:只有当被贴上@Inherited标签的注解被用在类上的时候子类才能获得这个注解)。就像之前提到的,如果父母是农村户口,那么他们的孩子也默认就是农村户口了。Spring中的@Qualifier注解,代码如下:
package org.springframework.beans.factory.annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented public @interface Qualifier { String value() default ""; }
@Qualifier注解可以被用在字段、方法、方法参数、类、接口、注解、枚举上,但是只有@Qualifier被用在类上的时候才能被它的子类继承,子类才可以获取到这个注解。
自定义注解
除了一些我们生来就被贴上的标签意外,我们在日常生活中不管是主动的还是被动都会去主动的给别人贴一些标签以及被别人贴一些标签。当我们在公司,按照职能划分,会被贴上不同的岗位标签,便于安排工作;迟到,早退,全勤这些标签用于考勤;优秀员工,技术达人,管理精英等标签用来树立标杆,有助于提高积极性和向心力。那么这些标签被创造出来有没有用处呢,对于公司来说自然是有用处的。但是呢,逗逼这个标签对公司来说有没有用处呢,我想,除非公司愿意因为员工逗逼颁发逗逼奖这才有点用处,否则的话谁关心呢!贴个标签大多数时候并不会影响正常的生活,除了个人或者组织关注了你身上的标签的时候才会有影响,就像现在很多人一看到河南人三个字就开骂了一样……。其实这也是为了说明,注解并不会影响程序的正常运行,有或者没有并不影响什么,只有关注了这些注解的程序获得并且解析了注解进行处理以后才会更改程序本身的行为。
我们知道JAVA的JDK中很多地方都用了注解,到我们使用Spring的时候,注解就被使用的更广泛了,Spring用注解来对bean进行分类,注册,注入以及管理,这些事情是Spring在扫描Bean的时候通过反射来获取Bean的注解信息,配合完成Bean的自动装配,进而进行管理,给我们提供了丰富多彩的功能。下面写一个利用反射来处理自定义注解的例子,这个例子就是简单生成一个建表语句,代码如下:
1、创建@Table注解
package person.lb.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * 表名 * @author nobounds * */ @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface Table { String value() default ""; }
2、创建@Column注解:
package person.lb.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * 字段 * @author nobounds * */ @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface Column { String name() default ""; String dataType() default "varchar(20)"; String comment() default ""; }
3、创建实体类Users:
package person.lb.annotation; @Table("users") public class Users { @Column(name="ID", dataType="int") private int id; @Column(comment="用户名") private String userName; @Column(name="pwd", comment="密码") private String password; @Column(dataType="varchar(25)", comment="邮箱") private String 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; } }
4、创建注解处理器AnnotationHandler:
package person.lb.annotation; import java.lang.annotation.Annotation; import java.lang.reflect.Field; public class AnnotationHandler { public static void main(String[] args) { StringBuilder sql = new StringBuilder("CREATE TABLE "); try { Class clazz = Class.forName("person.lb.annotation.Users"); //获取Users类上的Table注解 Table tableAnnotation = (Table) clazz.getAnnotation(Table.class); //获取表名 String tableName = tableAnnotation.value().toUpperCase(); if("".equals(tableName)) { tableName = clazz.getName().toUpperCase(); } sql.append(tableName); sql.append(" ( \n"); //获取类中的所有字段 Field[] fields = clazz.getDeclaredFields(); for(Field field : fields) { //获取字段上的所有注解 Annotation[] fieldAnnotations = field.getAnnotations(); if(fieldAnnotations.length > 0) { //遍历注解 for(Annotation fieldAnnotation : fieldAnnotations) { //如果是@Field注解,那么进行处理 if(fieldAnnotation instanceof Column) { //获取字段名 String columnName = ((Column) fieldAnnotation).name().toUpperCase(); if("".equals(columnName)) { columnName = field.getName().toUpperCase(); } //获取数据类型 String dataType = ((Column) fieldAnnotation).dataType().toUpperCase(); //获取注释 String comment = ((Column) fieldAnnotation).comment(); if("".equals(comment)) { sql.append(columnName + "\t" + dataType + ",\n"); } else { sql.append(columnName + "\t" + dataType + " COMMENT ‘" + comment + "‘,\n"); } } } } } sql.append(" ) "); System.out.println("生成的sql语句为:\n" + sql.toString()); } catch (ClassNotFoundException e) { e.printStackTrace(); } } }
上面是一个简单的生成sql的例子,例子中忽略了某些非空判断,逻辑并不严谨,仅作为参考使用。如果大家觉得有问题请留言!