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 &amp;&amp;(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();
}

}

三. 一张图描述注解

 

谢谢大家阅读。