前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >探一探神奇的注解

探一探神奇的注解

原创
作者头像
Simon、hao
发布2018-08-20 17:03:55
2770
发布2018-08-20 17:03:55
举报
文章被收录于专栏:java小记java小记

简介

无论我在web项目中,还是在纯后端项目当中我们都不难看到@Override这样的注解,都觉得很摸不着头脑,凭什么这个东西就可以这样子,于是自己写了个注解,并且简单的看了看注解的只是引入

怎么理解注解

在学习注解的时候,看到这样的一句话“乔布斯重新定义了手机,老罗重新定义了傻逼”,当然我对此种言论不持任何意见,个人还是很尊重老罗的,完全引用而已。

在我刚刚看注解的知识的时候,在书上,网上看到的解释,类似于

代码语言:txt
复制
注解(Annotation),也叫元数据。一种代码级别的说明。
它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。
它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。

当时看到这种解释,其实第一反应就是有点懵了,不知道为什么懵,但是就是懵,初学者理解起来更吃力,直到学习完,然后在网上看到这样的一段话,恍然大悟

注解如同标签

代码语言:txt
复制
回到博文开始的地方,之前某新闻客户端的评论有盖楼的习惯,于是“乔布斯重新定义了手机、罗永浩重新定义了傻X”,
就经常极为工整地出现在了评论楼层中,并且广大网友在相当长的一段时间内对于这种行为乐此不疲。这其实就是等同于贴标签的行为。
在某些网友眼中,罗永浩就成了傻X的代名词。
广大网友给罗永浩贴了一个名为“傻x”的标签,他们并不真正了解罗永浩;
不知道他当教师、砸冰箱、办博客的壮举,但是因为“傻x”这样的标签存在,这有助于他们直接快速地对罗永浩这个人做出评价,
然后基于此,罗永浩就可以成为茶余饭后的谈资,这就是标签的力量。
而在网络的另一边,老罗靠他的人格魅力自然收获一大批忠实的拥泵,他们对于老罗贴的又是另一种标签

如何使用注解

在平常开发当中,我们很少开发注解,所以很多人都认为注解都不重要,其实我们不难发现,特别是在现在的各种web框架中,注解使用的频率和种类已经多到恐怖的级别了

注解的开发

通过@interface关键字进行定义

代码语言:txt
复制
public @interface Property {
    
}

这样就创建了一个注解,这个注解是可以使用的,但是这个注解基本没有什么用

想要开发一个作用比较多的注解,那么我们还得直到一个概念

元注解

元注解的概念比较简单了,就是用来修饰注解的,说明该注解的使用场景等,也就是给注解打标签,元注解的有@Retention、@Documented、@Target、@Inherited、@Repeatable

@Retention
定义注解的保留期
  • @Retention(RetentionPolicy.SOURCE) //注解仅存在于源码中,在class字节码文件中不包含
  • @Retention(RetentionPolicy.CLASS) // 默认的保留策略,注解会在class字节码文件中存在,但运行时无法获得,
  • @Retention(RetentionPolicy.RUNTIME) // 注解会在class字节码文件中存在,在运行时可以通过反射获取到
  • 首先要明确生命周期长度 SOURCE < CLASS < RUNTIME ,所以前者能作用的地方后者一定也能作用。一般如果需要在运行时去动态获取注解信息,那只能用 RUNTIME 注解;如果要在编译时进行一些预处理操作,比如生成一些辅助代码(如 ButterKnife),就用 CLASS注解;如果只是做一些检查性的操作,比如 @Override 和 @SuppressWarnings,则可选用 SOURCE 注解。
@Target
定义注解的作用目标
  • @Target(ElementType.TYPE) //接口、类、枚举、注解
  • @Target(ElementType.FIELD) //字段、枚举的常量
  • @Target(ElementType.METHOD) //方法
  • @Target(ElementType.PARAMETER) //方法参数
  • @Target(ElementType.CONSTRUCTOR) //构造函数
  • @Target(ElementType.LOCAL_VARIABLE)//局部变量
  • @Target(ElementType.ANNOTATION_TYPE)//注解
  • @Target(ElementType.PACKAGE) ///包
@Documented
说明该注解将被包含在javadoc中
@Inherited
此注解修饰的注解可以被继承,例如注解A被@Inherited修饰,那么B CLASS被A修饰了,C继承B,等同于A修饰了C

如下

代码语言:txt
复制
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@interface A {}


@Test
public class B {}


public class C extends B {}
@Repeatable
被此注解修饰的注解是可以重复的。注解的参数是可重复注解的存储容器注解类型。

例如角色

代码语言:txt
复制
@interface Users {
    User[]  value();
}


@Repeatable(Users.class)
@interface User{
    String role default "";
}


@Person(role="admin")
@Person(role="user")
@Person(role="officer")
public class One{

}

注解实例

现在了解到,我们通常使用的比较多的元注解是@Retention、@Target这两个

代码语言:txt
复制
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Property {
    String defaultValue () default "";
}

如上自定义注解的意思就是在程序运行的时候使用,作用于字段,并且有一个属性,并且有一个默认值

代码语言:txt
复制
@Config
public class GlobalConfig {

    @Property(defaultValue = "aa")
    private String routingKeys;

    public String getRoutingKeys() {
        return routingKeys;
    }
    public void setRoutingKeys(String routingKeys) {
        this.routingKeys = routingKeys;
    }


}

如上就是一个使用的详情,在字段上可以使用此类注解

其实说到现在都没有一个具体的说明,注解到底怎么用,那是因为要开发注解的话,一定要和反射一起来使用,我们就接着刚才那段代码结合反射,来达到一个读取配置文件的一个功能

代码语言:txt
复制
public class LoadProperties {

    public <T> T loadProperties(String filePath,Class<T> clazz){
        T entity = null;
        try{
            //判断基本条件是否成立
            File file = new File(filePath);
            //Config是一个修饰类的注解
            boolean flag = clazz.isAnnotationPresent(Config.class);
            if(file.exists() && flag){
                // TODO: 2018/8/15
                Properties properties = new Properties();
                properties.load(new FileInputStream(file));
                entity = loadProperties(properties,clazz);
            }else{
                throw new LoadPropertiesException();
            }
        }catch (Exception e){
            e.printStackTrace();
        }


        return entity;
    }

    public <T> T loadProperties(Properties pro,Class<T> clazz) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
        T entity = clazz.newInstance();
        //获取所有属性
        Field[] fields = clazz.getDeclaredFields();
        //循环将配置文件的值塞入对象中
        for (Field field : fields){
            field.setAccessible(true);
            //拼接方法名
            String methodName = GlobalInfo.SET +
                    field.getName().substring(0,1).toUpperCase().concat(field.getName().substring(1));

            //获取对应的set方法
            Method method = clazz.getDeclaredMethod(methodName,String.class);
            String value = "";
            value = pro.getProperty(field.getName());
            if (null == value){
                value = field.getAnnotation(Property.class).defaultValue();
            }
            method.invoke(entity,value);
        }
        return entity;
    }
}

这个时候,我们在添加参数到properties当中的时候,只需要在GlobalConfig当中添加一个一摸一样的属性,并且填上注解,就可以了!

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 简介
    • 怎么理解注解
      • 注解如同标签
    • 如何使用注解
      • 注解的开发
      • 元注解
      • 注解实例
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档