Spring全家桶(六)必知必会的java注解技术

一、Java注解技术的基本概念

Java注解又称Java标注,通俗的说注解就是对某一事物添加注释说明,是Java 5.0版本开始支持加入源代码的特殊语法元数据。Java语言中的类、方法、变量、参数和包都可以被标注,Java标注可以通过反射获取标注内容。在编译器生成类文件是,标注可以嵌入到字节码中。Java虚拟机可以保留标注内容,在运行时可以获取到标注内容。

注解提供了安全的类似注释的机制,用来将任何的信息或元数据与程序元素进行管理。

注解的原理:
注解不会影响程序代码的执行。

二、Java标准注解

@Override

检查该方法是否是重载方法。如果发现其父类,或者是引用的接口中并没有该方法时,会报编译错误。

@Deprecated

标记过时方法。如果使用该方法,会报编译警告。

@SuppressWarnings

指示编译器去忽略注解中声明的警告。

测试,新建一个Person接口,里面定义三个方法,name()个age()用来定义姓名和年龄。

package com.stuspring.annotation;
public interface Person {
    public String name();
    public int age();
    @Deprecated
    public void sing();
}

Son类继承Person类:

package com.stuspring.annotation;
public class Son implements Person {

    @Override
    public String name() {
        return null;
    }

    @Override
    public int age() {
        return 0;
    }

    @Override
    public void sing() {
    }

}

@Override表明该方法是从父类继承而来的。如果在Person类中删除一个sing()方法,Son类的sing()方法仍然使用@Override来标注编译器就会报错,因为父类中并没有这个方法。

在父类中把sing()方法标注为@Deprecated,表明该方法已经过时,不推荐使用了。调用的时候会给出警告:
这里写图片描述

如果想忽略警告,可以使用@SuppressWarnings标注:

这里写图片描述

三、Java注解分类

按运行机制分,注解分为:

  1. 源码注解:注解只在源码中存在,在.class文件中不存在
  2. 编译时注解:注解在源码和.class文件中都存在
  3. 运行时注解:注解在运行阶段还起作用,甚至会影响程序的运行逻辑。

按照注解来源可以分为:

  1. 来自JDK的注解
  2. 来自第三方的注解
  3. 自定义的注解

*四、Java元注解

元注解是对Java注解进行注解。Java 5.0定义的元注解在
import java.lang.annotation包中,有以下四种类型:

  1. @Target:用于描述注解的使用范围,即被描述的注解可以用在什么地方,取值有以下值:
    - CONSTRUCTOR
    - FIELD
    - LOCAL_VARIABLE
    - METHOD
    - PACKAGE
    - PARAMETER
    - TYPE

如下两个注解,它们的作用域分别为方法和域。

@Target(ElementType.TYPE)
public @interface Table{
  //数据表名称注解,默认值为类名称
  public String tableName() default "className";
}

@Target(ElementType.FIELD)
public @interface NoDBColumn{}
  1. @Retention
    用于描述注解的生命周期。取值有以下几个
    SOURCE:在源文件中有效
    CLASS:在源文件、.class文件中保留
    RUNTIME:在运行时有效
  2. @Documented:标记注解,标记Documented后javadoc中会生成注解的文档说明
  3. @Inherited:标记注解,阐述了某个注解的类型是被继承的。使用@Inherited修饰以后,这个注解将被用于该class的子类。只会集成父类类上的注解,不会继承父类方法上的注解。

五、Java自定义注解

自定义注解的语法:

@<注解名>(<成员1>=<成员值1>,<成员1>=<成员值1>)

@Description(desc="I am eyeColor",author="Mooc boy",age=18)

新建一个Description.java,代码如下:

package com.stuspring.annotation;

import java.lang.annotation.*;

/**
 * Created by bee on 17/4/30.
 */

@Target({ElementType.METHOD})       //作用域 用在方法上
@Retention(RetentionPolicy.RUNTIME) //声明周期
@Inherited                          //允许子继承
@Documented                         //生成javadoc时会包含注解
public @interface Description {
    String desc();//成员无参无异常方式声明
    String author();
    int age() default 18;// 使用default为成员指定一个默认值
}

上面代码中定义了一个注解,注解的名字为Description,里面有desc、author、age三个成员,注解作用在方法上,生命周期为在运行时扔有作用,允许子继承,生成javadoc会包含注解。

六、通过反射解析注解

通过反射来获取类、函数或成员上的运行时注解信息,从而实现动态控制程序运行的逻辑。

首先自定义一个注解,Desc.java

package com.stuspring.annotation;

import java.lang.annotation.*;

/**
 * Created by bee on 17/5/3.
 */

@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Desc {

    String value();
}

在Son.java中使用注解:

package com.stuspring.annotation;

/**
 * Created by bee on 17/4/30.
 */

@Desc("I am class annotation")
public class Son implements Person {

    @Override
    @Desc("I am method annotation")
    public String name() {
        return null;
    }

    @Override
    public int age() {
        return 0;
    }

    @Override
    public void sing() {
    }
}

通过反射获取注解的信息,ParseAnn.java

package com.stuspring.annotation;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

/**
 * Created by bee on 17/5/3.
 */
public class ParseAnn {
    public static void main(String[] args) {
        //1.使用类加载器加载类
        try {
            Class c = Class.forName("com.stuspring.annotation.Son");
            //2.找到类上面的注解
            boolean isExist = c.isAnnotationPresent(Desc.class);

            if (isExist) {
                //3.拿到注解实例
                Desc desc = (Desc) c.getAnnotation(Desc.class);
                //4.打印注解的值
                System.out.println(desc.value());
            }

            //5.找到方法上的注解
            Method[] ms = c.getMethods();//得到类上的所有方法
            for (Method m : ms) {  //遍历
                boolean isExistMethod = m.isAnnotationPresent(Desc.class);
                if (isExistMethod) {

                    Desc desc = m.getAnnotation(Desc.class);
                    System.out.println(desc.value());
                }
            }

            //6.另一种解析方法

            for (Method m:ms){
                Annotation[] anns=m.getAnnotations();
                for (Annotation a:anns){
                    if (a instanceof Desc){
                        Desc desc= (Desc) a;
                        System.out.println(desc.value());
                    }
                }
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

    }
}

运行结果:

I am class annotation
I am method annotation
I am method annotation

七、注解项目实战

项目说明:

实现一个持久层框架,用来代替Hibernate的解决方案,核心代码是通过注解来实现。
需求:
1.有一张用户表,包括用户ID、用户名、昵称、年龄、性别、所在城市、邮箱、手机号
2.方便的对每个字段或字段的组合条件进行检索,打印出SQL。
3.使用方式要足够简单
Filter类:

package com.stuspring.annotation.inaction;

/**
 * Created by bee on 17/5/3.
 */


@Table("user")
public class Filter {

    @Column("id")
    private int id;

    @Column("userName")
    private String userName;

    @Column("nickName")
    private String nickName;

    @Column("age")
    private int age;

    @Column("city")
    private String city;

    @Column("email")
    private String email;

    @Column("mobile")
    private String mobile;


    public void setId(int id) {
        this.id = id;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public void setNickName(String nickName) {
        this.nickName = nickName;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public void setCity(String city) {
        this.city = city;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public void setMobile(String mobile) {
        this.mobile = mobile;
    }


    public int getId() {
        return id;
    }

    public String getUserName() {
        return userName;
    }

    public String getNickName() {
        return nickName;
    }

    public int getAge() {
        return age;
    }

    public String getCity() {
        return city;
    }

    public String getEmail() {
        return email;
    }

    public String getMobile() {
        return mobile;
    }


}

Table注解

package com.stuspring.annotation.inaction;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * Created by bee on 17/5/3.
 */


@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Table {

    String value();
}

Column注解:

package com.stuspring.annotation.inaction;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * Created by bee on 17/5/3.
 */

@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {

    String value();
}

测试:

package com.stuspring.annotation.inaction;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * Created by bee on 17/5/3.
 */
public class Test {

    public static void main(String[] args) {

        Filter f1 = new Filter();
        f1.setId(10);

        Filter f2 = new Filter();
        f2.setUserName("lucy");

        Filter f3 = new Filter();
        f3.setEmail("liu@sina.com,zh@163.com,1235@qq.com");


        Filter f4 = new Filter();
        f4.setEmail("liu@sina.com");

        Filter f5 = new Filter();
        f5.setUserName("Tom");
        f5.setAge(20);

        String sq1 = query(f1);
        String sq2 = query(f2);
        String sq3 = query(f3);
        String sq4 = query(f4);
        String sq5 = query(f5);
        System.out.println(sq1);
        System.out.println(sq2);
        System.out.println(sq3);
        System.out.println(sq4);
        System.out.println(sq5);

    }

    public static String query(Filter filter) {

        StringBuilder sb = new StringBuilder();
        //1.获取到Class
        Class c = filter.getClass();
        //获取到Table的名字
        boolean exist = c.isAnnotationPresent(Table.class);
        if (!exist) {
            return null;
        }

        Table table = (Table) c.getAnnotation(Table.class);
        String tbName = table.value();
        sb.append("SELECT * FROM ").append(tbName).append(" WHERE 1=1 ");
        //遍历所有字段
        Field[] fArray = c.getDeclaredFields();
        for (Field field : fArray) {
            boolean fExists = field.isAnnotationPresent(Column.class);
            if (!fExists) {
                continue;
            }

            Column column = field.getAnnotation(Column.class);
            String columnName = column.value();
            //拿到字段的值
            String fieldName = field.getName();
            Object fieldValue = null;

            String getMethodName = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
            try {
                Method getMethod = c.getMethod(getMethodName);
                fieldValue = getMethod.invoke(filter, null);
            } catch (Exception e) {
                e.printStackTrace();
            }

            //拼装SQL

            if (fieldValue == null || (fieldValue instanceof Integer && (Integer) fieldValue == 0)) {
                continue;
            }

            if (fieldValue instanceof String) {

                if (((String) fieldValue).contains(",")) {
                    String[] values = ((String) fieldValue).split(",");
                    sb.append("in(");
                    for (String v : values) {
                        sb.append("\'").append(v).append("\'").append(",");
                    }
                    sb.deleteCharAt(sb.length() - 1);
                    sb.append(")");
                } else {
                    fieldValue = "\'" + fieldValue + "\'";
                    sb.append(" and ").append(fieldName).append(" = ").append(fieldValue);
                }

            }else{
                sb.append(" and ").append(fieldName).append(" = ").append(fieldValue);
            }

        }
        return sb.toString();
    }
}

输出:

SELECT * FROM user WHERE 1=1  and id = 10
SELECT * FROM user WHERE 1=1  and userName = 'lucy'
SELECT * FROM user WHERE 1=1 in('liu@sina.com','zh@163.com','1235@qq.com')
SELECT * FROM user WHERE 1=1  and email = 'liu@sina.com'
SELECT * FROM user WHERE 1=1  and userName = 'Tom' and age = 20
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

esc_ai

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值