【Java】看完本篇文章,你就能自定义注解了

第一时间阅读最新文章

一、什么是注解

注意!是注“解”,不是注释,注释是在写代码时加上一些对代码的解释,它们两都起到了解释代码的作用

1.概念

从JDK5开始,Java增加对元数据的支持,也就是注解,注解与注释是有一定区别的,可以把注解理解为代码里的特殊标记,这些标记可以在编译,类加载,运行时被读取,并执行相应的处理。通过注解开发人员可以在不改变原有代码和逻辑的情况下在源代码中嵌入补充信息。
——百度百科

在Java中的注解是以@开头的,它会在编译,类加载,运行时被读取,然后由注解处理器来进行处理,注解仅仅是存放元数据,不会修改修饰对象的代码产生直接影响
注解和类、接口、数组、枚举等关键字平起平坐,同样重要

2.来源

在注解还没有出现之前,一般使用XML文件来存储元数据的,配置文件的信息还有SQL语句都可以算是元数据,这就使元数据和代码耦合度十分的低,如果项目十分大的话,就会造成维护困难,于是就诞生了注解,让元数据和代码紧密结合,极大的降低了编程的复杂度,在后来,注解功能就不仅仅局限与绑定元数据了
注解是真的好用,谁用谁知道

3.注解分类

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

二、自定义注解

在上面三类注解中,我们主要关注的是自定义注解

1.元注解

元注解在自定义注解中需要用到,总共有4个,分别是@Target、@Retention、@Inherited、@Documented

@Target

这个注解是表示自定义注解的作用域,也就是说这个注解表明了定义的注解可以用来修饰什么类型的类、属性、方法

下面是 @Target的取值表 ,也不需要记,用的时候查看一下就好了

取值 注解使用范围
METHOD 可用于方法上
TYPE 可用于类或者接口上
ANNOTATION_TYPE 可用于注解类型上(被@interface修饰的类型)
CONSTRUCTOR 可用于构造方法上
FIELD 可用于域上,就是类的属性/字段
LOCAL_VARIABLE 可用于局部变量上,就是方法内部的属性
PACKAGE 用于记录java文件的package信息
PARAMETER 可用于参数上

@Resource中的@Target的value

@Target({TYPE, FIELD, METHOD})

@Retention

这个注解表示的是自定义注解的生命周期,也就是说这个注解能够决定自定义注解能够在那个阶段被处理,在那些阶段可以存在

下面是@Retention的取值表,同上

取值 生命周期
RetentionPolicy.SOURCE 只能存活在.java文件上,不会存活在.class文件,在经过编译器编译之后就不存在了
RetentionPolicy.CLASS 能够存活在.class文件,不会存活在运行时期,也就是在内存中,但是在经过类加载器之后就不存在了
RetentionPolicy.RUNTIME 能够存活在内存中,无论经过编译器还是类加载器都会存在,也是我们自定义注解时常用的

@Resource中的@Retention的value

@Retention(RUNTIME)

@Inherited

这个注解能够让子类继承父类上的注解,打个比方说,A继承了B,B上有这个注解,也有其他注解,那么A类就会继承B类上的其他注解。但是子接口的继承和实现都不会父接口的注解
这个注解没有value,直接使用就好了

@Documented

这个注解表示,在生成javadoc时,带了该注解的类是否要包含该自定义注解的信息,我们用不上。生成javadoc文档的方式有很多,用IDEA、javadoc.exe命令行

2.自定义注解语法

  1. 使用@interface关键字定义,跟使用class、interface、enum等关键字一样
  2. 定义注解类型元素(annotation type element)
    定义注解类型元素才是我们的重点,第一,元素的访问修饰符必须为public;第二,元素的类型只能为基本数据类型(String、int、Class等)、还有枚举类型;第三、如果只有一个元素,则把元素名称取为value;第四,在元素名称后面加();第五,在()后面可以加default,后面接默认值

拉个@Retention注解来作例子

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
    /**
     * Returns the retention policy.
     * @return the retention policy
     */
    RetentionPolicy value();
}

3.自定义注解

场景:类似于数据库的表格
Table

/**
 * @author xxj
 * 表注解
 */
@Target({TYPE})
@Retention(RUNTIME)
public @interface Table {
    String value();
}

Column

/**
 * @author xxj
 * 行注解
 */
@Target(LOCAL_VARIABLE)
@Retention(RUNTIME)
public @interface Column {
    String value();
}

4.使用自定义注解

定义了注解,当然也要使用注解啦,这里涉及到反射机制,如果还不了解的可以去看我的【java】反射机制

首先,先定义一个User类

/**
 * @author xxj
 * User表
 */
@Table("User")
public class User implements Serializable {
    @Column("name")
    private String name;
    @Column("age")
    private Integer age;
    public User() {
    }
    //get、set、toString就不放上来了
}

然后,写一个Dome测试类
最重要的就是explainAnnotation()方法了,了解过反射的可以看一下

/**
 * @author xxj
 * 注解解析测试
 */
public class Demo {
    public static void main(String[] args) {
        User user=new User();
        user.setName("xiaoming");
        user.setAge(18);
        User user1=new User();
        user1.setName("xiaohong");
        //调用方法解析注解
        explainAnnotation(user);
        explainAnnotation(user1);
    }
    private static void explainAnnotation(Object object){
        //定义一个String来存放信息
        String str="";
        Class obClass=object.getClass();
        //判断是否是Table注解
        if (!obClass.isAnnotationPresent(Table.class)){
            return;
        }
        //获取到table注解信息
        Table table= (Table) obClass.getAnnotation(Table.class);
        //获取table注解的value
        String tableName=table.value();
        str+="tableName="+tableName;
        //获取object类的属性/字段
        Field[] fields=obClass.getDeclaredFields();
        //循环解析属性
        for (Field field:fields) {
            //判断是否是Column注解
            if (!field.isAnnotationPresent(Column.class)){
                continue;
            }
            //获取column注解信息
            Column column= field.getAnnotation(Column.class);
            //获取column注解的value
            String columnName=column.value();
            //拼接对应属性的getXxx()方法名称
            String getMethodName="get"+columnName.substring(0,1).toUpperCase()
                    +columnName.substring(1);
            //定义一个object对象来存放值
            Object fieldValue = null;
            try {
                //获取对应属性的getXxx()方法
                Method method=obClass.getMethod(getMethodName);
                //调用方法
                fieldValue=method.invoke(object);
            }catch (Exception e){}
            //拼接字符串
            str+=","+columnName+":"+fieldValue;
        }
        System.out.println(str);
    }
}

可以看到,注解的内容可以直接通过class类获得,但是对象的属性值只能通过对象获得,所以还是要使用method.invoke(object),将对象传递过去才能获得对象的属性值

三、总结

从上面的自定义注解和解析自定义注解中,我们可以看出创建了一个自定义的注解不是直接使用它就有效果的,而是要另外写一个方法来解析这个注解,然后根据解析出来的注解内容在做相应的操作。
像MyBatis中提供的@mapper,就是用来判断这个类是否是有@mapper注解,而写在@select上的value,就可以直接拿来拼接SQL语句了。

——————————————————————————————
你知道的越多,不知道的越多。

如果本文章内容有问题,请直接评论或者私信我。如果觉得写得还不错的话,点个赞也是对我的支持哦

未经允许,不得转载!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容