Java--注解
一. 注解的基本
1. 注解的通俗理解
注解(Annotation) 为我们在代码中添加信息提供了一种形式化的方法,是我们可以在稍后 某个时刻方便地使用这些数据(通过解析注解来使用这些数据)。
2. 注解的作用
- 生成文档
- 跟踪代码依赖性,实现替代配置文件功能, 减少配置。如 Spring 中的一些注解
- 在编译时进行格式检查,如 @Override 等
- 每当你创建描述符性质的类或者接口时, 一旦其中包含重复性的工作,就可以考虑使用注解来简化与自动化该过程。
3. 注解的状态
源码注解:只在源码中存在的注解。
编译时注解:注解在源码和.class 文件中都存在。
运行时注解:运行阶段还起作用,甚至会影响运行逻辑的注解,如 Spring, Mybatic 中常用的注解。
4. 注解的分类
a.jdk 内置注解:
- @Override:表示当前的方法定义将覆盖超类中的方法,如果出现错误,编译器就会报错。
- @Deprecated:如果使用此注解,编译器会出现警告信息。
- @SuppressWarnings:忽略编译器的警告信息。
如下 Override 的例子, 其他方法自测,child 继承 Person,并且覆盖了 Person 中的方法:
public class child extends Person {}@Override</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">覆盖</span> <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> age() { </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> TODO Auto-generated method stub</span> <span style="color: rgba(0, 0, 255, 1)">return</span> 0<span style="color: rgba(0, 0, 0, 1)">; } @Override </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> String name() { </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> TODO Auto-generated method stub</span> <span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">; } @Override </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> sing() { </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> TODO Auto-generated method stub</span>
}
b. 元注解
注解的注解,常见的有 4 个,在自定义注解中会用到,分别是
@Target,@Retention,@Documented,@Inherited
c. 自定义注解
自己定义的注解。自定义注解由元注解和自己定义的注解(annotation)构成,格式,要求及实例如下:
//自定义注解 //下面 4 行是元注解 @Target({ElementType.METHOD,ElementType.TYPE}) @Retention(RetentionPolicy.SOURCE)//元注解的作用域,生命周期 @Inherited //允许子继承 @Documented//生成 javadoc 文档时会包含次注解 //使用 @interface 关键字定义注解 public @interface Description{ /* * 成员类型是受限的,所有基本类型、String、Class、enum、Annotation、以上类型的数组形式。 * 如果注解只有一个成员时,则成员名必须取名为 value(), * 在使用是可以忽略成员名和赋值名 * 注解类可以没有成员,没有成员的注解称为标识注解 */ String value();//成员以无参无异常方式声明 //String author(); //int age() default 18;//可以给成员指定默认的值 }
5. 注解解析
注解解析其实是用了 Java 中的反射机制,不明白的可以看看我的上一篇博客,Java-- 反射的逐步理解
核心代码如下:
//1. 使用类加载器加载类 try { Class class1 =Class.forName("cn.ann.test.child");
//2. 找到类上面的注解 boolean isExist=class1.isAnnotationPresent(Description.class);//判断是否存在这个注解 Method[] ms = class1.getMethods(); for (Method method : ms) { boolean exist=method.isAnnotationPresent(Description.class); if(exist){ Description b=(Description)method.getAnnotation(Description.class); System.out.println(b.value()); }} </span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)">(isExist){ </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">3.得拿到注解实例</span> Description a=(Description)class1.getAnnotation(Description.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">); System.out.println(a.value()); } </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">4.找到方法上的注解</span> <span style="color: rgba(0, 0, 255, 1)">for</span><span style="color: rgba(0, 0, 0, 1)"> (Method method : ms) { Annotation[] s </span>=<span style="color: rgba(0, 0, 0, 1)">method.getAnnotations(); </span><span style="color: rgba(0, 0, 255, 1)">for</span><span style="color: rgba(0, 0, 0, 1)"> (Annotation annotation : s) { </span><span style="color: rgba(0, 0, 255, 1)">if</span>(annotation <span style="color: rgba(0, 0, 255, 1)">instanceof</span><span style="color: rgba(0, 0, 0, 1)"> Description){ System.out.println(((Description) annotation).value()); } } } } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (ClassNotFoundException e) { </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> TODO Auto-generated catch block</span>
e.printStackTrace();
}}</span></pre>
二. 注解应用的一个小场景
1. 场景要求
a. 有一张用户表,字段包括用户 ID,用户名,昵称,年龄,所在城市
b. 方便的对每个字段或着字段的组合条件进行检索,并打印出 SQL
2. 实现方法
具体代码如下(其中注释了代码的思路):
a. 用户表 Users.java
@Table("user") public class Users { @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;</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> getId() { </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> id; } </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> setId(<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> id) { </span><span style="color: rgba(0, 0, 255, 1)">this</span>.id =<span style="color: rgba(0, 0, 0, 1)"> id; } </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> String getUserName() { </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> userName; } </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> setUserName(String userName) { </span><span style="color: rgba(0, 0, 255, 1)">this</span>.userName =<span style="color: rgba(0, 0, 0, 1)"> userName; } </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> String getNickName() { </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> nickName; } </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> setNickName(String nickName) { </span><span style="color: rgba(0, 0, 255, 1)">this</span>.nickName =<span style="color: rgba(0, 0, 0, 1)"> nickName; } </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> getAge() { </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> age; } </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> setAge(<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> age) { </span><span style="color: rgba(0, 0, 255, 1)">this</span>.age =<span style="color: rgba(0, 0, 0, 1)"> age; } </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> String getCity() { </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> city; } </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> setCity(String city) { </span><span style="color: rgba(0, 0, 255, 1)">this</span>.city =<span style="color: rgba(0, 0, 0, 1)"> city; }
}
b. 自定义注解 Table.java
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Table {
String value();
}
c. 自定义注解 Column.java
@Target({ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented public @interface Column {String value();}
d. 测试类 test.java
public class Test { public static void main(String[] args) { Users f1 = new Users(); f1.setId(68);//表示查询 id 为 68 的用户 f1.setAge(35);
Users f2 = new Users(); f2.setUserName("huhu"); f2.setCity("lanzhou");
Users f3 = new Users(); f3.setAge(20);
String sql1 = query(f1); String sql2 = query(f2); String sql3 = query(f3);
System.out.println(sql1); System.out.println(sql2); System.out.println(sql3);} @SuppressWarnings(</span>"unchecked"<span style="color: rgba(0, 0, 0, 1)">) </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span><span style="color: rgba(0, 0, 0, 1)"> String query(Object obj) {</span> StringBuilder s=<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> StringBuilder(); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">1.获取到class</span> Class class1 =<span style="color: rgba(0, 0, 0, 1)"> obj.getClass(); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">2.获取到table的名字</span> <span style="color: rgba(0, 0, 255, 1)">boolean</span> isExist = class1.isAnnotationPresent(Table.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">); </span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)">(isExist){ Table hTable</span>=(Table)class1.getAnnotation(Table.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">); s.append(</span>"select * from ").append(hTable.value()).append(" where 1=1"<span style="color: rgba(0, 0, 0, 1)">); } </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">3.遍历所有的字段</span> Field[] fields =<span style="color: rgba(0, 0, 0, 1)">class1.getDeclaredFields(); </span><span style="color: rgba(0, 0, 255, 1)">for</span><span style="color: rgba(0, 0, 0, 1)"> (Field field : fields) { </span><span style="color: rgba(0, 0, 255, 1)">boolean</span> exist = field.isAnnotationPresent(Column.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">); </span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)">(exist){ Column f </span>=(Column)field.getAnnotation(Column.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">); String columnName </span>=<span style="color: rgba(0, 0, 0, 1)"> f.value(); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">System.out.println(columnName);</span> String fieldName =<span style="color: rgba(0, 0, 0, 1)"> field.getName(); Object fieldString</span>=<span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">; String getMethodName</span>="get"+fieldName.substring(0,1).toUpperCase()+fieldName.substring(1<span style="color: rgba(0, 0, 0, 1)">); </span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> { </span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)"> * 4.处理每个字段对应的sql * 4.1拿到字段名 * 4.2拿到字段的值 * 4.3拼装sql </span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)"> Method aMethod </span>=<span style="color: rgba(0, 0, 0, 1)"> class1.getMethod(getMethodName); fieldString</span>=(Object)aMethod.invoke(obj,<span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">System.out.println(fieldString);</span> <span style="color: rgba(0, 0, 255, 1)">if</span>(fieldString==<span style="color: rgba(0, 0, 255, 1)">null</span>||(fieldString <span style="color: rgba(0, 0, 255, 1)">instanceof</span> Integer &&(Integer)fieldString==0<span style="color: rgba(0, 0, 0, 1)">)){ </span><span style="color: rgba(0, 0, 255, 1)">continue</span><span style="color: rgba(0, 0, 0, 1)">; } s.append(</span>" and "+<span style="color: rgba(0, 0, 0, 1)">columnName); </span><span style="color: rgba(0, 0, 255, 1)">if</span>(fieldString <span style="color: rgba(0, 0, 255, 1)">instanceof</span><span style="color: rgba(0, 0, 0, 1)"> String){ s.append(</span>" = "+"'"+fieldString+"'"<span style="color: rgba(0, 0, 0, 1)">); } </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)">{ s.append(</span>" = "+<span style="color: rgba(0, 0, 0, 1)">fieldString); } } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (SecurityException e) { </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> TODO Auto-generated catch block</span>
e.printStackTrace();
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}} </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">Method[] msMethods = class1.getMethods(); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">for (Method method : msMethods) { </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">method.invoke(class1, Object); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">}</span> <span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> s.toString(); }
}
三. 一张图描述注解
谢谢大家阅读。