【java提高】(16)---java注解(Annotation)

java 提高(16)---java 注解

注解含义注解是 JDK1.5 之后才有的新特性, 它相当于一种标记,在程序中加入注解就等于为程序打上某种标记, 之后又通过类的反射机制来解析注解。

一、JDK 自带注解

JDK1.5 之后内部提供的三个注解

 @Deprecated       #废弃,过时。
 @Override         #重写、覆盖。
 @SuppressWarnings #压缩警告。

示例

@SuppressWarnings("deprecation")
public class AnnotationTest {
    //4、这里称为压缩警告注解,可以在类上也可以放在方法上, 因为该方法用了个已经过期的方法.getYear(),所以会发出警告
    // 加上这个注解表明取消对 deprecation 的警告,那么该方法里有过时方法也不会发出预警。同时 getYear() 的那条横线也消失了。
    @SuppressWarnings("deprecation")
    public static void main(String[] args) {

//1、这里的.getYear() 方法画了一条横线表示此方法已经过时了,里面方法加上了 @Deprecated 注解
new Date().getYear();
}

<span class="hljs-comment">//2、这里我通过@Deprecated注解自定义一个已经过时不建议使用的方法。</span>
<span class="hljs-meta">@Deprecated</span>
<span class="hljs-keyword">public</span> String   <span class="hljs-title function_">getName</span><span class="hljs-params">()</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-string">"小小"</span>;

}
<span class="hljs-comment">//3、重写(覆盖)父类Object的toString()方法</span>
<span class="hljs-meta">@Override</span>
<span class="hljs-keyword">public</span> String <span class="hljs-title function_">toString</span><span class="hljs-params">()</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-string">"小小"</span>;
}

}

注解示意图


二、自定义注解

示例

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface AnCode {// 使用 @interface 关键字定义注解
<span class="hljs-comment">//如果只有一个属性 强烈建议取名为value</span>
String <span class="hljs-title function_">value</span><span class="hljs-params">()</span> <span class="hljs-keyword">default</span> <span class="hljs-string">""</span>;

}

在自定义注解上面有四个注解,我们称为元注解,下面一个一个解释。

1、@Target 用于描述注解的使用范围

取值(ElementType)有:
    1CONSTRUCTOR:   用于描述构造器
    2、FIELD:         用于描述域(字段申明)
    3、LOCAL_VARIABLE:用于描述局部变量
    4、METHOD:        用于描述方法
    5、PACKAGE:       用于描述包
    6、PARAMETER:     用于描述参数
    7TYPE:          用于描述类、接口(包括注解类型) 或enum声明
    8、TYPE_PARAMETER:输入参数申明(JDK1.8)
    9、TYPE_USE:      使用类型(JDK1.8)

2、@Retention 定义了该注解生命周期

取值(RetentionPoicy)有:
    1、SOURCE:  在源文件中有效(即源文件保留)
    2CLASS:   在class文件中有效(即class保留)
    3、RUNTIME: 注解永久保留,可以被VM加载时加载到内存中

一般框架注解和我们自定义注解采用的几乎都是RUNTIME, 因为只有这个才能运行时通过反射来获取注解中的数据。

3、@Inherited

概念: @Inherited 阐述了某个被标注的类型是被继承的。如果一个使用了 @Inherited 修饰的 annotation 类型被用于一个 class,则这个 annotation 将被用于该 class 的子类。

注意:@Inherited annotation 类型是被标注过的 class 的子类所继承。类并不从它所实现的接口继承 annotation,方法并不从它所重载的方法继承 annotation
解释: 比如 A 继承 B,B 类的上面有一个注解 @A 带有元注解 @Inherited 那么 A 也可以拥有 B 父类的这个注解 @A,但接口实现是不可以的。同时需要指出 @A 注解是需要元注解 @Retention(RetentionPolicy.RUNTIME)。

参考文章:java @Inherited 注解的作用

4、@Documented

概念: 描述其它类型的 annotation 应该被作为被标注的程序成员的公共 API,因此可以被例如 javadoc 此类的工具文档化。

5、自定义注解参数

  1、只能用public或默认(default)这两个访问权修饰.例如,String value();这里把方法设为defaul默认类型;  
      2、参数成员只能用基本类型byte,short,char,int,long,float,double,boolean八种基本数据类型和
           String,Enum,Class,annotations等数据类型,以及这一些类型的数组;
   3、如果只有一个参数成员,最好把参数名称设为"value",后加小括号(也可以不加小括号)

三、自定义注解案例

目标 实现一个简单的通过注解生成 SQL 查询语句。

先创建两个注解

@Table 表名注解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Table {
<span class="hljs-comment">//数据库表名属性</span>
String <span class="hljs-title function_">value</span><span class="hljs-params">()</span> <span class="hljs-keyword">default</span> <span class="hljs-string">""</span>;

}

@Column 字段名注解

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
    // 数据库表字段名称和实体属性映射
    String value() default "";
}

User 实体

@Table("t_user")
public class User {
    /**
     * 用户 Id
     */
    @Column("user_id")
    private Integer userId;
    /**
     * 用户年龄
     */
    @Column("age")
    private Integer age;
<span class="hljs-keyword">public</span> <span class="hljs-title function_">User</span><span class="hljs-params">(Integer userId, Integer age)</span> {
    <span class="hljs-built_in">this</span>.userId = userId;
    <span class="hljs-built_in">this</span>.age = age;
}
<span class="hljs-comment">//添加get和set方法</span>
}

解析注解类

public class Query {
    public static String query(Object object) throws Exception{
        StringBuilder sql = new StringBuilder();
        //1. 利用反射获取 Class
        Class c = object.getClass();
        //2. 获取 Table 的名字
        boolean isExist = c.isAnnotationPresent(Table.class);
        if (!isExist) {
            return null;
        }
        Table t = (Table) c.getAnnotation(Table.class);
        //3、获取注解上的 value 值
        String tableName = t.value();
        sql.append("select * form").append(tableName).append("where 1 = 1");
        //4. 遍历所有的属性字段
        Field[] fArray = c.getDeclaredFields();
        for (Field field : fArray) {
            // 处理每个字段对应的 sql
            boolean fExist = field.isAnnotationPresent(Column.class);
            if (!fExist) {
                continue;
            }
            Column column = field.getAnnotation(Column.class);
            // 数据库字段名
            String columnName = column.value();
            //5、将 user_id 变成 userId
            String[] columns = columnName.split("_");
            StringBuilder columnBuilder = new StringBuilder();
            for (int i = 0; i < columns.length; i++) {
                String s = columns[i];
                columnBuilder.append(s.substring(0, 1).toUpperCase()).append(s.substring(1));
            }
            //6、活动属性值
            String getMethodName = "get" + columnBuilder.toString(); //get 方法名
            Method getMethod = c.getMethod(getMethodName);
            Object  fieldValue = getMethod.invoke(object);// 类字段值
            //7、拼装 sql
            sql.append("and").append(columnName).append("=").append(fieldValue);
        }
        return sql.toString();
    }
}

测试类

public static void main(String[] args) throws Exception {
        User user = new User(001, 4);
        String query = Query.query(user);
        System.out.println("query =" + query);
    }

运行结果

通过这个小案例实现了通过注解的方式,生成 sql 语句。


只要自己变优秀了,其他的事情才会跟着好起来(少将20)