注解就像javadoc的注释一样,只不过注释是静态源码级别的,而注解可以使运行时的,不但可以告诉编译器某些事,也可以用来减少工作负担。
下面为三种标准注解以及四种元注解:
1、@Target 表示该注解用于什么地方,可能的 ElemenetType 参数包括:
ElemenetType.CONSTRUCTOR 构造器声明
ElemenetType.FIELD 域声明(包括 enum 实例)
ElemenetType.LOCAL_VARIABLE 局部变量声明
ElemenetType.METHOD 方法声明
ElemenetType.PACKAGE 包声明
ElemenetType.PARAMETER 参数声明
ElemenetType.TYPE 类,接口(包括注解类型)或enum声明
2、@Retention 表示在什么级别保存该注解信息。可选的 RetentionPolicy 参数包括:
RetentionPolicy.SOURCE 注解将被编译器丢弃
RetentionPolicy.CLASS 注解在class文件中可用,但会被VM丢弃
RetentionPolicy.RUNTIME VM将在运行期也保留注释,因此可以通过反射机制读取注解的信息
3、@Documented 将此注解包含在 javadoc 中
4、@Inherited 允许子类继承父类中的注解'
5、@Deprecated 表示当前元素是不赞成使用的。
6、@Override 表示当前方法是覆盖父类的方法
7、@SuppressWarnings 表示关闭一些不当的编译器警告信息
下面看示例,《thinking in java 4th》中[1070]示例改的:
2 import java.lang.annotation.ElementType;
3 import java.lang.annotation.Retention;
4 import java.lang.annotation.RetentionPolicy;
5 import java.lang.annotation.Target;
6 import java.lang.reflect.Field;
7 import java.util.ArrayList;
8 import java.util.List;
9
10
11 public class Test {
12
13 @Target(ElementType.TYPE)
14 @Retention(RetentionPolicy.RUNTIME)
15 public @interface DBTable{
16 public String name() default "";
17 }
18
19 //定义SQL约束注解
20 @Target(ElementType.FIELD)//这个注解用于字段
21 @Retention(RetentionPolicy.RUNTIME)//这个注解保留到运行时
22 public @interface Constraints{
23 boolean primaryKey() default false;
24 boolean allowNull() default true;
25 boolean unique() default false;
26 }
27
28 //定义SQLString 类型注解
29 @Target(ElementType.FIELD)
30 @Retention(RetentionPolicy.RUNTIME)
31 public @interface SQLString{
32 int value() default 0;
33 String name() default "";
34 Constraints constraints() default @Constraints; //这是个嵌套注解,默认值就是@约束注解
35 }
36
37 //定义SQLInterger类型注解
38 @Target(ElementType.FIELD)
39 @Retention(RetentionPolicy.RUNTIME)
40 public @interface SQLInterger{
41 String name() default "";
42 Constraints constraints() default @Constraints;
43 }
44
45 public @interface Uniqueness{
46 Constraints constraints() default @Constraints(unique=true); //嵌套了Consttrains注解,默认使注解的unique元素为t
47 }
48
49
50
51 //我们扩展一下,自定义SQLDate注解
52 @Target(ElementType.FIELD)
53 @Retention(RetentionPolicy.RUNTIME)
54 public @interface SQLDate{
55 String name() default "2012-01-01"; //注解只允许那几中基本数据类型
56 Constraints constraints() default @Constraints;
57 }
58
59 //这是一个java bean,包含了要往数据库写入得一个对象的所有信息
60 @DBTable(name="MEMBER")
61 public class Member{
62 @SQLString(30)//为firstName注解, @SQLString ,value是30,其他为默认,firstName
63 String firstName;
64 @SQLString(50)//同上,value其实是个快捷方式,如果注释只定义了value这个元素,那么赋值的时候,可以用键值对那样赋值
65 String lastName;
66 @SQLInterger Integer age;//同上,这里注解的所有字段为默认,名字为age
67 //这是个内嵌元素的注解
68 @SQLString(value=30,constraints=@Constraints(primaryKey=true))
69 String handle;
70 @SQLString(value=30,name="2020-10-1")
71 String birthDay;
72
73 public String getFirstName() {
74 return firstName;
75 }
76
77 public String getLastName() {
78 return lastName;
79 }
80
81 public Integer getAge() {
82 return age;
83 }
84
85 public String getBirthDay() {
86 return birthDay;
87 }
88
89 int memberCount;
90
91 public String toString(){
92 return handle;
93 }
94
95 }
96
97
98 public static void main(String[] args) throws ClassNotFoundException{
99 String className = "Test$Member";
100 Class<?> cl=Class.forName(className); //反射,获得类的class字节码
101 //反射出cl的注解,参数是DBTable的字节码class
102 DBTable dbTable=cl.getAnnotation(DBTable.class);
103 String tableName=dbTable.name();
104 //这个用来存储java beans的属性
105 List<String> columnDefs=new ArrayList<String>();
106 //获取这个java beans的所有属性,这里也顺便学到java bean相关的反射
107 for(Field field:cl.getDeclaredFields()){
108 String columnName=null;
109 //获取这个java bean属性的所有注解
110 Annotation[] anns=field.getDeclaredAnnotations();
111 if(anns.length<1)
112 continue; //如果没有注解,则跳过,到下一个属性
113 //如果注解集合的第一元素是个SQLInterger注解的话
114 if(anns[0] instanceof SQLInterger){
115 SQLInterger sInt=(SQLInterger)anns[0];
116 if(sInt.name().length()<1)
117 //如果注解元素name没有定义名称的话,则使用属性名作为名字
118 columnName=field.getName().toUpperCase();
119 else
120 //定义了的话,就用定义的东西
121 columnName=sInt.name();
122 columnDefs.add(columnName+" INT"+getConstraints(sInt.constraints()));
123 }
124 //如果第一个元素是SQLString注解的话
125 if(anns[0] instanceof SQLString ){
126 SQLString sString=(SQLString) anns[0];
127 if(sString.name().length()<1)
128 columnName=field.getName().toUpperCase();
129 else
130 columnName=sString.name();
131 columnDefs.add(columnName+" VARCHAR("+sString.value()+")"+getConstraints(sString.constraints()));
132 }
133 }
134
135 //下面模拟创建表
136 StringBuilder createCommand=new StringBuilder("CREATE TABLE "+tableName+"(");
137 for(String columnDef:columnDefs)
138 createCommand.append("\n "+columnDef+".");
139 String tableCreate=createCommand.substring(0,createCommand.length()-1)+");";
140 System.out.println("Table Cration SQL for "+className+" is:\n"+tableCreate);
141
142 }
143
144 //获得约束
145 private static String getConstraints(Constraints con){
146 String constraints="";
147 if(!con.allowNull()) //如果约束不允许使用空值
148 constraints +=" NOT NULL";
149 if(con.primaryKey())//如果是主键
150 constraints+=" PRIMARY KEY";
151 if(con.unique())
152 constraints+=" UNIQUE";
153 return constraints;
154 }
155
156
157 }